LCOV - code coverage report
Current view: top level - vnet/flow - flow_cli.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 4 477 0.8 %
Date: 2023-10-26 01:39:38 Functions: 8 47 17.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : #include <stddef.h>
      16             : 
      17             : #include <vnet/vnet.h>
      18             : #include <vnet/devices/devices.h>
      19             : #include <vnet/ip/ip.h>
      20             : #include <vnet/ethernet/ethernet.h>
      21             : #include <vnet/ethernet/packet.h>
      22             : #include <vnet/flow/flow.h>
      23             : 
      24             : static format_function_t format_flow;
      25             : 
      26             : uword
      27           0 : unformat_ip_port_and_mask (unformat_input_t * input, va_list * args)
      28             : {
      29           0 :   ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *);
      30           0 :   u32 port = 0, mask = 0;
      31             : 
      32           0 :   if (unformat (input, "any"))
      33             :     ;
      34           0 :   else if (unformat (input, "%u/%u", &port, &mask))
      35             :     ;
      36           0 :   else if (unformat (input, "%u/0x%x", &port, &mask))
      37             :     ;
      38           0 :   else if (unformat (input, "%u", &port))
      39           0 :     mask = 0xffff;
      40             :   else
      41           0 :     return 0;
      42             : 
      43           0 :   if (port > 0xffff || mask > 0xffff)
      44           0 :     return 0;
      45             : 
      46           0 :   pm->port = port;
      47           0 :   pm->mask = mask;
      48           0 :   return 1;
      49             : }
      50             : 
      51             : u8 *
      52           0 : format_ip_port_and_mask (u8 * s, va_list * args)
      53             : {
      54           0 :   ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *);
      55             : 
      56           0 :   if (pm->port == 0 && pm->mask == 0)
      57           0 :     return format (s, "any");
      58             : 
      59           0 :   if (pm->mask == 0xffff)
      60           0 :     return format (s, "%u", pm->port);
      61             : 
      62           0 :   return format (s, "%u/0x%x", pm->port, pm->mask);
      63             : }
      64             : 
      65             : uword
      66           0 : unformat_ip_protocol_and_mask (unformat_input_t * input, va_list * args)
      67             : {
      68           0 :   ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *);
      69           0 :   u32 prot = 0, mask = 0;
      70             : 
      71           0 :   if (unformat (input, "any"))
      72             :     ;
      73           0 :   else if (unformat (input, "%U", unformat_ip_protocol, &prot))
      74           0 :     mask = 0xFF;
      75           0 :   else if (unformat (input, "%u", &prot))
      76           0 :     mask = 0xFF;
      77             :   else
      78           0 :     return 0;
      79             : 
      80           0 :   if (prot > 0XFF || mask > 0xFF)
      81           0 :     return 0;
      82             : 
      83           0 :   pm->prot = prot;
      84           0 :   pm->mask = mask;
      85           0 :   return 1;
      86             : }
      87             : 
      88             : u8 *
      89           0 : format_ip_protocol_and_mask (u8 * s, va_list * args)
      90             : {
      91           0 :   ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *);
      92             : 
      93           0 :   if (pm->prot == 0 && pm->mask == 0)
      94           0 :     return format (s, "any");
      95             : 
      96           0 :   return format (s, "%U", format_ip_protocol, pm->prot);
      97             : }
      98             : 
      99             : u8 *
     100           0 : format_flow_error (u8 * s, va_list * args)
     101             : {
     102           0 :   int error = va_arg (*args, int);
     103             : 
     104           0 :   if (error == 0)
     105           0 :     return format (s, "no error");
     106             : 
     107             : #define _(v,n,str) if (error == v) return format (s, #str);
     108           0 :   foreach_flow_error;
     109             : #undef _
     110             : 
     111           0 :   return format (s, "unknown error (%d)", error);
     112             : }
     113             : 
     114             : u8 *
     115           0 : format_flow_actions (u8 * s, va_list * args)
     116             : {
     117           0 :   u32 actions = va_arg (*args, u32);
     118           0 :   u8 *t = 0;
     119             : 
     120             : #define _(a, b, c) if (actions & (1 << a)) \
     121             :   t = format (t, "%s%s", t ? " ":"", c);
     122           0 :   foreach_flow_action
     123             : #undef _
     124           0 :     s = format (s, "%v", t);
     125           0 :   vec_free (t);
     126           0 :   return s;
     127             : }
     128             : 
     129             : u8 *
     130           0 : format_flow_enabled_hw (u8 * s, va_list * args)
     131             : {
     132           0 :   u32 flow_index = va_arg (*args, u32);
     133           0 :   vnet_flow_t *f = vnet_get_flow (flow_index);
     134           0 :   if (f == 0)
     135           0 :     return format (s, "not found");
     136             : 
     137           0 :   u8 *t = 0;
     138             :   u32 hw_if_index;
     139             :   uword private_data;
     140           0 :   vnet_main_t *vnm = vnet_get_main ();
     141             :   /* *INDENT-OFF* */
     142           0 :   hash_foreach (hw_if_index, private_data, f->private_data,
     143             :     ({
     144             :      t = format (t, "%s%U", t ? ", " : "",
     145             :                  format_vnet_hw_if_index_name, vnm, hw_if_index);
     146             :      }));
     147             :   /* *INDENT-ON* */
     148           0 :   s = format (s, "%v", t);
     149           0 :   vec_free (t);
     150           0 :   return s;
     151             : }
     152             : 
     153             : u8 *
     154           0 : format_rss_function (u8 * s, va_list * args)
     155             : {
     156           0 :   vnet_rss_function_t func = va_arg (*args, vnet_rss_function_t);
     157             : 
     158             :   if (0)
     159             :     ;
     160             : #undef _
     161             : #define _(f, n) \
     162             :       else if (func == VNET_RSS_FUNC_##f) \
     163             :         return format (s, n);
     164             : 
     165           0 :   foreach_rss_function
     166             : #undef _
     167           0 :     return format (s, "unknown");
     168             : }
     169             : 
     170             : u8 *
     171           0 : format_rss_types (u8 * s, va_list * args)
     172             : {
     173           0 :   u64 type = va_arg (*args, u64);
     174             : 
     175             : #undef _
     176             : #define _(a,b,c)     \
     177             :   if (type & (1UL<<a)) \
     178             :     s = format (s, "%s ", c);
     179             : 
     180           0 :   foreach_flow_rss_types
     181             : #undef _
     182           0 :     return s;
     183             : }
     184             : 
     185             : static const char *flow_type_strings[] = { 0,
     186             : #define _(a,b,c) c,
     187             :   foreach_flow_type
     188             : #undef _
     189             : };
     190             : 
     191             : static clib_error_t *
     192           0 : show_flow_entry (vlib_main_t * vm, unformat_input_t * input,
     193             :                  vlib_cli_command_t * cmd_arg)
     194             : {
     195           0 :   vnet_main_t *vnm = vnet_get_main ();
     196           0 :   vnet_flow_main_t *fm = &flow_main;
     197           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     198             :   vnet_hw_interface_t *hi;
     199             :   vnet_device_class_t *dev_class;
     200             :   vnet_flow_t *f;
     201             :   uword private_data;
     202           0 :   u32 index = ~0, hw_if_index;
     203             : 
     204           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     205           0 :     goto no_args;
     206             : 
     207           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     208             :     {
     209           0 :       if (unformat (line_input, "index %u", &index))
     210             :         ;
     211             :       else
     212           0 :         return clib_error_return (0, "parse error: '%U'",
     213             :                                   format_unformat_error, line_input);
     214             :     }
     215             : 
     216           0 :   unformat_free (line_input);
     217             : 
     218           0 :   if (index != ~0)
     219             :     {
     220           0 :       if ((f = vnet_get_flow (index)) == 0)
     221           0 :         return clib_error_return (0, "no such flow");
     222             : 
     223           0 :       vlib_cli_output (vm, "%-10s: %u", "index", f->index);
     224           0 :       vlib_cli_output (vm, "%-10s: %s", "type", flow_type_strings[f->type]);
     225           0 :       vlib_cli_output (vm, "%-10s: %U", "match", format_flow, f);
     226           0 :       if (f->type == VNET_FLOW_TYPE_GENERIC)
     227             :         {
     228           0 :           vlib_cli_output (vm, "%s: %s", "spec", f->generic.pattern.spec);
     229           0 :           vlib_cli_output (vm, "%s: %s", "mask", f->generic.pattern.mask);
     230             :         }
     231             :       /* *INDENT-OFF* */
     232           0 :       hash_foreach (hw_if_index, private_data, f->private_data,
     233             :         ({
     234             :          hi = vnet_get_hw_interface (vnm, hw_if_index);
     235             :           dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
     236             :           vlib_cli_output (vm,  "interface %U\n",
     237             :                            format_vnet_hw_if_index_name, vnm, hw_if_index);
     238             :           if (dev_class->format_flow)
     239             :             vlib_cli_output (vm,  "  %U\n", dev_class->format_flow,
     240             :                              hi->dev_instance, f->index, private_data);
     241             :          }));
     242             :       /* *INDENT-ON* */
     243           0 :       return 0;
     244             :     }
     245             : 
     246           0 : no_args:
     247             :   /* *INDENT-OFF* */
     248           0 :   pool_foreach (f, fm->global_flow_pool)
     249             :     {
     250           0 :       vlib_cli_output (vm, "%U\n", format_flow, f);
     251           0 :       if (f->type == VNET_FLOW_TYPE_GENERIC)
     252             :         {
     253           0 :           vlib_cli_output (vm, "%s: %s", "spec", f->generic.pattern.spec);
     254           0 :           vlib_cli_output (vm, "%s: %s", "mask", f->generic.pattern.mask);
     255             :         }
     256             :     }
     257             :   /* *INDENT-ON* */
     258             : 
     259           0 :   return 0;
     260             : }
     261             : 
     262             : /* *INDENT-OFF* */
     263      285289 : VLIB_CLI_COMMAND (show_flow_entry_command, static) = {
     264             :     .path = "show flow entry",
     265             :     .short_help = "show flow entry [index <index>]",
     266             :     .function = show_flow_entry,
     267             : };
     268             : /* *INDENT-ON* */
     269             : 
     270             : static clib_error_t *
     271           0 : show_flow_ranges (vlib_main_t * vm, unformat_input_t * input,
     272             :                   vlib_cli_command_t * cmd_arg)
     273             : {
     274           0 :   vnet_flow_main_t *fm = &flow_main;
     275           0 :   vnet_flow_range_t *r = 0;
     276             : 
     277           0 :   vlib_cli_output (vm, "%8s  %8s  %s", "Start", "Count", "Owner");
     278             : 
     279             :   /* *INDENT-OFF* */
     280           0 :   vec_foreach (r, fm->ranges)
     281             :     {
     282           0 :       vlib_cli_output (vm, "%8u  %8u  %s", r->start, r->count, r->owner);
     283             :     };
     284             :   /* *INDENT-ON* */
     285           0 :   return 0;
     286             : }
     287             : 
     288             : /* *INDENT-OFF* */
     289      285289 : VLIB_CLI_COMMAND (show_flow_ranges_command, static) = {
     290             :     .path = "show flow ranges",
     291             :     .short_help = "show flow ranges",
     292             :     .function = show_flow_ranges,
     293             : };
     294             : /* *INDENT-ON* */
     295             : 
     296             : static clib_error_t *
     297           0 : show_flow_interface (vlib_main_t * vm, unformat_input_t * input,
     298             :                      vlib_cli_command_t * cmd_arg)
     299             : {
     300           0 :   vnet_main_t *vnm = vnet_get_main ();
     301             :   vnet_hw_interface_t *hi;
     302             :   vnet_device_class_t *dev_class;
     303           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     304           0 :   u32 hw_if_index = ~0;
     305             : 
     306           0 :   if (unformat_user (input, unformat_line_input, line_input))
     307             :     {
     308           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     309             :         {
     310           0 :           if (unformat (line_input, "%U",
     311             :                         unformat_vnet_hw_interface, vnm, &hw_if_index))
     312             :             ;
     313             :           else
     314           0 :             return clib_error_return (0, "parse error: '%U'",
     315             :                                       format_unformat_error, line_input);
     316             :         }
     317           0 :       unformat_free (line_input);
     318             :     }
     319             : 
     320           0 :   if (hw_if_index == ~0)
     321           0 :     return clib_error_return (0, "please specify interface");
     322             : 
     323           0 :   hi = vnet_get_hw_interface (vnm, hw_if_index);
     324           0 :   dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
     325           0 :   if (dev_class->format_flow == 0)
     326           0 :     return clib_error_return (0, "not supported");
     327             : 
     328           0 :   vlib_cli_output (vm, "%U", dev_class->format_flow, hi->dev_instance, ~0, 0);
     329           0 :   return 0;
     330             : }
     331             : 
     332             : /* *INDENT-OFF* */
     333      285289 : VLIB_CLI_COMMAND (show_flow_interface_command, static) = {
     334             :     .path = "show flow interface",
     335             :     .short_help = "show flow interface <interface name>",
     336             :     .function = show_flow_interface,
     337             : };
     338             : /* *INDENT-ON* */
     339             : 
     340             : static clib_error_t *
     341           0 : test_flow (vlib_main_t * vm, unformat_input_t * input,
     342             :            vlib_cli_command_t * cmd_arg)
     343             : {
     344             :   vnet_flow_t flow;
     345           0 :   vnet_main_t *vnm = vnet_get_main ();
     346           0 :   unformat_input_t _line_input, *line_input = &_line_input;
     347             :   enum
     348             :   {
     349             :     FLOW_UNKNOWN_ACTION,
     350             :     FLOW_ADD,
     351             :     FLOW_DEL,
     352             :     FLOW_ENABLE,
     353             :     FLOW_DISABLE
     354           0 :   } action = FLOW_UNKNOWN_ACTION;
     355             :   enum
     356             :   {
     357             :     FLOW_UNKNOWN_CLASS,
     358             :     FLOW_ETHERNET_CLASS,
     359             :     FLOW_IPV4_CLASS,
     360             :     FLOW_IPV6_CLASS,
     361           0 :   } flow_class = FLOW_UNKNOWN_CLASS;
     362             : 
     363           0 :   u32 hw_if_index = ~0, flow_index = ~0;
     364             :   int rv;
     365           0 :   u32 teid = 0, session_id = 0, spi = 0;
     366           0 :   u32 vni = 0;
     367           0 :   u32 queue_start = 0, queue_end = 0;
     368           0 :   vnet_flow_type_t type = VNET_FLOW_TYPE_UNKNOWN;
     369           0 :   ip4_address_and_mask_t ip4s = {}, in_ip4s = {};
     370           0 :   ip4_address_and_mask_t ip4d = {}, in_ip4d = {};
     371           0 :   ip6_address_and_mask_t ip6s = {}, in_ip6s = {};
     372           0 :   ip6_address_and_mask_t ip6d = {}, in_ip6d = {};
     373           0 :   ip_port_and_mask_t sport = {}, in_sport = {};
     374           0 :   ip_port_and_mask_t dport = {}, in_dport = {};
     375           0 :   ip_prot_and_mask_t protocol = {}, in_proto = {};
     376             :   u16 eth_type;
     377           0 :   bool inner_ip4_set = false, inner_ip6_set = false;
     378           0 :   bool tcp_udp_port_set = false, inner_port_set = false;
     379           0 :   bool gtpc_set = false;
     380           0 :   bool gtpu_set = false;
     381           0 :   bool vni_set = false;
     382           0 :   bool l2tpv3oip_set = false;
     383           0 :   bool ipsec_esp_set = false, ipsec_ah_set = false;
     384           0 :   u8 *rss_type[3] = { };
     385           0 :   u8 *type_str = NULL;
     386           0 :   u8 *spec = NULL;
     387           0 :   u8 *mask = NULL;
     388             : 
     389           0 :   clib_memset (&flow, 0, sizeof (vnet_flow_t));
     390           0 :   flow.index = ~0;
     391           0 :   flow.actions = 0;
     392             : 
     393           0 :   if (!unformat_user (input, unformat_line_input, line_input))
     394           0 :     return 0;
     395             : 
     396           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     397             :     {
     398           0 :       if (unformat (line_input, "add"))
     399           0 :         action = FLOW_ADD;
     400           0 :       else if (unformat (line_input, "del"))
     401           0 :         action = FLOW_DEL;
     402           0 :       else if (unformat (line_input, "enable"))
     403           0 :         action = FLOW_ENABLE;
     404           0 :       else if (unformat (line_input, "disable"))
     405           0 :         action = FLOW_DISABLE;
     406           0 :       else if (unformat (line_input, "spec %s", &spec))
     407             :         ;
     408           0 :       else if (unformat (line_input, "mask %s", &mask))
     409             :         ;
     410           0 :       else if (unformat (line_input, "eth-type %U",
     411             :                          unformat_ethernet_type_host_byte_order, &eth_type))
     412           0 :         flow_class = FLOW_ETHERNET_CLASS;
     413           0 :       else if (unformat (line_input, "src-ip %U",
     414             :                          unformat_ip4_address_and_mask, &ip4s))
     415           0 :         flow_class = FLOW_IPV4_CLASS;
     416           0 :       else if (unformat (line_input, "dst-ip %U",
     417             :                          unformat_ip4_address_and_mask, &ip4d))
     418           0 :         flow_class = FLOW_IPV4_CLASS;
     419           0 :       else if (unformat (line_input, "in-src-ip %U",
     420             :                          unformat_ip4_address_and_mask, &in_ip4s))
     421           0 :         inner_ip4_set = true;
     422           0 :       else if (unformat (line_input, "in-dst-ip %U",
     423             :                          unformat_ip4_address_and_mask, &in_ip4d))
     424           0 :         inner_ip4_set = true;
     425           0 :       else if (unformat (line_input, "ip6-src-ip %U",
     426             :                          unformat_ip6_address_and_mask, &ip6s))
     427           0 :         flow_class = FLOW_IPV6_CLASS;
     428           0 :       else if (unformat (line_input, "ip6-dst-ip %U",
     429             :                          unformat_ip6_address_and_mask, &ip6d))
     430           0 :         flow_class = FLOW_IPV6_CLASS;
     431           0 :       else if (unformat (line_input, "in-ip6-src-ip %U",
     432             :                          unformat_ip6_address_and_mask, &in_ip6s))
     433           0 :         inner_ip6_set = true;
     434           0 :       else if (unformat (line_input, "in-ip6-dst-ip %U",
     435             :                          unformat_ip6_address_and_mask, &in_ip6d))
     436           0 :         inner_ip6_set = true;
     437           0 :       else if (unformat (line_input, "src-port %U", unformat_ip_port_and_mask,
     438             :                          &sport))
     439           0 :         tcp_udp_port_set = true;
     440           0 :       else if (unformat (line_input, "dst-port %U", unformat_ip_port_and_mask,
     441             :                          &dport))
     442           0 :         tcp_udp_port_set = true;
     443             :       else
     444           0 :         if (unformat
     445             :             (line_input, "proto %U", unformat_ip_protocol_and_mask,
     446             :              &protocol))
     447             :         ;
     448           0 :       else if (unformat (line_input, "in-src-port %U",
     449             :                          unformat_ip_port_and_mask, &in_sport))
     450           0 :         inner_port_set = true;
     451           0 :       else if (unformat (line_input, "in-dst-port %U",
     452             :                          unformat_ip_port_and_mask, &in_dport))
     453           0 :         inner_port_set = true;
     454           0 :       else if (unformat (line_input, "in-proto %U",
     455             :                          unformat_ip_protocol_and_mask, &in_proto))
     456             :         ;
     457           0 :       else if (unformat (line_input, "gtpc teid %u", &teid))
     458           0 :         gtpc_set = true;
     459           0 :       else if (unformat (line_input, "gtpu teid %u", &teid))
     460           0 :         gtpu_set = true;
     461           0 :       else if (unformat (line_input, "vxlan vni %u", &vni))
     462           0 :         vni_set = true;
     463           0 :       else if (unformat (line_input, "session id %u", &session_id))
     464             :         {
     465           0 :           if (protocol.prot == IP_PROTOCOL_L2TP)
     466           0 :             l2tpv3oip_set = true;
     467             :         }
     468           0 :       else if (unformat (line_input, "spi %u", &spi))
     469             :         {
     470           0 :           if (protocol.prot == IP_PROTOCOL_IPSEC_ESP)
     471           0 :             ipsec_esp_set = true;
     472           0 :           else if (protocol.prot == IP_PROTOCOL_IPSEC_AH)
     473           0 :             ipsec_ah_set = true;
     474             :         }
     475           0 :       else if (unformat (line_input, "index %u", &flow_index))
     476             :         ;
     477           0 :       else if (unformat (line_input, "next-node %U", unformat_vlib_node, vm,
     478             :                          &flow.redirect_node_index))
     479           0 :         flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_NODE;
     480           0 :       else if (unformat (line_input, "mark %d", &flow.mark_flow_id))
     481           0 :         flow.actions |= VNET_FLOW_ACTION_MARK;
     482           0 :       else if (unformat (line_input, "buffer-advance %d",
     483             :                          &flow.buffer_advance))
     484           0 :         flow.actions |= VNET_FLOW_ACTION_BUFFER_ADVANCE;
     485           0 :       else if (unformat (line_input, "redirect-to-queue %d",
     486             :                          &flow.redirect_queue))
     487           0 :         flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_QUEUE;
     488           0 :       else if (unformat (line_input, "drop"))
     489           0 :         flow.actions |= VNET_FLOW_ACTION_DROP;
     490           0 :       else if (unformat (line_input, "rss function"))
     491             :         {
     492             :           if (0)
     493             :             ;
     494             : #undef _
     495             : #define _(f, s) \
     496             :       else if (unformat (line_input, s)) \
     497             :       flow.rss_fun = VNET_RSS_FUNC_##f;
     498             : 
     499           0 :           foreach_rss_function
     500             : #undef _
     501             :             else
     502             :             {
     503           0 :               return clib_error_return (0, "unknown input `%U'",
     504             :                                         format_unformat_error, line_input);
     505             :             }
     506             : 
     507           0 :           flow.actions |= VNET_FLOW_ACTION_RSS;
     508             :         }
     509           0 :       else if (unformat (line_input, "rss types"))
     510             :         {
     511           0 :           rss_type[0] = NULL;
     512           0 :           rss_type[1] = NULL;
     513           0 :           rss_type[2] = NULL;
     514           0 :           type_str = NULL;
     515             : 
     516           0 :           if (unformat (line_input, "%s use %s and %s",
     517             :                         &rss_type[0], &rss_type[1], &rss_type[2]))
     518             :             ;
     519           0 :           else if (unformat
     520             :                    (line_input, "%s use %s", &rss_type[0], &rss_type[1]))
     521             :             ;
     522           0 :           else if (unformat (line_input, "%s", &rss_type[0]))
     523             :             ;
     524             : 
     525             : #undef _
     526             : #define _(a,b,c)     \
     527             :       else if (!clib_strcmp(c, (const char *)type_str)) \
     528             :         flow.rss_types |= (1ULL<<a);
     529             : 
     530             : #define check_rss_types(_str)     \
     531             :       if (_str != NULL) {\
     532             :         type_str = _str;\
     533             :         if (0) \
     534             :           ; \
     535             :         foreach_flow_rss_types \
     536             :         else \
     537             :         { \
     538             :           return clib_error_return (0, "parse error: '%U'", \
     539             :           format_unformat_error, line_input); \
     540             :         } \
     541             :       }
     542             : 
     543           0 :           check_rss_types (rss_type[0])
     544           0 :             check_rss_types (rss_type[1]) check_rss_types (rss_type[2])
     545             : #undef _
     546           0 :             flow.actions |= VNET_FLOW_ACTION_RSS;
     547             :         }
     548           0 :       else if (unformat (line_input, "rss queues"))
     549             :         {
     550           0 :           if (unformat (line_input, "%d to %d", &queue_start, &queue_end))
     551             :             ;
     552             :           else
     553             :             {
     554           0 :               return clib_error_return (0, "unknown input `%U'",
     555             :                                         format_unformat_error, line_input);
     556             :             }
     557             : 
     558           0 :           flow.queue_index = queue_start;
     559           0 :           flow.queue_num = queue_end - queue_start + 1;
     560             : 
     561           0 :           flow.actions |= VNET_FLOW_ACTION_RSS;
     562             :         }
     563           0 :       else if (unformat (line_input, "%U", unformat_vnet_hw_interface, vnm,
     564             :                          &hw_if_index))
     565             :         ;
     566             :       else
     567           0 :         return clib_error_return (0, "parse error: '%U'",
     568             :                                   format_unformat_error, line_input);
     569             :     }
     570             : 
     571           0 :   unformat_free (line_input);
     572             : 
     573           0 :   if (hw_if_index == ~0 && (action == FLOW_ENABLE || action == FLOW_DISABLE))
     574           0 :     return clib_error_return (0, "Please specify interface name");
     575             : 
     576           0 :   if (flow_index == ~0 && (action == FLOW_ENABLE || action == FLOW_DISABLE ||
     577             :                            action == FLOW_DEL))
     578           0 :     return clib_error_return (0, "Please specify flow index");
     579             : 
     580           0 :   switch (action)
     581             :     {
     582           0 :     case FLOW_ADD:
     583           0 :       if (flow.actions == 0)
     584           0 :         return clib_error_return (0, "Please specify at least one action");
     585             : 
     586             :       /* Adjust the flow type */
     587             :       switch (flow_class)
     588             :         {
     589           0 :         case FLOW_ETHERNET_CLASS:
     590           0 :           type = VNET_FLOW_TYPE_ETHERNET;
     591           0 :           break;
     592             : 
     593           0 :         case FLOW_IPV4_CLASS:
     594           0 :           if (gtpc_set)
     595             :             {
     596           0 :               type = VNET_FLOW_TYPE_IP4_GTPC;
     597           0 :               protocol.prot = IP_PROTOCOL_UDP;
     598             :             }
     599           0 :           else if (gtpu_set)
     600             :             {
     601           0 :               type = VNET_FLOW_TYPE_IP4_GTPU;
     602           0 :               protocol.prot = IP_PROTOCOL_UDP;
     603             :             }
     604           0 :           else if (vni_set)
     605             :             {
     606           0 :               type = VNET_FLOW_TYPE_IP4_VXLAN;
     607           0 :               protocol.prot = IP_PROTOCOL_UDP;
     608             :             }
     609           0 :           else if (l2tpv3oip_set)
     610           0 :             type = VNET_FLOW_TYPE_IP4_L2TPV3OIP;
     611           0 :           else if (ipsec_esp_set)
     612           0 :             type = VNET_FLOW_TYPE_IP4_IPSEC_ESP;
     613           0 :           else if (ipsec_ah_set)
     614           0 :             type = VNET_FLOW_TYPE_IP4_IPSEC_AH;
     615           0 :           else if (tcp_udp_port_set)
     616           0 :             type = VNET_FLOW_TYPE_IP4_N_TUPLE;
     617           0 :           else if (inner_ip4_set)
     618             :             {
     619           0 :               if (inner_port_set)
     620           0 :                 type = VNET_FLOW_TYPE_IP4_IP4_N_TUPLE;
     621             :               else
     622           0 :                 type = VNET_FLOW_TYPE_IP4_IP4;
     623           0 :               protocol.prot = IP_PROTOCOL_IP_IN_IP;
     624             :             }
     625           0 :           else if (inner_ip6_set)
     626             :             {
     627           0 :               if (inner_port_set)
     628           0 :                 type = VNET_FLOW_TYPE_IP4_IP6_N_TUPLE;
     629             :               else
     630           0 :                 type = VNET_FLOW_TYPE_IP4_IP6;
     631           0 :               protocol.prot = IP_PROTOCOL_IPV6;
     632             :             }
     633             :           else
     634           0 :             type = VNET_FLOW_TYPE_IP4;
     635           0 :           break;
     636           0 :         case FLOW_IPV6_CLASS:
     637           0 :           if (tcp_udp_port_set)
     638           0 :             type = VNET_FLOW_TYPE_IP6_N_TUPLE;
     639           0 :           else if (vni_set)
     640           0 :             type = VNET_FLOW_TYPE_IP6_VXLAN;
     641           0 :           else if (inner_ip4_set)
     642             :             {
     643           0 :               if (inner_port_set)
     644           0 :                 type = VNET_FLOW_TYPE_IP6_IP4_N_TUPLE;
     645             :               else
     646           0 :                 type = VNET_FLOW_TYPE_IP6_IP4;
     647           0 :               protocol.prot = IP_PROTOCOL_IP_IN_IP;
     648             :             }
     649           0 :           else if (inner_ip6_set)
     650             :             {
     651           0 :               if (inner_port_set)
     652           0 :                 type = VNET_FLOW_TYPE_IP6_IP6_N_TUPLE;
     653             :               else
     654           0 :                 type = VNET_FLOW_TYPE_IP6_IP6;
     655           0 :               protocol.prot = IP_PROTOCOL_IPV6;
     656             :             }
     657             :           else
     658           0 :             type = VNET_FLOW_TYPE_IP6;
     659           0 :           break;
     660             : 
     661           0 :         default:
     662           0 :           if (spec && mask)
     663             :             {
     664           0 :               type = VNET_FLOW_TYPE_GENERIC;
     665           0 :               break;
     666             :             }
     667           0 :           return clib_error_return (0,
     668             :                                     "Please specify a supported flow type");
     669             :         }
     670             : 
     671             :       /* Assign specific field values per flow type */
     672           0 :       if (flow_class == FLOW_ETHERNET_CLASS)
     673             :         {
     674           0 :           flow.ethernet.eth_hdr.type = eth_type;
     675             :         }
     676           0 :       else if (flow_class == FLOW_IPV4_CLASS)
     677             :         {
     678           0 :           vnet_flow_ip4_t *ip4_ptr = &flow.ip4;
     679             : 
     680           0 :           clib_memcpy (&ip4_ptr->src_addr, &ip4s,
     681             :                        sizeof (ip4_address_and_mask_t));
     682           0 :           clib_memcpy (&ip4_ptr->dst_addr, &ip4d,
     683             :                        sizeof (ip4_address_and_mask_t));
     684           0 :           ip4_ptr->protocol.prot = protocol.prot;
     685             : 
     686             :           /* In this cli, we use the protocol.mask only when the flow type is
     687             :            * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
     688             :            * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
     689             :            */
     690           0 :           if (type == VNET_FLOW_TYPE_IP4)
     691           0 :             ip4_ptr->protocol.mask = protocol.mask;
     692             : 
     693           0 :           switch (protocol.prot)
     694             :             {
     695             :               /* ip4-n-tuple */
     696           0 :             case IP_PROTOCOL_TCP:
     697             :             case IP_PROTOCOL_UDP:
     698           0 :               flow.ip4_n_tuple.src_port = sport;
     699           0 :               flow.ip4_n_tuple.dst_port = dport;
     700             : 
     701           0 :               if (type == VNET_FLOW_TYPE_IP4_GTPC)
     702           0 :                 flow.ip4_gtpc.teid = teid;
     703           0 :               else if (type == VNET_FLOW_TYPE_IP4_GTPU)
     704           0 :                 flow.ip4_gtpu.teid = teid;
     705           0 :               else if (type == VNET_FLOW_TYPE_IP4_VXLAN)
     706           0 :                 flow.ip4_vxlan.vni = vni;
     707           0 :               break;
     708           0 :             case IP_PROTOCOL_L2TP:
     709           0 :               flow.ip4_l2tpv3oip.session_id = session_id;
     710           0 :               break;
     711           0 :             case IP_PROTOCOL_IPSEC_ESP:
     712           0 :               flow.ip4_ipsec_esp.spi = spi;
     713           0 :               break;
     714           0 :             case IP_PROTOCOL_IPSEC_AH:
     715           0 :               flow.ip4_ipsec_esp.spi = spi;
     716           0 :               break;
     717           0 :             case IP_PROTOCOL_IP_IN_IP:
     718           0 :               clib_memcpy (&flow.ip4_ip4.in_src_addr, &in_ip4s,
     719             :                            sizeof (ip4_address_and_mask_t));
     720           0 :               clib_memcpy (&flow.ip4_ip4.in_dst_addr, &in_ip4d,
     721             :                            sizeof (ip4_address_and_mask_t));
     722           0 :               if (type == VNET_FLOW_TYPE_IP4_IP4_N_TUPLE)
     723             :                 {
     724           0 :                   flow.ip4_ip4.in_protocol.prot = in_proto.prot;
     725           0 :                   flow.ip4_ip4_n_tuple.in_src_port = in_sport;
     726           0 :                   flow.ip4_ip4_n_tuple.in_dst_port = in_dport;
     727             :                 }
     728           0 :               break;
     729           0 :             case IP_PROTOCOL_IPV6:
     730           0 :               clib_memcpy (&flow.ip4_ip6.in_src_addr, &in_ip6s,
     731             :                            sizeof (ip6_address_and_mask_t));
     732           0 :               clib_memcpy (&flow.ip4_ip6.in_dst_addr, &in_ip6d,
     733             :                            sizeof (ip6_address_and_mask_t));
     734           0 :               if (type == VNET_FLOW_TYPE_IP4_IP6_N_TUPLE)
     735             :                 {
     736           0 :                   flow.ip4_ip6.in_protocol.prot = in_proto.prot;
     737           0 :                   flow.ip4_ip6_n_tuple.in_src_port = in_sport;
     738           0 :                   flow.ip4_ip6_n_tuple.in_dst_port = in_dport;
     739             :                 }
     740           0 :               break;
     741           0 :             default:
     742           0 :               break;
     743             :             }
     744             :         }
     745           0 :       else if (flow_class == FLOW_IPV6_CLASS)
     746             :         {
     747           0 :           vnet_flow_ip6_t *ip6_ptr = &flow.ip6;
     748             : 
     749           0 :           clib_memcpy (&flow.ip6_n_tuple.src_addr, &ip6s,
     750             :                        sizeof (ip6_address_and_mask_t));
     751           0 :           clib_memcpy (&flow.ip6_n_tuple.dst_addr, &ip6d,
     752             :                        sizeof (ip6_address_and_mask_t));
     753             : 
     754           0 :           ip6_ptr->protocol.prot = protocol.prot;
     755             : 
     756             :           /* In this cli, we use the protocol.mask only when the flow type is
     757             :            * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
     758             :            * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
     759             :            */
     760           0 :           if (type == VNET_FLOW_TYPE_IP6)
     761           0 :             ip6_ptr->protocol.mask = protocol.mask;
     762             : 
     763           0 :           switch (protocol.prot)
     764             :             {
     765             :               /* ip6-n-tuple */
     766           0 :             case IP_PROTOCOL_TCP:
     767             :             case IP_PROTOCOL_UDP:
     768           0 :               flow.ip6_n_tuple.src_port = sport;
     769           0 :               flow.ip6_n_tuple.dst_port = dport;
     770             : 
     771           0 :               if (type == VNET_FLOW_TYPE_IP6_VXLAN)
     772           0 :                 flow.ip6_vxlan.vni = vni;
     773           0 :               break;
     774           0 :             case IP_PROTOCOL_IP_IN_IP:
     775           0 :               clib_memcpy (&flow.ip6_ip4.in_src_addr, &in_ip4s,
     776             :                            sizeof (ip4_address_and_mask_t));
     777           0 :               clib_memcpy (&flow.ip6_ip4.in_dst_addr, &in_ip4d,
     778             :                            sizeof (ip4_address_and_mask_t));
     779           0 :               if (type == VNET_FLOW_TYPE_IP6_IP4_N_TUPLE)
     780             :                 {
     781           0 :                   flow.ip6_ip4.in_protocol.prot = in_proto.prot;
     782           0 :                   flow.ip6_ip4_n_tuple.in_src_port = in_sport;
     783           0 :                   flow.ip6_ip4_n_tuple.in_dst_port = in_dport;
     784             :                 }
     785           0 :               break;
     786           0 :             case IP_PROTOCOL_IPV6:
     787           0 :               clib_memcpy (&flow.ip6_ip6.in_src_addr, &in_ip6s,
     788             :                            sizeof (ip6_address_and_mask_t));
     789           0 :               clib_memcpy (&flow.ip6_ip6.in_dst_addr, &in_ip6d,
     790             :                            sizeof (ip6_address_and_mask_t));
     791           0 :               if (type == VNET_FLOW_TYPE_IP6_IP6_N_TUPLE)
     792             :                 {
     793           0 :                   flow.ip6_ip6.in_protocol.prot = in_proto.prot;
     794           0 :                   flow.ip6_ip6_n_tuple.in_src_port = in_sport;
     795           0 :                   flow.ip6_ip6_n_tuple.in_dst_port = in_dport;
     796             :                 }
     797           0 :               break;
     798           0 :             default:
     799           0 :               break;
     800             :             }
     801           0 :         }
     802           0 :       if (type == VNET_FLOW_TYPE_GENERIC)
     803             :         {
     804           0 :           clib_memcpy (flow.generic.pattern.spec, spec,
     805             :                        sizeof (flow.generic.pattern.spec));
     806           0 :           clib_memcpy (flow.generic.pattern.mask, mask,
     807             :                        sizeof (flow.generic.pattern.mask));
     808             :         }
     809             : 
     810           0 :       flow.type = type;
     811           0 :       rv = vnet_flow_add (vnm, &flow, &flow_index);
     812           0 :       if (!rv)
     813           0 :         vlib_cli_output (vm, "flow %u added", flow_index);
     814             : 
     815           0 :       break;
     816           0 :     case FLOW_DEL:
     817           0 :       rv = vnet_flow_del (vnm, flow_index);
     818           0 :       break;
     819           0 :     case FLOW_ENABLE:
     820           0 :       rv = vnet_flow_enable (vnm, flow_index, hw_if_index);
     821           0 :       break;
     822           0 :     case FLOW_DISABLE:
     823           0 :       rv = vnet_flow_disable (vnm, flow_index, hw_if_index);
     824           0 :       break;
     825           0 :     default:
     826           0 :       return clib_error_return (0, "please specify action (add, del, enable,"
     827             :                                 " disable)");
     828             :     }
     829             : 
     830           0 :   if (rv < 0)
     831           0 :     return clib_error_return (0, "flow error: %U", format_flow_error, rv);
     832             : 
     833           0 :   return 0;
     834             : }
     835             : 
     836             : /* *INDENT-OFF* */
     837      285289 : VLIB_CLI_COMMAND (test_flow_command, static) = {
     838             :   .path = "test flow",
     839             :   .short_help = "test flow [add|del|enable|disable] [index <id>] "
     840             :                 "[src-ip <ip-addr/mask>] [dst-ip <ip-addr/mask>] "
     841             :                 "[ip6-src-ip <ip-addr/mask>] [ip6-dst-ip <ip-addr/mask>] "
     842             :                 "[src-port <port/mask>] [dst-port <port/mask>] "
     843             :                 "[proto <ip-proto>] "
     844             :                 "[gtpc teid <teid>] [gtpu teid <teid>] [vxlan <vni>] "
     845             :                 "[session id <session>] [spi <spi>]"
     846             :                 "[spec <spec string>] [mask <mask string>]"
     847             :                 "[next-node <node>] [mark <id>] [buffer-advance <len>] "
     848             :                 "[redirect-to-queue <queue>] [drop] "
     849             :                 "[rss function <name>] [rss types <flow type>]"
     850             :                 "[rss queues <queue_start> to <queue_end>]",
     851             :   .function = test_flow,
     852             : };
     853             : /* *INDENT-ON* */
     854             : 
     855             : static u8 *
     856           0 : format_flow_match_element (u8 * s, va_list * args)
     857             : {
     858           0 :   char *type = va_arg (*args, char *);
     859           0 :   void *ptr = va_arg (*args, void *);
     860             : 
     861           0 :   if (strncmp (type, "u8", 2) == 0)
     862           0 :     return format (s, "%d", *(u8 *) ptr);
     863             : 
     864           0 :   if (strncmp (type, "u16", 3) == 0)
     865           0 :     return format (s, "%d", *(u16 *) ptr);
     866             : 
     867           0 :   if (strncmp (type, "u32", 3) == 0)
     868           0 :     return format (s, "%d", *(u32 *) ptr);
     869             : 
     870           0 :   if (strncmp (type, "ethernet_header_t", 13) == 0)
     871             :     {
     872             :       ethernet_max_header_t m;
     873           0 :       memset (&m, 0, sizeof (m));
     874           0 :       m.ethernet = *(ethernet_header_t *) ptr;
     875             :       /* convert the ethernet type to net order */
     876           0 :       m.ethernet.type = clib_host_to_net_u16 (m.ethernet.type);
     877           0 :       return format (s, "%U", format_ethernet_header, &m);
     878             :     }
     879             : 
     880           0 :   if (strncmp (type, "ip4_address_t", 13) == 0)
     881           0 :     return format (s, "%U", format_ip4_address, ptr);
     882             : 
     883           0 :   if (strncmp (type, "ip4_address_and_mask_t", 13) == 0)
     884           0 :     return format (s, "%U", format_ip4_address_and_mask, ptr);
     885             : 
     886           0 :   if (strncmp (type, "ip6_address_t", 13) == 0)
     887           0 :     return format (s, "%U", format_ip6_address, ptr);
     888             : 
     889           0 :   if (strncmp (type, "ip6_address_and_mask_t", 13) == 0)
     890           0 :     return format (s, "%U", format_ip6_address_and_mask, ptr);
     891             : 
     892           0 :   if (strncmp (type, "ip_prot_and_mask_t", 13) == 0)
     893           0 :     return format (s, "%U", format_ip_protocol_and_mask, ptr);
     894             : 
     895           0 :   if (strncmp (type, "ip_port_and_mask_t", 18) == 0)
     896           0 :     return format (s, "%U", format_ip_port_and_mask, ptr);
     897             : 
     898           0 :   s = format (s, "unknown type '%s'", type);
     899           0 :   return s;
     900             : }
     901             : 
     902             : #define _fe(a,b) s2 = format (s2, "%s%s %U", s2 ? ", ":"", #b, \
     903             :                               format_flow_match_element, #a, &f->b);
     904             : #define _(a,b,c) \
     905             : u8 * format_flow_match_##b (u8 * s, va_list * args)                     \
     906             : {                                                                       \
     907             :   vnet_flow_##b##_t *f = __builtin_va_arg (*args, vnet_flow_##b##_t *); \
     908             :   u8 *s2 = 0; \
     909             : foreach_flow_entry_##b \
     910             :   s = format (s, "%v", s2);; \
     911             :   vec_free (s2); \
     912             : return s; \
     913             : }
     914           0 : foreach_flow_type
     915             : #undef _
     916             : #undef _fe
     917             : static u8 *
     918           0 : format_flow_match (u8 * s, va_list * args)
     919             : {
     920           0 :   vnet_flow_t *f = va_arg (*args, vnet_flow_t *);
     921             : 
     922             : #define _(a,b,c) \
     923             :   if (f->type == VNET_FLOW_TYPE_##a) \
     924             :     return format (s, "%U", format_flow_match_##b, &f->b);
     925           0 :   foreach_flow_type;
     926             : #undef _
     927             : 
     928           0 :   return s;
     929             : }
     930             : 
     931             : static u8 *
     932           0 : format_flow (u8 * s, va_list * args)
     933             : {
     934           0 :   vlib_main_t *vm = vlib_get_main ();
     935           0 :   vnet_flow_t *f = va_arg (*args, vnet_flow_t *);
     936           0 :   u32 indent = format_get_indent (s);
     937           0 :   u8 *t = 0;
     938             : 
     939           0 :   s = format (s, "flow-index %u type %s active %u",
     940           0 :               f->index, flow_type_strings[f->type],
     941           0 :               hash_elts (f->private_data)),
     942           0 :     s = format (s, "\n%Umatch: %U", format_white_space, indent + 2,
     943             :                 format_flow_match, f);
     944           0 :   s = format (s, "\n%Uaction: %U", format_white_space, indent + 2,
     945             :               format_flow_actions, f->actions);
     946             : 
     947           0 :   if (f->actions & VNET_FLOW_ACTION_DROP)
     948           0 :     t = format (t, "%sdrop", t ? ", " : "");
     949             : 
     950           0 :   if (f->actions & VNET_FLOW_ACTION_MARK)
     951           0 :     t = format (t, "%smark %u", t ? ", " : "", f->mark_flow_id);
     952             : 
     953           0 :   if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_QUEUE)
     954           0 :     t =
     955           0 :       format (t, "%sredirect-to-queue %u", t ? ", " : "", f->redirect_queue);
     956             : 
     957           0 :   if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
     958           0 :     t = format (t, "%snext-node %U", t ? ", " : "",
     959             :                 format_vlib_node_name, vm, f->redirect_node_index);
     960             : 
     961           0 :   if (f->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
     962           0 :     t = format (t, "%sbuffer-advance %d", t ? ", " : "", f->buffer_advance);
     963             : 
     964           0 :   if (f->actions & VNET_FLOW_ACTION_RSS)
     965             :     {
     966           0 :       t = format (t, "%srss function %U", t ? ", " : "",
     967           0 :                   format_rss_function, f->rss_fun);
     968           0 :       t = format (t, "%srss types %U", t ? ", " : "",
     969             :                   format_rss_types, f->rss_types);
     970             :     }
     971             : 
     972           0 :   if (t)
     973             :     {
     974           0 :       s = format (s, "\n%U%v", format_white_space, indent + 4, t);
     975           0 :       vec_free (t);
     976             :     }
     977             : 
     978           0 :   return s;
     979             : }
     980             : 
     981             : /*
     982             :  * fd.io coding-style-patch-verification: ON
     983             :  *
     984             :  * Local Variables:
     985             :  * eval: (c-set-style "gnu")
     986             :  * End:
     987             :  */

Generated by: LCOV version 1.14