FD.io VPP  v21.01.1
Vector Packet Processing
flow_cli.c
Go to the documentation of this file.
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 
25 
26 uword
28 {
29  ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *);
30  u32 port = 0, mask = 0;
31 
32  if (unformat (input, "any"))
33  ;
34  else if (unformat (input, "%u/%u", &port, &mask))
35  ;
36  else if (unformat (input, "%u/0x%x", &port, &mask))
37  ;
38  else if (unformat (input, "%u", &port))
39  mask = 0xffff;
40  else
41  return 0;
42 
43  if (port > 0xffff || mask > 0xffff)
44  return 0;
45 
46  pm->port = port;
47  pm->mask = mask;
48  return 1;
49 }
50 
51 u8 *
52 format_ip_port_and_mask (u8 * s, va_list * args)
53 {
54  ip_port_and_mask_t *pm = va_arg (*args, ip_port_and_mask_t *);
55 
56  if (pm->port == 0 && pm->mask == 0)
57  return format (s, "any");
58 
59  if (pm->mask == 0xffff)
60  return format (s, "%u", pm->port);
61 
62  return format (s, "%u/0x%x", pm->port, pm->mask);
63 }
64 
65 uword
67 {
68  ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *);
69  u32 prot = 0, mask = 0;
70 
71  if (unformat (input, "any"))
72  ;
73  else if (unformat (input, "%U", unformat_ip_protocol, &prot))
74  mask = 0xFF;
75  else if (unformat (input, "%u", &prot))
76  mask = 0xFF;
77  else
78  return 0;
79 
80  if (prot > 0XFF || mask > 0xFF)
81  return 0;
82 
83  pm->prot = prot;
84  pm->mask = mask;
85  return 1;
86 }
87 
88 u8 *
89 format_ip_protocol_and_mask (u8 * s, va_list * args)
90 {
91  ip_prot_and_mask_t *pm = va_arg (*args, ip_prot_and_mask_t *);
92 
93  if (pm->prot == 0 && pm->mask == 0)
94  return format (s, "any");
95 
96  return format (s, "%U", format_ip_protocol, pm->prot);
97 }
98 
99 u8 *
100 format_flow_error (u8 * s, va_list * args)
101 {
102  int error = va_arg (*args, int);
103 
104  if (error == 0)
105  return format (s, "no error");
106 
107 #define _(v,n,str) if (error == v) return format (s, #str);
109 #undef _
110 
111  return format (s, "unknown error (%d)", error);
112 }
113 
114 u8 *
115 format_flow_actions (u8 * s, va_list * args)
116 {
117  u32 actions = va_arg (*args, u32);
118  u8 *t = 0;
119 
120 #define _(a, b, c) if (actions & (1 << a)) \
121  t = format (t, "%s%s", t ? " ":"", c);
123 #undef _
124  s = format (s, "%v", t);
125  vec_free (t);
126  return s;
127 }
128 
129 u8 *
130 format_flow_enabled_hw (u8 * s, va_list * args)
131 {
132  u32 flow_index = va_arg (*args, u32);
133  vnet_flow_t *f = vnet_get_flow (flow_index);
134  if (f == 0)
135  return format (s, "not found");
136 
137  u8 *t = 0;
138  u32 hw_if_index;
139  uword private_data;
140  vnet_main_t *vnm = vnet_get_main ();
141  /* *INDENT-OFF* */
142  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  s = format (s, "%v", t);
149  vec_free (t);
150  return s;
151 }
152 
153 u8 *
154 format_rss_function (u8 * s, va_list * args)
155 {
156  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 
166 #undef _
167  return format (s, "unknown");
168 }
169 
170 u8 *
171 format_rss_types (u8 * s, va_list * args)
172 {
173  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 
181 #undef _
182  return s;
183 }
184 
185 static const char *flow_type_strings[] = { 0,
186 #define _(a,b,c) c,
188 #undef _
189 };
190 
191 static clib_error_t *
193  vlib_cli_command_t * cmd_arg)
194 {
195  vnet_main_t *vnm = vnet_get_main ();
197  unformat_input_t _line_input, *line_input = &_line_input;
199  vnet_device_class_t *dev_class;
200  vnet_flow_t *f;
201  uword private_data;
202  u32 index = ~0, hw_if_index;
203 
204  if (!unformat_user (input, unformat_line_input, line_input))
205  goto no_args;
206 
207  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
208  {
209  if (unformat (line_input, "index %u", &index))
210  ;
211  else
212  return clib_error_return (0, "parse error: '%U'",
213  format_unformat_error, line_input);
214  }
215 
216  unformat_free (line_input);
217 
218  if (index != ~0)
219  {
220  if ((f = vnet_get_flow (index)) == 0)
221  return clib_error_return (0, "no such flow");
222 
223  vlib_cli_output (vm, "%-10s: %u", "index", f->index);
224  vlib_cli_output (vm, "%-10s: %s", "type", flow_type_strings[f->type]);
225  vlib_cli_output (vm, "%-10s: %U", "match", format_flow, f);
226  /* *INDENT-OFF* */
227  hash_foreach (hw_if_index, private_data, f->private_data,
228  ({
229  hi = vnet_get_hw_interface (vnm, hw_if_index);
230  dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
231  vlib_cli_output (vm, "interface %U\n",
232  format_vnet_hw_if_index_name, vnm, hw_if_index);
233  if (dev_class->format_flow)
234  vlib_cli_output (vm, " %U\n", dev_class->format_flow,
235  hi->dev_instance, f->index, private_data);
236  }));
237  /* *INDENT-ON* */
238  return 0;
239  }
240 
241 no_args:
242  /* *INDENT-OFF* */
244  {
245  vlib_cli_output (vm, "%U\n", format_flow, f);
246  }
247  /* *INDENT-ON* */
248 
249  return 0;
250 }
251 
252 /* *INDENT-OFF* */
253 VLIB_CLI_COMMAND (show_flow_entry_command, static) = {
254  .path = "show flow entry",
255  .short_help = "show flow entry [index <index>]",
256  .function = show_flow_entry,
257 };
258 /* *INDENT-ON* */
259 
260 static clib_error_t *
262  vlib_cli_command_t * cmd_arg)
263 {
265  vnet_flow_range_t *r = 0;
266 
267  vlib_cli_output (vm, "%8s %8s %s", "Start", "Count", "Owner");
268 
269  /* *INDENT-OFF* */
270  vec_foreach (r, fm->ranges)
271  {
272  vlib_cli_output (vm, "%8u %8u %s", r->start, r->count, r->owner);
273  };
274  /* *INDENT-ON* */
275  return 0;
276 }
277 
278 /* *INDENT-OFF* */
279 VLIB_CLI_COMMAND (show_flow_ranges_command, static) = {
280  .path = "show flow ranges",
281  .short_help = "show flow ranges",
282  .function = show_flow_ranges,
283 };
284 /* *INDENT-ON* */
285 
286 static clib_error_t *
288  vlib_cli_command_t * cmd_arg)
289 {
290  vnet_main_t *vnm = vnet_get_main ();
292  vnet_device_class_t *dev_class;
293  unformat_input_t _line_input, *line_input = &_line_input;
294  u32 hw_if_index = ~0;
295 
296  if (unformat_user (input, unformat_line_input, line_input))
297  {
298  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
299  {
300  if (unformat (line_input, "%U",
301  unformat_vnet_hw_interface, vnm, &hw_if_index))
302  ;
303  else
304  return clib_error_return (0, "parse error: '%U'",
305  format_unformat_error, line_input);
306  }
307  unformat_free (line_input);
308  }
309 
310  if (hw_if_index == ~0)
311  return clib_error_return (0, "please specify interface");
312 
313  hi = vnet_get_hw_interface (vnm, hw_if_index);
314  dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
315  if (dev_class->format_flow == 0)
316  return clib_error_return (0, "not supported");
317 
318  vlib_cli_output (vm, "%U", dev_class->format_flow, hi->dev_instance, ~0, 0);
319  return 0;
320 }
321 
322 /* *INDENT-OFF* */
323 VLIB_CLI_COMMAND (show_flow_interface_command, static) = {
324  .path = "show flow interface",
325  .short_help = "show flow interface <interface name>",
326  .function = show_flow_interface,
327 };
328 /* *INDENT-ON* */
329 
330 static clib_error_t *
332  vlib_cli_command_t * cmd_arg)
333 {
335  vnet_main_t *vnm = vnet_get_main ();
336  unformat_input_t _line_input, *line_input = &_line_input;
337  enum
338  {
339  FLOW_UNKNOWN_ACTION,
340  FLOW_ADD,
341  FLOW_DEL,
342  FLOW_ENABLE,
343  FLOW_DISABLE
344  } action = FLOW_UNKNOWN_ACTION;
345  enum
346  {
347  FLOW_UNKNOWN_CLASS,
348  FLOW_ETHERNET_CLASS,
349  FLOW_IPV4_CLASS,
350  FLOW_IPV6_CLASS,
351  } flow_class = FLOW_UNKNOWN_CLASS;
352 
353  u32 hw_if_index = ~0, flow_index = ~0;
354  int rv;
355  u32 teid = 0, session_id = 0, spi = 0;
356  u16 vni = 0;
358  ip4_address_and_mask_t ip4s = { };
359  ip4_address_and_mask_t ip4d = { };
360  ip6_address_and_mask_t ip6s = { };
361  ip6_address_and_mask_t ip6d = { };
362  ip_port_and_mask_t sport = { };
363  ip_port_and_mask_t dport = { };
365  u16 eth_type;
366  bool tcp_udp_port_set = false;
367  bool gtpc_set = false;
368  bool gtpu_set = false;
369  bool vni_set = false;
370  bool l2tpv3oip_set = false;
371  bool ipsec_esp_set = false, ipsec_ah_set = false;
372  u8 *rss_type[3] = { };
373  u8 *type_str = NULL;
374 
375  clib_memset (&flow, 0, sizeof (vnet_flow_t));
376  flow.index = ~0;
377  flow.actions = 0;
378 
379  if (!unformat_user (input, unformat_line_input, line_input))
380  return 0;
381 
382  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
383  {
384  if (unformat (line_input, "add"))
385  action = FLOW_ADD;
386  else if (unformat (line_input, "del"))
387  action = FLOW_DEL;
388  else if (unformat (line_input, "enable"))
389  action = FLOW_ENABLE;
390  else if (unformat (line_input, "disable"))
391  action = FLOW_DISABLE;
392  else if (unformat (line_input, "eth-type %U",
394  flow_class = FLOW_ETHERNET_CLASS;
395  else if (unformat (line_input, "src-ip %U",
397  flow_class = FLOW_IPV4_CLASS;
398  else if (unformat (line_input, "dst-ip %U",
400  flow_class = FLOW_IPV4_CLASS;
401  else if (unformat (line_input, "ip6-src-ip %U",
403  flow_class = FLOW_IPV6_CLASS;
404  else if (unformat (line_input, "ip6-dst-ip %U",
406  flow_class = FLOW_IPV6_CLASS;
407  else if (unformat (line_input, "src-port %U", unformat_ip_port_and_mask,
408  &sport))
409  tcp_udp_port_set = true;
410  else if (unformat (line_input, "dst-port %U", unformat_ip_port_and_mask,
411  &dport))
412  tcp_udp_port_set = true;
413  else
414  if (unformat
415  (line_input, "proto %U", unformat_ip_protocol_and_mask,
416  &protocol))
417  ;
418  else if (unformat (line_input, "gtpc teid %u", &teid))
419  gtpc_set = true;
420  else if (unformat (line_input, "gtpu teid %u", &teid))
421  gtpu_set = true;
422  else if (unformat (line_input, "vxlan vni %u", &vni))
423  vni_set = true;
424  else if (unformat (line_input, "session id %u", &session_id))
425  {
426  if (protocol.prot == IP_PROTOCOL_L2TP)
427  l2tpv3oip_set = true;
428  }
429  else if (unformat (line_input, "spi %u", &spi))
430  {
431  if (protocol.prot == IP_PROTOCOL_IPSEC_ESP)
432  ipsec_esp_set = true;
433  else if (protocol.prot == IP_PROTOCOL_IPSEC_AH)
434  ipsec_ah_set = true;
435  }
436  else if (unformat (line_input, "index %u", &flow_index))
437  ;
438  else if (unformat (line_input, "next-node %U", unformat_vlib_node, vm,
439  &flow.redirect_node_index))
440  flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_NODE;
441  else if (unformat (line_input, "mark %d", &flow.mark_flow_id))
442  flow.actions |= VNET_FLOW_ACTION_MARK;
443  else if (unformat (line_input, "buffer-advance %d",
444  &flow.buffer_advance))
445  flow.actions |= VNET_FLOW_ACTION_BUFFER_ADVANCE;
446  else if (unformat (line_input, "redirect-to-queue %d",
447  &flow.redirect_queue))
448  flow.actions |= VNET_FLOW_ACTION_REDIRECT_TO_QUEUE;
449  else if (unformat (line_input, "drop"))
450  flow.actions |= VNET_FLOW_ACTION_DROP;
451  else if (unformat (line_input, "rss function"))
452  {
453  if (0)
454  ;
455 #undef _
456 #define _(f, s) \
457  else if (unformat (line_input, s)) \
458  flow.rss_fun = VNET_RSS_FUNC_##f;
459 
461 #undef _
462  else
463  {
464  return clib_error_return (0, "unknown input `%U'",
465  format_unformat_error, line_input);
466  }
467 
468  flow.actions |= VNET_FLOW_ACTION_RSS;
469  }
470  else if (unformat (line_input, "rss types"))
471  {
472  rss_type[0] = NULL;
473  rss_type[1] = NULL;
474  rss_type[2] = NULL;
475  type_str = NULL;
476 
477  if (unformat (line_input, "%s use %s and %s",
478  &rss_type[0], &rss_type[1], &rss_type[2]))
479  ;
480  else if (unformat
481  (line_input, "%s use %s", &rss_type[0], &rss_type[1]))
482  ;
483  else if (unformat (line_input, "%s", &rss_type[0]))
484  ;
485 
486 #undef _
487 #define _(a,b,c) \
488  else if (!clib_strcmp(c, (const char *)type_str)) \
489  flow.rss_types |= (1ULL<<a);
490 
491 #define check_rss_types(_str) \
492  if (_str != NULL) {\
493  type_str = _str;\
494  if (0) \
495  ; \
496  foreach_flow_rss_types \
497  else \
498  { \
499  return clib_error_return (0, "parse error: '%U'", \
500  format_unformat_error, line_input); \
501  } \
502  }
503 
504  check_rss_types (rss_type[0])
505  check_rss_types (rss_type[1]) check_rss_types (rss_type[2])
506 #undef _
507  flow.actions |= VNET_FLOW_ACTION_RSS;
508  }
509  else if (unformat (line_input, "%U", unformat_vnet_hw_interface, vnm,
510  &hw_if_index))
511  ;
512  else
513  return clib_error_return (0, "parse error: '%U'",
514  format_unformat_error, line_input);
515  }
516 
517  unformat_free (line_input);
518 
519  if (hw_if_index == ~0 && (action == FLOW_ENABLE || action == FLOW_DISABLE))
520  return clib_error_return (0, "Please specify interface name");
521 
522  if (flow_index == ~0 && (action == FLOW_ENABLE || action == FLOW_DISABLE ||
523  action == FLOW_DEL))
524  return clib_error_return (0, "Please specify flow index");
525 
526  switch (action)
527  {
528  case FLOW_ADD:
529  if (flow.actions == 0)
530  return clib_error_return (0, "Please specify at least one action");
531 
532  /* Adjust the flow type */
533  switch (flow_class)
534  {
535  case FLOW_ETHERNET_CLASS:
536  type = VNET_FLOW_TYPE_ETHERNET;
537  break;
538 
539  case FLOW_IPV4_CLASS:
540  if (gtpc_set)
541  {
542  type = VNET_FLOW_TYPE_IP4_GTPC;
543  protocol.prot = IP_PROTOCOL_UDP;
544  }
545  else if (gtpu_set)
546  {
547  type = VNET_FLOW_TYPE_IP4_GTPU;
548  protocol.prot = IP_PROTOCOL_UDP;
549  }
550  else if (vni_set)
551  {
552  type = VNET_FLOW_TYPE_IP4_VXLAN;
553  protocol.prot = IP_PROTOCOL_UDP;
554  }
555  else if (l2tpv3oip_set)
556  type = VNET_FLOW_TYPE_IP4_L2TPV3OIP;
557  else if (ipsec_esp_set)
558  type = VNET_FLOW_TYPE_IP4_IPSEC_ESP;
559  else if (ipsec_ah_set)
560  type = VNET_FLOW_TYPE_IP4_IPSEC_AH;
561  else if (tcp_udp_port_set)
562  type = VNET_FLOW_TYPE_IP4_N_TUPLE;
563  else
564  type = VNET_FLOW_TYPE_IP4;
565  break;
566  case FLOW_IPV6_CLASS:
567  if (tcp_udp_port_set)
568  type = VNET_FLOW_TYPE_IP6_N_TUPLE;
569  else if (vni_set)
570  type = VNET_FLOW_TYPE_IP6_VXLAN;
571  else
572  type = VNET_FLOW_TYPE_IP6;
573  break;
574 
575  default:
576  return clib_error_return (0,
577  "Please specify a supported flow type");
578  }
579 
580  /* Assign specific field values per flow type */
581  if (flow_class == FLOW_ETHERNET_CLASS)
582  {
583  flow.ethernet.eth_hdr.type = eth_type;
584  }
585  else if (flow_class == FLOW_IPV4_CLASS)
586  {
587  vnet_flow_ip4_t *ip4_ptr = &flow.ip4;
588 
589  clib_memcpy (&ip4_ptr->src_addr, &ip4s,
590  sizeof (ip4_address_and_mask_t));
591  clib_memcpy (&ip4_ptr->dst_addr, &ip4d,
592  sizeof (ip4_address_and_mask_t));
593  ip4_ptr->protocol.prot = protocol.prot;
594 
595  /* In this cli, we use the protocol.mask only when the flow type is
596  * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
597  * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
598  */
599  if (type == VNET_FLOW_TYPE_IP4)
600  ip4_ptr->protocol.mask = protocol.mask;
601 
602  switch (protocol.prot)
603  {
604  /* ip4-n-tuple */
605  case IP_PROTOCOL_TCP:
606  case IP_PROTOCOL_UDP:
607  flow.ip4_n_tuple.src_port = sport;
608  flow.ip4_n_tuple.dst_port = dport;
609 
610  if (type == VNET_FLOW_TYPE_IP4_GTPC)
611  flow.ip4_gtpc.teid = teid;
612  else if (type == VNET_FLOW_TYPE_IP4_GTPU)
613  flow.ip4_gtpu.teid = teid;
614  else if (type == VNET_FLOW_TYPE_IP4_VXLAN)
615  flow.ip4_vxlan.vni = vni;
616  break;
617  case IP_PROTOCOL_L2TP:
618  flow.ip4_l2tpv3oip.session_id = session_id;
619  break;
620  case IP_PROTOCOL_IPSEC_ESP:
621  flow.ip4_ipsec_esp.spi = spi;
622  break;
623  case IP_PROTOCOL_IPSEC_AH:
624  flow.ip4_ipsec_esp.spi = spi;
625  break;
626  default:
627  break;
628  }
629  }
630  else if (flow_class == FLOW_IPV6_CLASS)
631  {
632  vnet_flow_ip6_t *ip6_ptr = &flow.ip6;
633 
634  clib_memcpy (&flow.ip6_n_tuple.src_addr, &ip6s,
635  sizeof (ip6_address_and_mask_t));
636  clib_memcpy (&flow.ip6_n_tuple.dst_addr, &ip6d,
637  sizeof (ip6_address_and_mask_t));
638 
639  ip6_ptr->protocol.prot = protocol.prot;
640 
641  /* In this cli, we use the protocol.mask only when the flow type is
642  * VNET_FLOW_TYPE_IP4/IP6. For other cases, the IP protocol is just
643  * used to identify the next layer type: e.g. UDP/TCP or IPSEC_ESP
644  */
645  if (type == VNET_FLOW_TYPE_IP6)
646  ip6_ptr->protocol.mask = protocol.mask;
647 
648  switch (protocol.prot)
649  {
650  /* ip6-n-tuple */
651  case IP_PROTOCOL_TCP:
652  case IP_PROTOCOL_UDP:
653  flow.ip6_n_tuple.src_port = sport;
654  flow.ip6_n_tuple.dst_port = dport;
655 
656  if (type == VNET_FLOW_TYPE_IP6_VXLAN)
657  flow.ip6_vxlan.vni = vni;
658  break;
659  default:
660  break;
661  }
662  }
663 
664  flow.type = type;
665  rv = vnet_flow_add (vnm, &flow, &flow_index);
666  if (!rv)
667  vlib_cli_output (vm, "flow %u added", flow_index);
668 
669  break;
670  case FLOW_DEL:
671  rv = vnet_flow_del (vnm, flow_index);
672  break;
673  case FLOW_ENABLE:
674  rv = vnet_flow_enable (vnm, flow_index, hw_if_index);
675  break;
676  case FLOW_DISABLE:
677  rv = vnet_flow_disable (vnm, flow_index, hw_if_index);
678  break;
679  default:
680  return clib_error_return (0, "please specify action (add, del, enable,"
681  " disable)");
682  }
683 
684  if (rv < 0)
685  return clib_error_return (0, "flow error: %U", format_flow_error, rv);
686 
687  return 0;
688 }
689 
690 /* *INDENT-OFF* */
691 VLIB_CLI_COMMAND (test_flow_command, static) = {
692  .path = "test flow",
693  .short_help = "test flow [add|del|enable|disable] [index <id>] "
694  "[src-ip <ip-addr/mask>] [dst-ip <ip-addr/mask>] "
695  "[ip6-src-ip <ip-addr/mask>] [ip6-dst-ip <ip-addr/mask>] "
696  "[src-port <port/mask>] [dst-port <port/mask>] "
697  "[proto <ip-proto>] "
698  "[gtpc teid <teid>] [gtpu teid <teid>] [vxlan <vni>] "
699  "[session id <session>] [spi <spi>]"
700  "[next-node <node>] [mark <id>] [buffer-advance <len>] "
701  "[redirect-to-queue <queue>] [drop] "
702  "[rss function <name>] [rss types <flow type>]",
703  .function = test_flow,
704 };
705 /* *INDENT-ON* */
706 
707 static u8 *
708 format_flow_match_element (u8 * s, va_list * args)
709 {
710  char *type = va_arg (*args, char *);
711  void *ptr = va_arg (*args, void *);
712 
713  if (strncmp (type, "u8", 2) == 0)
714  return format (s, "%d", *(u8 *) ptr);
715 
716  if (strncmp (type, "u16", 3) == 0)
717  return format (s, "%d", *(u16 *) ptr);
718 
719  if (strncmp (type, "u32", 3) == 0)
720  return format (s, "%d", *(u32 *) ptr);
721 
722  if (strncmp (type, "ethernet_header_t", 13) == 0)
723  {
725  memset (&m, 0, sizeof (m));
726  m.ethernet = *(ethernet_header_t *) ptr;
727  /* convert the ethernet type to net order */
728  m.ethernet.type = clib_host_to_net_u16 (m.ethernet.type);
729  return format (s, "%U", format_ethernet_header, &m);
730  }
731 
732  if (strncmp (type, "ip4_address_t", 13) == 0)
733  return format (s, "%U", format_ip4_address, ptr);
734 
735  if (strncmp (type, "ip4_address_and_mask_t", 13) == 0)
736  return format (s, "%U", format_ip4_address_and_mask, ptr);
737 
738  if (strncmp (type, "ip6_address_t", 13) == 0)
739  return format (s, "%U", format_ip6_address, ptr);
740 
741  if (strncmp (type, "ip6_address_and_mask_t", 13) == 0)
742  return format (s, "%U", format_ip6_address_and_mask, ptr);
743 
744  if (strncmp (type, "ip_prot_and_mask_t", 13) == 0)
745  return format (s, "%U", format_ip_protocol_and_mask, ptr);
746 
747  if (strncmp (type, "ip_port_and_mask_t", 18) == 0)
748  return format (s, "%U", format_ip_port_and_mask, ptr);
749 
750  s = format (s, "unknown type '%s'", type);
751  return s;
752 }
753 
754 #define _fe(a,b) s2 = format (s2, "%s%s %U", s2 ? ", ":"", #b, \
755  format_flow_match_element, #a, &f->b);
756 #define _(a,b,c) \
757 u8 * format_flow_match_##b (u8 * s, va_list * args) \
758 { \
759  vnet_flow_##b##_t *f = __builtin_va_arg (*args, vnet_flow_##b##_t *); \
760  u8 *s2 = 0; \
761 foreach_flow_entry_##b \
762  s = format (s, "%v", s2);; \
763  vec_free (s2); \
764 return s; \
765 }
767 #undef _
768 #undef _fe
769 static u8 *
770 format_flow_match (u8 * s, va_list * args)
771 {
772  vnet_flow_t *f = va_arg (*args, vnet_flow_t *);
773 
774 #define _(a,b,c) \
775  if (f->type == VNET_FLOW_TYPE_##a) \
776  return format (s, "%U", format_flow_match_##b, &f->b);
778 #undef _
779 
780  return s;
781 }
782 
783 static u8 *
784 format_flow (u8 * s, va_list * args)
785 {
787  vnet_flow_t *f = va_arg (*args, vnet_flow_t *);
788  u32 indent = format_get_indent (s);
789  u8 *t = 0;
790 
791  s = format (s, "flow-index %u type %s active %u",
792  f->index, flow_type_strings[f->type],
793  hash_elts (f->private_data)),
794  s = format (s, "\n%Umatch: %U", format_white_space, indent + 2,
795  format_flow_match, f);
796  s = format (s, "\n%Uaction: %U", format_white_space, indent + 2,
798 
799  if (f->actions & VNET_FLOW_ACTION_DROP)
800  t = format (t, "%sdrop", t ? ", " : "");
801 
802  if (f->actions & VNET_FLOW_ACTION_MARK)
803  t = format (t, "%smark %u", t ? ", " : "", f->mark_flow_id);
804 
805  if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_QUEUE)
806  t =
807  format (t, "%sredirect-to-queue %u", t ? ", " : "", f->redirect_queue);
808 
809  if (f->actions & VNET_FLOW_ACTION_REDIRECT_TO_NODE)
810  t = format (t, "%snext-node %U", t ? ", " : "",
812 
813  if (f->actions & VNET_FLOW_ACTION_BUFFER_ADVANCE)
814  t = format (t, "%sbuffer-advance %d", t ? ", " : "", f->buffer_advance);
815 
816  if (f->actions & VNET_FLOW_ACTION_RSS)
817  {
818  t = format (t, "%srss function %U", t ? ", " : "",
820  t = format (t, "%srss types %U", t ? ", " : "",
822  }
823 
824  if (t)
825  {
826  s = format (s, "\n%U%v", format_white_space, indent + 4, t);
827  vec_free (t);
828  }
829 
830  return s;
831 }
832 
833 /*
834  * fd.io coding-style-patch-verification: ON
835  *
836  * Local Variables:
837  * eval: (c-set-style "gnu")
838  * End:
839  */
unformat_function_t unformat_vnet_hw_interface
vnet_rss_function_t rss_fun
Definition: flow.h:245
format_function_t format_ip_protocol
Definition: format.h:45
unformat_function_t unformat_ip_protocol
Definition: format.h:46
u16 vni
Definition: flow_types.api:160
format_function_t format_vlib_node_name
Definition: node_funcs.h:1222
u64 rss_types
Definition: flow.h:242
vnet_flow_type_t type
Definition: flow.h:220
format_function_t format_ip6_address_and_mask
Definition: format.h:93
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define foreach_rss_function
Definition: flow.h:159
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
u8 * format_flow_actions(u8 *s, va_list *args)
Definition: flow_cli.c:115
unsigned long u64
Definition: types.h:89
vl_api_ip_proto_t protocol
Definition: lb_types.api:72
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
static u32 format_get_indent(u8 *s)
Definition: format.h:72
vlib_main_t * vm
Definition: in2out_ed.c:1580
static clib_error_t * test_flow(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: flow_cli.c:331
vnet_flow_t * global_flow_pool
Definition: flow.h:276
u8 * format_flow_error(u8 *s, va_list *args)
Definition: flow_cli.c:100
u16 mask
Definition: flow_types.api:52
struct _vnet_device_class vnet_device_class_t
int vnet_flow_disable(vnet_main_t *vnm, u32 flow_index, u32 hw_if_index)
Definition: flow.c:135
u32 redirect_node_index
Definition: flow.h:232
unsigned char u8
Definition: types.h:56
static clib_error_t * show_flow_entry(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: flow_cli.c:192
ip_protocol_t prot
Definition: flow.h:180
#define fm
#define clib_memcpy(d, s, n)
Definition: string.h:180
u8 *() format_function_t(u8 *s, va_list *args)
Definition: format.h:48
format_function_t format_ip4_address
Definition: format.h:73
static vnet_device_class_t * vnet_get_device_class(vnet_main_t *vnm, u32 dev_class_index)
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:129
static format_function_t format_flow
Definition: flow_cli.c:24
description fragment has unexpected format
Definition: map.api:433
#define hash_foreach(key_var, value_var, h, body)
Definition: hash.h:442
u32 mark_flow_id
Definition: flow.h:229
static u8 * format_flow_match_element(u8 *s, va_list *args)
Definition: flow_cli.c:708
#define clib_error_return(e, args...)
Definition: error.h:99
vnet_flow_main_t flow_main
Definition: flow.c:21
unsigned int u32
Definition: types.h:88
vnet_flow_range_t * ranges
Definition: flow.h:282
unformat_function_t unformat_line_input
Definition: format.h:282
vl_api_fib_path_type_t type
Definition: fib_types.api:123
int vnet_flow_del(vnet_main_t *vnm, u32 flow_index)
Definition: flow.c:67
Definition: cJSON.c:84
u32 redirect_queue
Definition: flow.h:236
static clib_error_t * show_flow_ranges(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: flow_cli.c:261
u8 * format_rss_function(u8 *s, va_list *args)
Definition: flow_cli.c:154
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u32 session_id
Definition: flow_types.api:131
u8 * format_rss_types(u8 *s, va_list *args)
Definition: flow_cli.c:171
vnet_flow_t * vnet_get_flow(u32 flow_index)
Definition: flow.c:57
#define foreach_flow_rss_types
Definition: flow.h:132
u32 index
Definition: flow.h:223
uword unformat_ip_protocol_and_mask(unformat_input_t *input, va_list *args)
Definition: flow_cli.c:66
i32 buffer_advance
Definition: flow.h:239
u32 actions
Definition: flow.h:226
uword * private_data
Definition: flow.h:255
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
u8 * format_ip_port_and_mask(u8 *s, va_list *args)
Definition: flow_cli.c:52
format_function_t format_ip6_address
Definition: format.h:91
vnet_rss_function_t
Definition: flow.h:195
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
u8 * format_flow_enabled_hw(u8 *s, va_list *args)
Definition: flow_cli.c:130
u32 spi
Definition: flow_types.api:140
#define check_rss_types(_str)
u8 * format_ip_protocol_and_mask(u8 *s, va_list *args)
Definition: flow_cli.c:89
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
foreach_flow_type
Definition: flow.h:212
static const char * flow_type_strings[]
Definition: flow_cli.c:185
static uword hash_elts(void *v)
Definition: hash.h:118
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
u8 * format_ethernet_header(u8 *s, va_list *args)
Definition: format.c:178
uword unformat_ip_port_and_mask(unformat_input_t *input, va_list *args)
Definition: flow_cli.c:27
static foreach_flow_type u8 * format_flow_match(u8 *s, va_list *args)
Definition: flow_cli.c:770
int vnet_flow_add(vnet_main_t *vnm, vnet_flow_t *flow, u32 *flow_index)
Definition: flow.c:43
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static clib_error_t * show_flow_interface(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg)
Definition: flow_cli.c:287
vl_api_ip4_address_t hi
Definition: arp.api:37
vl_api_flow_t flow
Definition: flow_types.api:240
uword unformat_ethernet_type_host_byte_order(unformat_input_t *input, va_list *args)
Definition: format.c:249
vl_api_mac_event_action_t action
Definition: l2.api:181
vnet_flow_type_t
Definition: flow.h:186
vl_api_flow_action_t actions
Definition: flow_types.api:224
format_function_t format_ip4_address_and_mask
Definition: format.h:75
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
u32 index
Definition: flow_types.api:221
u16 port
Definition: lb_types.api:73
int vnet_flow_enable(vnet_main_t *vnm, u32 flow_index, u32 hw_if_index)
Definition: flow.c:91
unformat_function_t unformat_vlib_node
Definition: node_funcs.h:1228
ethernet_header_t ethernet
Definition: ethernet.h:121
u32 teid
Definition: flow_types.api:182
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
unformat_function_t unformat_ip6_address_and_mask
Definition: format.h:90
#define vec_foreach(var, vec)
Vector iterator.
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
unformat_function_t unformat_ip4_address_and_mask
Definition: format.h:70