1/*
2 * Copyright (c) 2015 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/*
16 * interface_cli.c: interface CLI
17 *
18 * Copyright (c) 2008 Eliot Dresselhaus
19 *
20 * Permission is hereby granted, free of charge, to any person obtaining
21 * a copy of this software and associated documentation files (the
22 * "Software"), to deal in the Software without restriction, including
23 * without limitation the rights to use, copy, modify, merge, publish,
24 * distribute, sublicense, and/or sell copies of the Software, and to
25 * permit persons to whom the Software is furnished to do so, subject to
26 * the following conditions:
27 *
28 * The above copyright notice and this permission notice shall be
29 * included in all copies or substantial portions of the Software.
30 *
31 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 */
39
40/**
41 * @file
42 * @brief Interface CLI.
43 *
44 * Source code for several CLI interface commands.
45 *
46 */
47
48#include <vnet/vnet.h>
49#include <vnet/ip/ip.h>
50#include <vppinfra/bitmap.h>
51#include <vnet/fib/ip4_fib.h>
52#include <vnet/fib/ip6_fib.h>
53#include <vnet/l2/l2_output.h>
54#include <vnet/l2/l2_input.h>
55#include <vnet/classify/vnet_classify.h>
56
57static int
58compare_interface_names (void *a1, void *a2)
59{
60  u32 *hi1 = a1;
61  u32 *hi2 = a2;
62
63  return vnet_hw_interface_compare (vnet_get_main (), *hi1, *hi2);
64}
65
66static clib_error_t *
67show_or_clear_hw_interfaces (vlib_main_t * vm,
68			     unformat_input_t * input,
69			     vlib_cli_command_t * cmd)
70{
71  clib_error_t *error = 0;
72  vnet_main_t *vnm = vnet_get_main ();
73  vnet_interface_main_t *im = &vnm->interface_main;
74  vnet_hw_interface_t *hi;
75  u32 hw_if_index, *hw_if_indices = 0;
76  int i, verbose = -1, is_show, show_bond = 0;
77
78  is_show = strstr (cmd->path, "show") != 0;
79  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
80    {
81      /* See if user wants to show a specific interface. */
82      if (unformat
83	  (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
84	vec_add1 (hw_if_indices, hw_if_index);
85
86      /* See if user wants to show an interface with a specific hw_if_index. */
87      else if (unformat (input, "%u", &hw_if_index))
88	vec_add1 (hw_if_indices, hw_if_index);
89
90      else if (unformat (input, "verbose"))
91	verbose = 1;		/* this is also the default */
92
93      else if (unformat (input, "detail"))
94	verbose = 2;
95
96      else if (unformat (input, "brief"))
97	verbose = 0;
98
99      else if (unformat (input, "bond"))
100	{
101	  show_bond = 1;
102	  if (verbose < 0)
103	    verbose = 0;	/* default to brief for link bonding */
104	}
105
106      else
107	{
108	  error = clib_error_return (0, "unknown input `%U'",
109				     format_unformat_error, input);
110	  goto done;
111	}
112    }
113
114  /* Gather interfaces. */
115  if (vec_len (hw_if_indices) == 0)
116    pool_foreach (hi, im->hw_interfaces,
117		  vec_add1 (hw_if_indices, hi - im->hw_interfaces));
118
119  if (verbose < 0)
120    verbose = 1;		/* default to verbose (except bond) */
121
122  if (is_show)
123    {
124      /* Sort by name. */
125      vec_sort_with_function (hw_if_indices, compare_interface_names);
126
127      vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, 0, verbose);
128      for (i = 0; i < vec_len (hw_if_indices); i++)
129	{
130	  hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
131	  if (show_bond == 0)	/* show all interfaces */
132	    vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
133			     hi, verbose);
134	  else if ((hi->bond_info) &&
135		   (hi->bond_info != VNET_HW_INTERFACE_BOND_INFO_SLAVE))
136	    {			/* show only bonded interface and all its slave interfaces */
137	      int hw_idx;
138	      vnet_hw_interface_t *shi;
139	      vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
140			       hi, verbose);
141
142              /* *INDENT-OFF* */
143	      clib_bitmap_foreach (hw_idx, hi->bond_info,
144              ({
145                shi = vnet_get_hw_interface(vnm, hw_idx);
146                vlib_cli_output (vm, "%U\n",
147                                 format_vnet_hw_interface, vnm, shi, verbose);
148              }));
149              /* *INDENT-ON* */
150	    }
151	}
152    }
153  else
154    {
155      for (i = 0; i < vec_len (hw_if_indices); i++)
156	{
157	  vnet_device_class_t *dc;
158
159	  hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
160	  dc = vec_elt_at_index (im->device_classes, hi->dev_class_index);
161
162	  if (dc->clear_counters)
163	    dc->clear_counters (hi->dev_instance);
164	}
165    }
166
167done:
168  vec_free (hw_if_indices);
169  return error;
170}
171
172/*?
173 * Display more detailed information about all or a list of given interfaces.
174 * The verboseness of the output can be controlled by the following optional
175 * parameters:
176 * - brief: Only show name, index and state (default for bonded interfaces).
177 * - verbose: Also display additional attributes (default for all other interfaces).
178 * - detail: Also display all remaining attributes and extended statistics.
179 *
180 * To limit the output of the command to bonded interfaces and their slave
181 * interfaces, use the '<em>bond</em>' optional parameter.
182 *
183 * @cliexpar
184 * Example of how to display default data for all interfaces:
185 * @cliexstart{show hardware-interfaces}
186 *               Name                Idx   Link  Hardware
187 * GigabitEthernet7/0/0               1     up   GigabitEthernet7/0/0
188 *   Ethernet address ec:f4:bb:c0:bc:fc
189 *   Intel e1000
190 *     carrier up full duplex speed 1000 mtu 9216
191 *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
192 *     cpu socket 0
193 * GigabitEthernet7/0/1               2     up   GigabitEthernet7/0/1
194 *   Ethernet address ec:f4:bb:c0:bc:fd
195 *   Intel e1000
196 *     carrier up full duplex speed 1000 mtu 9216
197 *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
198 *     cpu socket 0
199 * VirtualEthernet0/0/0               3     up   VirtualEthernet0/0/0
200 *   Ethernet address 02:fe:a5:a9:8b:8e
201 * VirtualEthernet0/0/1               4     up   VirtualEthernet0/0/1
202 *   Ethernet address 02:fe:c0:4e:3b:b0
203 * VirtualEthernet0/0/2               5     up   VirtualEthernet0/0/2
204 *   Ethernet address 02:fe:1f:73:92:81
205 * VirtualEthernet0/0/3               6     up   VirtualEthernet0/0/3
206 *   Ethernet address 02:fe:f2:25:c4:68
207 * local0                             0    down  local0
208 *   local
209 * @cliexend
210 * Example of how to display '<em>verbose</em>' data for an interface by name and
211 * software index (where 2 is the software index):
212 * @cliexstart{show hardware-interfaces GigabitEthernet7/0/0 2 verbose}
213 *               Name                Idx   Link  Hardware
214 * GigabitEthernet7/0/0               1     up   GigabitEthernet7/0/0
215 *   Ethernet address ec:f4:bb:c0:bc:fc
216 *   Intel e1000
217 *     carrier up full duplex speed 1000 mtu 9216
218 *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
219 *     cpu socket 0
220 * GigabitEthernet7/0/1               2    down  GigabitEthernet7/0/1
221 *   Ethernet address ec:f4:bb:c0:bc:fd
222 *   Intel e1000
223 *     carrier up full duplex speed 1000 mtu 9216
224 *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
225 *     cpu socket 0
226 * @cliexend
227 ?*/
228/* *INDENT-OFF* */
229VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = {
230  .path = "show hardware-interfaces",
231  .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] "
232    "[<interface> [<interface> [..]]] [<sw_idx> [<sw_idx> [..]]]",
233  .function = show_or_clear_hw_interfaces,
234};
235/* *INDENT-ON* */
236
237
238/*?
239 * Clear the extended statistics for all or a list of given interfaces
240 * (statistics associated with the '<em>show hardware-interfaces</em>' command).
241 *
242 * @cliexpar
243 * Example of how to clear the extended statistics for all interfaces:
244 * @cliexcmd{clear hardware-interfaces}
245 * Example of how to clear the extended statistics for an interface by
246 * name and software index (where 2 is the software index):
247 * @cliexcmd{clear hardware-interfaces GigabitEthernet7/0/0 2}
248 ?*/
249/* *INDENT-OFF* */
250VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = {
251  .path = "clear hardware-interfaces",
252  .short_help = "clear hardware-interfaces "
253    "[<interface> [<interface> [..]]] [<sw_idx> [<sw_idx> [..]]]",
254  .function = show_or_clear_hw_interfaces,
255};
256/* *INDENT-ON* */
257
258static int
259sw_interface_name_compare (void *a1, void *a2)
260{
261  vnet_sw_interface_t *si1 = a1;
262  vnet_sw_interface_t *si2 = a2;
263
264  return vnet_sw_interface_compare (vnet_get_main (),
265				    si1->sw_if_index, si2->sw_if_index);
266}
267
268static clib_error_t *
269show_sw_interfaces (vlib_main_t * vm,
270		    unformat_input_t * input, vlib_cli_command_t * cmd)
271{
272  clib_error_t *error = 0;
273  vnet_main_t *vnm = vnet_get_main ();
274  unformat_input_t _linput, *linput = &_linput;
275  vnet_interface_main_t *im = &vnm->interface_main;
276  vnet_sw_interface_t *si, *sorted_sis = 0;
277  u32 sw_if_index = ~(u32) 0;
278  u8 show_addresses = 0;
279  u8 show_features = 0;
280  u8 show_tag = 0;
281  u8 show_vtr = 0;
282  int verbose = 0;
283
284  /*
285   * Get a line of input. Won't work if the user typed
286   * "show interface" and nothing more.
287   */
288  if (unformat_user (input, unformat_line_input, linput))
289    {
290      while (unformat_check_input (linput) != UNFORMAT_END_OF_INPUT)
291	{
292	  /* See if user wants to show specific interface */
293	  if (unformat
294	      (linput, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
295	    {
296	      si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
297	      vec_add1 (sorted_sis, si[0]);
298	    }
299	  else if (unformat (linput, "address") || unformat (linput, "addr"))
300	    show_addresses = 1;
301	  else if (unformat (linput, "features") || unformat (linput, "feat"))
302	    show_features = 1;
303	  else if (unformat (linput, "tag"))
304	    show_tag = 1;
305	  else if (unformat (linput, "vtr"))
306	    show_vtr = 1;
307	  else if (unformat (linput, "verbose"))
308	    verbose = 1;
309	  else
310	    {
311	      vec_free (sorted_sis);
312	      error = clib_error_return (0, "unknown input `%U'",
313					 format_unformat_error, linput);
314	      goto done;
315	    }
316	}
317      unformat_free (linput);
318    }
319  if (show_features || show_tag || show_vtr)
320    {
321      if (sw_if_index == ~(u32) 0)
322	{
323	  vec_free (sorted_sis);
324	  return clib_error_return (0, "Interface not specified...");
325	}
326    }
327
328  if (show_features)
329    {
330      vnet_interface_features_show (vm, sw_if_index, verbose);
331
332      l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
333      u32 fb = l2_input->feature_bitmap;
334      /* intf input features are masked by bridge domain */
335      if (l2_input->bridge)
336	fb &= l2input_bd_config (l2_input->bd_index)->feature_bitmap;
337      vlib_cli_output (vm, "\nl2-input:\n%U", format_l2_input_features, fb,
338		       1);
339
340      l2_output_config_t *l2_output = l2output_intf_config (sw_if_index);
341      vlib_cli_output (vm, "\nl2-output:");
342      if (l2_output->out_vtr_flag)
343	vlib_cli_output (vm, "%10s (%s)", "VTR", "--internal--");
344      vlib_cli_output (vm, "%U", format_l2_output_features,
345		       l2_output->feature_bitmap, 1);
346      vec_free (sorted_sis);
347      return 0;
348    }
349  if (show_tag)
350    {
351      u8 *tag;
352      tag = vnet_get_sw_interface_tag (vnm, sw_if_index);
353      vlib_cli_output (vm, "%U: %s",
354		       format_vnet_sw_if_index_name, vnm, sw_if_index,
355		       tag ? (char *) tag : "(none)");
356      vec_free (sorted_sis);
357      return 0;
358    }
359
360  /*
361   * Show vlan tag rewrite data for one interface.
362   */
363  if (show_vtr)
364    {
365      u32 vtr_op = L2_VTR_DISABLED;
366      u32 push_dot1q = 0, tag1 = 0, tag2 = 0;
367
368      if (l2vtr_get (vm, vnm, sw_if_index,
369		     &vtr_op, &push_dot1q, &tag1, &tag2) != 0)
370	{
371	  vlib_cli_output (vm, "%U: Problem getting vlan tag-rewrite data",
372			   format_vnet_sw_if_index_name, vnm, sw_if_index);
373	  return 0;
374	}
375      vlib_cli_output (vm, "%U:  VTR %0U",
376		       format_vnet_sw_if_index_name, vnm, sw_if_index,
377		       format_vtr, vtr_op, push_dot1q, tag1, tag2);
378      return 0;
379    }
380
381  if (!show_addresses)
382    vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0);
383
384  if (vec_len (sorted_sis) == 0)	/* Get all interfaces */
385    {
386      /* Gather interfaces. */
387      sorted_sis =
388	vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
389      _vec_len (sorted_sis) = 0;
390      /* *INDENT-OFF* */
391      pool_foreach (si, im->sw_interfaces,
392      ({
393        int visible = vnet_swif_is_api_visible (si);
394        if (visible)
395          vec_add1 (sorted_sis, si[0]);}
396        ));
397      /* *INDENT-ON* */
398      /* Sort by name. */
399      vec_sort_with_function (sorted_sis, sw_interface_name_compare);
400    }
401
402  if (show_addresses)
403    {
404      vec_foreach (si, sorted_sis)
405      {
406	ip4_main_t *im4 = &ip4_main;
407	ip6_main_t *im6 = &ip6_main;
408	ip_lookup_main_t *lm4 = &im4->lookup_main;
409	ip_lookup_main_t *lm6 = &im6->lookup_main;
410	ip_interface_address_t *ia = 0;
411	u32 fib_index4 = 0, fib_index6 = 0;
412
413	if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index)
414	  fib_index4 = vec_elt (im4->fib_index_by_sw_if_index,
415				si->sw_if_index);
416
417	if (vec_len (im6->fib_index_by_sw_if_index) > si->sw_if_index)
418	  fib_index6 = vec_elt (im6->fib_index_by_sw_if_index,
419				si->sw_if_index);
420
421	ip4_fib_t *fib4 = ip4_fib_get (fib_index4);
422	ip6_fib_t *fib6 = ip6_fib_get (fib_index6);
423
424	if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
425	  vlib_cli_output
426	    (vm, "%U (%s): \n  unnumbered, use %U",
427	     format_vnet_sw_if_index_name, vnm, si->sw_if_index,
428	     (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn",
429	     format_vnet_sw_if_index_name, vnm, si->unnumbered_sw_if_index);
430	else
431	  vlib_cli_output
432	    (vm, "%U (%s):",
433	     format_vnet_sw_if_index_name, vnm, si->sw_if_index,
434	     (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn");
435
436	/* Display any L2 info */
437	l2_input_config_t *l2_input = l2input_intf_config (si->sw_if_index);
438	if (l2_input->bridge)
439	  {
440	    bd_main_t *bdm = &bd_main;
441	    u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id;
442	    vlib_cli_output (vm, "  L2 bridge bd-id %d idx %d shg %d %s",
443			     bd_id, bd_find_index (bdm, bd_id), l2_input->shg,
444			     l2_input->bvi ? "bvi" : " ");
445	  }
446	else if (l2_input->xconnect)
447	  vlib_cli_output (vm, "  L2 xconnect %U",
448			   format_vnet_sw_if_index_name, vnm,
449			   l2_input->output_sw_if_index);
450
451	/* *INDENT-OFF* */
452	/* Display any IP4 addressing info */
453	foreach_ip_interface_address (lm4, ia, si->sw_if_index,
454				      1 /* honor unnumbered */,
455	({
456	  ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
457	  if (fib4->table_id)
458	    vlib_cli_output (vm, "  L3 %U/%d ip4 table-id %d fib-idx %d",
459			     format_ip4_address, r4, ia->address_length,
460			     fib4->table_id,
461			     ip4_fib_index_from_table_id (fib4->table_id));
462	  else
463	    vlib_cli_output (vm, "  L3 %U/%d",
464			     format_ip4_address, r4, ia->address_length);
465        }));
466	/* *INDENT-ON* */
467
468	/* *INDENT-OFF* */
469	/* Display any IP6 addressing info */
470	foreach_ip_interface_address (lm6, ia, si->sw_if_index,
471				      1 /* honor unnumbered */,
472        ({
473	  ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
474	  if (fib6->table_id)
475	    vlib_cli_output (vm, "  L3 %U/%d ip6 table-id %d fib-idx %d",
476			     format_ip6_address, r6, ia->address_length,
477			     fib6->table_id,
478			     ip6_fib_index_from_table_id (fib6->table_id));
479	  else
480	    vlib_cli_output (vm, "  L3 %U/%d",
481			     format_ip6_address, r6, ia->address_length);
482        }));
483	/* *INDENT-ON* */
484      }
485    }
486  else
487    {
488      vec_foreach (si, sorted_sis)
489      {
490	vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, si);
491      }
492    }
493
494done:
495  vec_free (sorted_sis);
496  return error;
497}
498
499/* *INDENT-OFF* */
500VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = {
501  .path = "show interface",
502  .short_help = "show interface [address|addr|features|feat|vtr] [<interface> [<interface> [..]]] [verbose]",
503  .function = show_sw_interfaces,
504  .is_mp_safe = 1,
505};
506/* *INDENT-ON* */
507
508/* Root of all interface commands. */
509/* *INDENT-OFF* */
510VLIB_CLI_COMMAND (vnet_cli_interface_command, static) = {
511  .path = "interface",
512  .short_help = "Interface commands",
513};
514/* *INDENT-ON* */
515
516/* *INDENT-OFF* */
517VLIB_CLI_COMMAND (vnet_cli_set_interface_command, static) = {
518  .path = "set interface",
519  .short_help = "Interface commands",
520};
521/* *INDENT-ON* */
522
523static clib_error_t *
524clear_interface_counters (vlib_main_t * vm,
525			  unformat_input_t * input, vlib_cli_command_t * cmd)
526{
527  vnet_main_t *vnm = vnet_get_main ();
528  vnet_interface_main_t *im = &vnm->interface_main;
529  vlib_simple_counter_main_t *sm;
530  vlib_combined_counter_main_t *cm;
531  int j, n_counters;
532
533  n_counters = vec_len (im->combined_sw_if_counters);
534
535  for (j = 0; j < n_counters; j++)
536    {
537      im = &vnm->interface_main;
538      cm = im->combined_sw_if_counters + j;
539      vlib_clear_combined_counters (cm);
540    }
541
542  n_counters = vec_len (im->sw_if_counters);
543
544  for (j = 0; j < n_counters; j++)
545    {
546      im = &vnm->interface_main;
547      sm = im->sw_if_counters + j;
548      vlib_clear_simple_counters (sm);
549    }
550
551  return 0;
552}
553
554/*?
555 * Clear the statistics for all interfaces (statistics associated with the
556 * '<em>show interface</em>' command).
557 *
558 * @cliexpar
559 * Example of how to clear the statistics for all interfaces:
560 * @cliexcmd{clear interfaces}
561 ?*/
562/* *INDENT-OFF* */
563VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
564  .path = "clear interfaces",
565  .short_help = "clear interfaces",
566  .function = clear_interface_counters,
567};
568/* *INDENT-ON* */
569
570/**
571 * Parse subinterface names.
572 *
573 * The following subinterface syntax is supported. The first two are for
574 * backwards compatability:
575 *
576 * <intf-name> <id>
577 *     - a subinterface with the name <intf-name>.<id>. The subinterface
578 *       is a single dot1q vlan with vlan id <id> and exact-match semantics.
579 *
580 * <intf-name> <min_id>-<max_id>
581 *     - a set of the above subinterfaces, repeating for each id
582 *       in the range <min_id> to <max_id>
583 *
584 * In the following, exact-match semantics (i.e. the number of vlan tags on the
585 * packet must match the number of tags in the configuration) are used only if
586 * the keyword exact-match is present. Non-exact match is the default.
587 *
588 * <intf-name> <id> dot1q <outer_id> [exact-match]
589 *     - a subinterface with the name <intf-name>.<id>. The subinterface
590 *       is a single dot1q vlan with vlan id <outer_id>.
591 *
592 * <intf-name> <id> dot1q any [exact-match]
593 *     - a subinterface with the name <intf-name>.<id>. The subinterface
594 *       is a single dot1q vlan with any vlan id.
595 *
596 * <intf-name> <id> dot1q <outer_id> inner-dot1q <inner_id> [exact-match]
597 *     - a subinterface with the name <intf-name>.<id>. The subinterface
598 *       is a double dot1q vlan with outer vlan id <outer_id> and inner vlan id
599 *       <inner_id>.
600 *
601 * <intf-name> <id> dot1q <outer_id> inner-dot1q any [exact-match]
602 *     - a subinterface with the name <intf-name>.<id>. The subinterface
603 *       is a double dot1q vlan with outer vlan id <id> and any inner vlan id.
604 *
605 * <intf-name> <id> dot1q any inner-dot1q any [exact-match]
606 *
607 *     - a subinterface with the name <intf-name>.<id>. The subinterface
608 *       is a double dot1q vlan with any outer vlan id and any inner vlan id.
609 *
610 * For each of the above CLI, there is a duplicate that uses the keyword
611 * "dot1ad" in place of the first "dot1q". These interfaces use ethertype
612 * 0x88ad in place of 0x8100 for the outer ethertype. Note that for double-
613 * tagged packets the inner ethertype is always 0x8100. Also note that
614 * the dot1q and dot1ad naming spaces are independent, so it is legal to
615 * have both "Gig3/0/0.1 dot1q 100" and "Gig3/0/0.2 dot1ad 100". For example:
616 *
617 * <intf-name> <id> dot1ad <outer_id> inner-dot1q <inner_id> [exact-match]
618 *     - a subinterface with the name <intf-name>.<id>. The subinterface
619 *       is a double dot1ad vlan with outer vlan id <outer_id> and inner vlan
620 *       id <inner_id>.
621 *
622 * <intf-name> <id> untagged
623 *     - a subinterface with the name <intf-name>.<id>. The subinterface
624 *       has no vlan tags. Only one can be specified per interface.
625 *
626 * <intf-name> <id> default
627 *     - a subinterface with the name <intf-name>.<id>. This is associated
628 *       with a packet that did not match any other configured subinterface
629 *       on this interface. Only one can be specified per interface.
630 */
631
632static clib_error_t *
633parse_vlan_sub_interfaces (unformat_input_t * input,
634			   vnet_sw_interface_t * template)
635{
636  clib_error_t *error = 0;
637  u32 inner_vlan, outer_vlan;
638
639  if (unformat (input, "any inner-dot1q any"))
640    {
641      template->sub.eth.flags.two_tags = 1;
642      template->sub.eth.flags.outer_vlan_id_any = 1;
643      template->sub.eth.flags.inner_vlan_id_any = 1;
644    }
645  else if (unformat (input, "any"))
646    {
647      template->sub.eth.flags.one_tag = 1;
648      template->sub.eth.flags.outer_vlan_id_any = 1;
649    }
650  else if (unformat (input, "%d inner-dot1q any", &outer_vlan))
651    {
652      template->sub.eth.flags.two_tags = 1;
653      template->sub.eth.flags.inner_vlan_id_any = 1;
654      template->sub.eth.outer_vlan_id = outer_vlan;
655    }
656  else if (unformat (input, "%d inner-dot1q %d", &outer_vlan, &inner_vlan))
657    {
658      template->sub.eth.flags.two_tags = 1;
659      template->sub.eth.outer_vlan_id = outer_vlan;
660      template->sub.eth.inner_vlan_id = inner_vlan;
661    }
662  else if (unformat (input, "%d", &outer_vlan))
663    {
664      template->sub.eth.flags.one_tag = 1;
665      template->sub.eth.outer_vlan_id = outer_vlan;
666    }
667  else
668    {
669      error = clib_error_return (0, "expected dot1q config, got `%U'",
670				 format_unformat_error, input);
671      goto done;
672    }
673
674  if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
675    {
676      if (unformat (input, "exact-match"))
677	{
678	  template->sub.eth.flags.exact_match = 1;
679	}
680    }
681
682done:
683  return error;
684}
685
686static clib_error_t *
687create_sub_interfaces (vlib_main_t * vm,
688		       unformat_input_t * input, vlib_cli_command_t * cmd)
689{
690  vnet_main_t *vnm = vnet_get_main ();
691  clib_error_t *error = 0;
692  u32 hw_if_index, sw_if_index;
693  vnet_hw_interface_t *hi;
694  u32 id, id_min, id_max;
695  vnet_sw_interface_t template;
696
697  hw_if_index = ~0;
698  if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
699    {
700      error = clib_error_return (0, "unknown interface `%U'",
701				 format_unformat_error, input);
702      goto done;
703    }
704
705  clib_memset (&template, 0, sizeof (template));
706  template.sub.eth.raw_flags = 0;
707
708  if (unformat (input, "%d default", &id_min))
709    {
710      id_max = id_min;
711      template.sub.eth.flags.default_sub = 1;
712    }
713  else if (unformat (input, "%d untagged", &id_min))
714    {
715      id_max = id_min;
716      template.sub.eth.flags.no_tags = 1;
717      template.sub.eth.flags.exact_match = 1;
718    }
719  else if (unformat (input, "%d dot1q", &id_min))
720    {
721      /* parse dot1q config */
722      id_max = id_min;
723      error = parse_vlan_sub_interfaces (input, &template);
724      if (error)
725	goto done;
726    }
727  else if (unformat (input, "%d dot1ad", &id_min))
728    {
729      /* parse dot1ad config */
730      id_max = id_min;
731      template.sub.eth.flags.dot1ad = 1;
732      error = parse_vlan_sub_interfaces (input, &template);
733      if (error)
734	goto done;
735    }
736  else if (unformat (input, "%d-%d", &id_min, &id_max))
737    {
738      template.sub.eth.flags.one_tag = 1;
739      template.sub.eth.flags.exact_match = 1;
740      if (id_min > id_max)
741	goto id_error;
742    }
743  else if (unformat (input, "%d", &id_min))
744    {
745      id_max = id_min;
746      template.sub.eth.flags.one_tag = 1;
747      template.sub.eth.outer_vlan_id = id_min;
748      template.sub.eth.flags.exact_match = 1;
749    }
750  else
751    {
752    id_error:
753      error = clib_error_return (0, "expected ID or ID MIN-MAX, got `%U'",
754				 format_unformat_error, input);
755      goto done;
756    }
757
758  hi = vnet_get_hw_interface (vnm, hw_if_index);
759
760  if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
761    {
762      error =
763	clib_error_return (0,
764			   "not allowed as %v belong to a BondEthernet interface",
765			   hi->name);
766      goto done;
767    }
768
769  for (id = id_min; id <= id_max; id++)
770    {
771      uword *p;
772      vnet_interface_main_t *im = &vnm->interface_main;
773      u64 sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
774      u64 *kp;
775
776      p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
777      if (p)
778	{
779	  if (CLIB_DEBUG > 0)
780	    clib_warning ("sup sw_if_index %d, sub id %d already exists\n",
781			  hi->sw_if_index, id);
782	  continue;
783	}
784
785      template.type = VNET_SW_INTERFACE_TYPE_SUB;
786      template.flood_class = VNET_FLOOD_CLASS_NORMAL;
787      template.sup_sw_if_index = hi->sw_if_index;
788      template.sub.id = id;
789      if (id_min < id_max)
790	template.sub.eth.outer_vlan_id = id;
791
792      error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
793      if (error)
794	goto done;
795
796      kp = clib_mem_alloc (sizeof (*kp));
797      *kp = sup_and_sub_key;
798
799      hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index);
800      hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
801      vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
802		       vnet_get_main (), sw_if_index);
803    }
804
805done:
806  return error;
807}
808
809/*?
810 * This command is used to add VLAN IDs to interfaces, also known as subinterfaces.
811 * The primary input to this command is the '<em>interface</em>' and '<em>subId</em>'
812 * (subinterface Id) parameters. If no additional VLAN ID is provide, the VLAN ID is
813 * assumed to be the '<em>subId</em>'. The VLAN ID and '<em>subId</em>' can be different,
814 * but this is not recommended.
815 *
816 * This command has several variations:
817 * - <b>create sub-interfaces <interface> <subId></b> - Create a subinterface to
818 * process packets with a given 802.1q VLAN ID (same value as the '<em>subId</em>').
819 *
820 * - <b>create sub-interfaces <interface> <subId> default</b> - Adding the
821 * '<em>default</em>' parameter indicates that packets with VLAN IDs that do not
822 * match any other subinterfaces should be sent to this subinterface.
823 *
824 * - <b>create sub-interfaces <interface> <subId> untagged</b> - Adding the
825 * '<em>untagged</em>' parameter indicates that packets no VLAN IDs should be sent
826 * to this subinterface.
827 *
828 * - <b>create sub-interfaces <interface> <subId>-<subId></b> - Create a range of
829 * subinterfaces to handle a range of VLAN IDs.
830 *
831 * - <b>create sub-interfaces <interface> <subId> dot1q|dot1ad <vlanId>|any [exact-match]</b> -
832 * Use this command to specify the outer VLAN ID, to either be explicit or to make the
833 * VLAN ID different from the '<em>subId</em>'.
834 *
835 * - <b>create sub-interfaces <interface> <subId> dot1q|dot1ad <vlanId>|any inner-dot1q
836 * <vlanId>|any [exact-match]</b> - Use this command to specify the outer VLAN ID and
837 * the inner VLAN ID.
838 *
839 * When '<em>dot1q</em>' or '<em>dot1ad</em>' is explicitly entered, subinterfaces
840 * can be configured as either exact-match or non-exact match. Non-exact match is the CLI
841 * default. If '<em>exact-match</em>' is specified, packets must have the same number of
842 * VLAN tags as the configuration. For non-exact-match, packets must at least that number
843 * of tags. L3 (routed) interfaces must be configured as exact-match. L2 interfaces are
844 * typically configured as non-exact-match. If '<em>dot1q</em>' or '<em>dot1ad</em>' is NOT
845 * entered, then the default behavior is exact-match.
846 *
847 * Use the '<em>show interface</em>' command to display all subinterfaces.
848 *
849 * @cliexpar
850 * @parblock
851 * Example of how to create a VLAN subinterface 11 to process packets on 802.1q VLAN ID 11:
852 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11}
853 *
854 * The previous example is shorthand and is equivalent to:
855 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 11 exact-match}
856 *
857 *
858 * Example of how to create a subinterface number that is different from the VLAN ID:
859 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100}
860 *
861 *
862 * Examples of how to create q-in-q and q-in-any subinterfaces:
863 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200}
864 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any}
865 *
866 * Examples of how to create dot1ad interfaces:
867 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1ad 11}
868 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1ad 100 inner-dot1q 200}
869 *
870 *
871 * Examples of '<em>exact-match</em>' versus non-exact match. A packet with
872 * outer VLAN 100 and inner VLAN 200 would match this interface, because the default
873 * is non-exact match:
874 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100}
875 *
876 * However, the same packet would NOT match this interface because '<em>exact-match</em>'
877 * is specified and only one VLAN is configured, but packet contains two VLANs:
878 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100 exact-match}
879 *
880 *
881 * Example of how to created a subinterface to process untagged packets:
882 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 untagged}
883 *
884 * Example of how to created a subinterface to process any packet with a VLAN ID that
885 * does not match any other subinterface:
886 * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 7 default}
887 *
888 * When subinterfaces are created, they are in the down state. Example of how to
889 * enable a newly created subinterface:
890 * @cliexcmd{set interface GigabitEthernet2/0/0.7 up}
891 * @endparblock
892 ?*/
893/* *INDENT-OFF* */
894VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = {
895  .path = "create sub-interfaces",
896  .short_help = "create sub-interfaces <interface> "
897    "{<subId> [default|untagged]} | "
898    "{<subId>-<subId>} | "
899    "{<subId> dot1q|dot1ad <vlanId>|any [inner-dot1q <vlanId>|any] [exact-match]}",
900  .function = create_sub_interfaces,
901};
902/* *INDENT-ON* */
903
904static clib_error_t *
905set_state (vlib_main_t * vm,
906	   unformat_input_t * input, vlib_cli_command_t * cmd)
907{
908  vnet_main_t *vnm = vnet_get_main ();
909  clib_error_t *error;
910  u32 sw_if_index, flags;
911
912  sw_if_index = ~0;
913  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
914    {
915      error = clib_error_return (0, "unknown interface `%U'",
916				 format_unformat_error, input);
917      goto done;
918    }
919
920  if (!unformat (input, "%U", unformat_vnet_sw_interface_flags, &flags))
921    {
922      error = clib_error_return (0, "unknown flags `%U'",
923				 format_unformat_error, input);
924      goto done;
925    }
926
927  error = vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
928  if (error)
929    goto done;
930
931done:
932  return error;
933}
934
935
936/*?
937 * This command is used to change the admin state (up/down) of an interface.
938 *
939 * If an interface is down, the optional '<em>punt</em>' flag can also be set.
940 * The '<em>punt</em>' flag implies the interface is disabled for forwarding
941 * but punt all traffic to slow-path. Use the '<em>enable</em>' flag to clear
942 * '<em>punt</em>' flag (interface is still down).
943 *
944 * @cliexpar
945 * Example of how to configure the admin state of an interface to '<em>up</em?':
946 * @cliexcmd{set interface state GigabitEthernet2/0/0 up}
947 * Example of how to configure the admin state of an interface to '<em>down</em?':
948 * @cliexcmd{set interface state GigabitEthernet2/0/0 down}
949 ?*/
950/* *INDENT-OFF* */
951VLIB_CLI_COMMAND (set_state_command, static) = {
952  .path = "set interface state",
953  .short_help = "set interface state <interface> [up|down|punt|enable]",
954  .function = set_state,
955};
956/* *INDENT-ON* */
957
958static clib_error_t *
959set_unnumbered (vlib_main_t * vm,
960		unformat_input_t * input, vlib_cli_command_t * cmd)
961{
962  vnet_main_t *vnm = vnet_get_main ();
963  u32 unnumbered_sw_if_index = ~0;
964  u32 inherit_from_sw_if_index = ~0;
965  int enable = 1;
966
967  if (unformat (input, "%U use %U",
968		unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
969		unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index))
970    enable = 1;
971  else if (unformat (input, "del %U",
972		     unformat_vnet_sw_interface, vnm,
973		     &unnumbered_sw_if_index))
974    enable = 0;
975  else
976    return clib_error_return (0, "parse error '%U'",
977			      format_unformat_error, input);
978
979  if (~0 == unnumbered_sw_if_index)
980    return clib_error_return (0, "Specify the unnumbered interface");
981  if (enable && ~0 == inherit_from_sw_if_index)
982    return clib_error_return (0, "When enabling unnumbered specify the"
983			      " IP enabled interface that it uses");
984
985  vnet_sw_interface_update_unnumbered (unnumbered_sw_if_index,
986				       inherit_from_sw_if_index, enable);
987
988  return (NULL);
989}
990
991/* *INDENT-OFF* */
992VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
993  .path = "set interface unnumbered",
994  .short_help = "set interface unnumbered [<interface> use <interface> | del <interface>]",
995  .function = set_unnumbered,
996};
997/* *INDENT-ON* */
998
999
1000
1001static clib_error_t *
1002set_hw_class (vlib_main_t * vm,
1003	      unformat_input_t * input, vlib_cli_command_t * cmd)
1004{
1005  vnet_main_t *vnm = vnet_get_main ();
1006  vnet_interface_main_t *im = &vnm->interface_main;
1007  clib_error_t *error;
1008  u32 hw_if_index, hw_class_index;
1009
1010  hw_if_index = ~0;
1011  if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
1012    {
1013      error = clib_error_return (0, "unknown hardware interface `%U'",
1014				 format_unformat_error, input);
1015      goto done;
1016    }
1017
1018  if (!unformat_user (input, unformat_hash_string,
1019		      im->hw_interface_class_by_name, &hw_class_index))
1020    {
1021      error = clib_error_return (0, "unknown hardware class `%U'",
1022				 format_unformat_error, input);
1023      goto done;
1024    }
1025
1026  error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index);
1027  if (error)
1028    goto done;
1029
1030done:
1031  return error;
1032}
1033
1034/* *INDENT-OFF* */
1035VLIB_CLI_COMMAND (set_hw_class_command, static) = {
1036  .path = "set interface hw-class",
1037  .short_help = "Set interface hardware class",
1038  .function = set_hw_class,
1039};
1040/* *INDENT-ON* */
1041
1042static clib_error_t *
1043vnet_interface_cli_init (vlib_main_t * vm)
1044{
1045  return 0;
1046}
1047
1048VLIB_INIT_FUNCTION (vnet_interface_cli_init);
1049
1050static clib_error_t *
1051renumber_interface_command_fn (vlib_main_t * vm,
1052			       unformat_input_t * input,
1053			       vlib_cli_command_t * cmd)
1054{
1055  u32 hw_if_index;
1056  u32 new_dev_instance;
1057  vnet_main_t *vnm = vnet_get_main ();
1058  int rv;
1059
1060  if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
1061    return clib_error_return (0, "unknown hardware interface `%U'",
1062			      format_unformat_error, input);
1063
1064  if (!unformat (input, "%d", &new_dev_instance))
1065    return clib_error_return (0, "new dev instance missing");
1066
1067  rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance);
1068
1069  switch (rv)
1070    {
1071    case 0:
1072      break;
1073
1074    default:
1075      return clib_error_return (0, "vnet_interface_name_renumber returned %d",
1076				rv);
1077
1078    }
1079
1080  return 0;
1081}
1082
1083
1084/* *INDENT-OFF* */
1085VLIB_CLI_COMMAND (renumber_interface_command, static) = {
1086  .path = "renumber interface",
1087  .short_help = "renumber interface <interface> <new-dev-instance>",
1088  .function = renumber_interface_command_fn,
1089};
1090/* *INDENT-ON* */
1091
1092static clib_error_t *
1093promiscuous_cmd (vlib_main_t * vm,
1094		 unformat_input_t * input, vlib_cli_command_t * cmd)
1095{
1096  vnet_main_t *vnm = vnet_get_main ();
1097  u32 hw_if_index;
1098  u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL;
1099  ethernet_main_t *em = &ethernet_main;
1100  ethernet_interface_t *eif;
1101
1102  if (unformat (input, "on %U",
1103		unformat_vnet_hw_interface, vnm, &hw_if_index))
1104    ;
1105  else if (unformat (input, "off %U",
1106		     unformat_ethernet_interface, vnm, &hw_if_index))
1107    flags = 0;
1108  else
1109    return clib_error_return (0, "unknown input `%U'",
1110			      format_unformat_error, input);
1111
1112  eif = ethernet_get_interface (em, hw_if_index);
1113  if (!eif)
1114    return clib_error_return (0, "not supported");
1115
1116  ethernet_set_flags (vnm, hw_if_index, flags);
1117  return 0;
1118}
1119
1120/* *INDENT-OFF* */
1121VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = {
1122  .path = "set interface promiscuous",
1123  .short_help = "set interface promiscuous [on|off] <interface>",
1124  .function = promiscuous_cmd,
1125};
1126/* *INDENT-ON* */
1127
1128static clib_error_t *
1129mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1130{
1131  vnet_main_t *vnm = vnet_get_main ();
1132  u32 hw_if_index, sw_if_index, mtu;
1133  ethernet_main_t *em = &ethernet_main;
1134  u32 mtus[VNET_N_MTU] = { 0, 0, 0, 0 };
1135
1136  if (unformat (input, "%d %U", &mtu,
1137		unformat_vnet_hw_interface, vnm, &hw_if_index))
1138    {
1139      /*
1140       * Change physical MTU on interface. Only supported for Ethernet
1141       * interfaces
1142       */
1143      vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1144      ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index);
1145
1146      if (!eif)
1147	return clib_error_return (0, "not supported");
1148
1149      if (mtu < hi->min_supported_packet_bytes)
1150	return clib_error_return (0, "Invalid mtu (%d): "
1151				  "must be >= min pkt bytes (%d)", mtu,
1152				  hi->min_supported_packet_bytes);
1153
1154      if (mtu > hi->max_supported_packet_bytes)
1155	return clib_error_return (0, "Invalid mtu (%d): must be <= (%d)", mtu,
1156				  hi->max_supported_packet_bytes);
1157
1158      vnet_hw_interface_set_mtu (vnm, hw_if_index, mtu);
1159      goto done;
1160    }
1161  else if (unformat (input, "packet %d %U", &mtu,
1162		     unformat_vnet_sw_interface, vnm, &sw_if_index))
1163    /* Set default packet MTU (including L3 header */
1164    mtus[VNET_MTU_L3] = mtu;
1165  else if (unformat (input, "ip4 %d %U", &mtu,
1166		     unformat_vnet_sw_interface, vnm, &sw_if_index))
1167    mtus[VNET_MTU_IP4] = mtu;
1168  else if (unformat (input, "ip6 %d %U", &mtu,
1169		     unformat_vnet_sw_interface, vnm, &sw_if_index))
1170    mtus[VNET_MTU_IP6] = mtu;
1171  else if (unformat (input, "mpls %d %U", &mtu,
1172		     unformat_vnet_sw_interface, vnm, &sw_if_index))
1173    mtus[VNET_MTU_MPLS] = mtu;
1174  else
1175    return clib_error_return (0, "unknown input `%U'",
1176			      format_unformat_error, input);
1177
1178  vnet_sw_interface_set_protocol_mtu (vnm, sw_if_index, mtus);
1179
1180done:
1181  return 0;
1182}
1183
1184/* *INDENT-OFF* */
1185VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
1186  .path = "set interface mtu",
1187  .short_help = "set interface mtu [packet|ip4|ip6|mpls] <value> <interface>",
1188  .function = mtu_cmd,
1189};
1190/* *INDENT-ON* */
1191
1192static clib_error_t *
1193show_interface_sec_mac_addr_fn (vlib_main_t * vm, unformat_input_t * input,
1194				vlib_cli_command_t * cmd)
1195{
1196  vnet_main_t *vnm = vnet_get_main ();
1197  vnet_interface_main_t *im = &vnm->interface_main;
1198  ethernet_main_t *em = &ethernet_main;
1199  u32 sw_if_index = ~0;
1200  vnet_sw_interface_t *si, *sorted_sis = 0;
1201
1202  if (unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1203    {
1204      si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
1205      vec_add1 (sorted_sis, si[0]);
1206    }
1207
1208  /* if an interface name was not passed, get all interfaces */
1209  if (vec_len (sorted_sis) == 0)
1210    {
1211      sorted_sis =
1212	vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
1213      _vec_len (sorted_sis) = 0;
1214      /* *INDENT-OFF* */
1215      pool_foreach (si, im->sw_interfaces,
1216      ({
1217        int visible = vnet_swif_is_api_visible (si);
1218        if (visible)
1219          vec_add1 (sorted_sis, si[0]);}
1220        ));
1221      /* *INDENT-ON* */
1222      /* Sort by name. */
1223      vec_sort_with_function (sorted_sis, sw_interface_name_compare);
1224    }
1225
1226  vec_foreach (si, sorted_sis)
1227  {
1228    vnet_sw_interface_t *sup_si;
1229    ethernet_interface_t *ei;
1230
1231    sup_si = vnet_get_sup_sw_interface (vnm, si->sw_if_index);
1232    ei = ethernet_get_interface (em, sup_si->hw_if_index);
1233
1234    vlib_cli_output (vm, "%U (%s):",
1235		     format_vnet_sw_if_index_name, vnm, si->sw_if_index,
1236		     (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
1237		     "up" : "dn");
1238
1239    if (ei && ei->secondary_addrs)
1240      {
1241	mac_address_t *sec_addr;
1242
1243	vec_foreach (sec_addr, ei->secondary_addrs)
1244	{
1245	  vlib_cli_output (vm, "  %U", format_mac_address_t, sec_addr);
1246	}
1247      }
1248  }
1249
1250  vec_free (sorted_sis);
1251  return 0;
1252}
1253
1254/*?
1255 * This command is used to display interface secondary mac addresses.
1256 *
1257 * @cliexpar
1258 * Example of how to display interface secondary mac addresses:
1259 * @cliexstart{show interface secondary-mac-address}
1260 * @cliexend
1261?*/
1262/* *INDENT-OFF* */
1263VLIB_CLI_COMMAND (show_interface_sec_mac_addr, static) = {
1264  .path = "show interface secondary-mac-address",
1265  .short_help = "show interface secondary-mac-address [<interface>]",
1266  .function = show_interface_sec_mac_addr_fn,
1267};
1268/* *INDENT-ON* */
1269
1270static clib_error_t *
1271interface_add_del_mac_address (vlib_main_t * vm, unformat_input_t * input,
1272			       vlib_cli_command_t * cmd)
1273{
1274  vnet_main_t *vnm = vnet_get_main ();
1275  vnet_sw_interface_t *si = NULL;
1276  clib_error_t *error = 0;
1277  u32 sw_if_index = ~0;
1278  u8 mac[6] = { 0 };
1279  u8 is_add, is_del;
1280
1281  is_add = is_del = 0;
1282
1283  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1284    {
1285      error = clib_error_return (0, "unknown interface `%U'",
1286				 format_unformat_error, input);
1287      goto done;
1288    }
1289  if (!unformat_user (input, unformat_ethernet_address, mac))
1290    {
1291      error = clib_error_return (0, "expected mac address `%U'",
1292				 format_unformat_error, input);
1293      goto done;
1294    }
1295
1296  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1297    {
1298      if (unformat (input, "add"))
1299	is_add = 1;
1300      else if (unformat (input, "del"))
1301	is_del = 1;
1302      else
1303	break;
1304    }
1305
1306  if (is_add == is_del)
1307    {
1308      error = clib_error_return (0, "must choose one of add or del");
1309      goto done;
1310    }
1311
1312  si = vnet_get_sw_interface (vnm, sw_if_index);
1313  error =
1314    vnet_hw_interface_add_del_mac_address (vnm, si->hw_if_index, mac, is_add);
1315
1316done:
1317  return error;
1318}
1319
1320/*?
1321 * The '<em>set interface secondary-mac-address </em>' command allows adding
1322 * or deleting extra MAC addresses on a given interface without changing the
1323 * default MAC address. This could allow packets sent to these MAC addresses
1324 * to be received without setting the interface to promiscuous mode.
1325 * Not all interfaces support this operation. The ones that do are mostly
1326 * hardware NICs, though virtio does also.
1327 *
1328 * @cliexpar
1329 * @parblock
1330 * Example of how to add a secondary MAC Address on an interface:
1331 * @cliexcmd{set interface secondary-mac-address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01 add}
1332 * Example of how to delete a secondary MAC address from an interface:
1333 * @cliexcmd{set interface secondary-mac-address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01 del}
1334 * @endparblock
1335?*/
1336/* *INDENT-OFF* */
1337VLIB_CLI_COMMAND (interface_add_del_mac_address_cmd, static) = {
1338  .path = "set interface secondary-mac-address",
1339  .short_help = "set interface secondary-mac-address <interface> <mac-address> [(add|del)]",
1340  .function = interface_add_del_mac_address,
1341};
1342/* *INDENT-ON* */
1343
1344static clib_error_t *
1345set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input,
1346			   vlib_cli_command_t * cmd)
1347{
1348  vnet_main_t *vnm = vnet_get_main ();
1349  vnet_sw_interface_t *si = NULL;
1350  clib_error_t *error = 0;
1351  u32 sw_if_index = ~0;
1352  u8 mac[6] = { 0 };
1353
1354  if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1355    {
1356      error = clib_error_return (0, "unknown interface `%U'",
1357				 format_unformat_error, input);
1358      goto done;
1359    }
1360  if (!unformat_user (input, unformat_ethernet_address, mac))
1361    {
1362      error = clib_error_return (0, "expected mac address `%U'",
1363				 format_unformat_error, input);
1364      goto done;
1365    }
1366  si = vnet_get_sw_interface (vnm, sw_if_index);
1367  error = vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, mac);
1368done:
1369  return error;
1370}
1371
1372/*?
1373 * The '<em>set interface mac address </em>' command allows to set MAC address of given interface.
1374 * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address
1375 * change are changes of MAC addresses in FIB tables (ipv4 and ipv6).
1376 *
1377 * @cliexpar
1378 * @parblock
1379 * Example of how to change MAC Address of interface:
1380 * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01}
1381 * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02}
1382 * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03}
1383 * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04}
1384 * @endparblock
1385?*/
1386/* *INDENT-OFF* */
1387VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
1388  .path = "set interface mac address",
1389  .short_help = "set interface mac address <interface> <mac-address>",
1390  .function = set_interface_mac_address,
1391};
1392/* *INDENT-ON* */
1393
1394static clib_error_t *
1395set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1396{
1397  vnet_main_t *vnm = vnet_get_main ();
1398  u32 sw_if_index = ~0;
1399  u8 *tag = 0;
1400
1401  if (!unformat (input, "%U %s", unformat_vnet_sw_interface,
1402		 vnm, &sw_if_index, &tag))
1403    return clib_error_return (0, "unknown input `%U'",
1404			      format_unformat_error, input);
1405
1406  vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
1407
1408  return 0;
1409}
1410
1411/* *INDENT-OFF* */
1412VLIB_CLI_COMMAND (set_tag_command, static) = {
1413  .path = "set interface tag",
1414  .short_help = "set interface tag <interface> <tag>",
1415  .function = set_tag,
1416};
1417/* *INDENT-ON* */
1418
1419static clib_error_t *
1420clear_tag (vlib_main_t * vm, unformat_input_t * input,
1421	   vlib_cli_command_t * cmd)
1422{
1423  vnet_main_t *vnm = vnet_get_main ();
1424  u32 sw_if_index = ~0;
1425
1426  if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1427    return clib_error_return (0, "unknown input `%U'",
1428			      format_unformat_error, input);
1429
1430  vnet_clear_sw_interface_tag (vnm, sw_if_index);
1431
1432  return 0;
1433}
1434
1435/* *INDENT-OFF* */
1436VLIB_CLI_COMMAND (clear_tag_command, static) = {
1437  .path = "clear interface tag",
1438  .short_help = "clear interface tag <interface>",
1439  .function = clear_tag,
1440};
1441/* *INDENT-ON* */
1442
1443static clib_error_t *
1444set_ip_directed_broadcast (vlib_main_t * vm,
1445			   unformat_input_t * input, vlib_cli_command_t * cmd)
1446{
1447  vnet_main_t *vnm = vnet_get_main ();
1448  u32 sw_if_index = ~0;
1449  u8 enable = 0;
1450
1451  if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index));
1452  else if (unformat (input, "enable"))
1453    enable = 1;
1454  else if (unformat (input, "disable"))
1455    enable = 0;
1456  else
1457    return clib_error_return (0, "unknown input: `%U'",
1458			      format_unformat_error, input);
1459
1460  if (~0 == sw_if_index)
1461    return clib_error_return (0, "specify an interface: `%U'",
1462			      format_unformat_error, input);
1463
1464  vnet_sw_interface_ip_directed_broadcast (vnm, sw_if_index, enable);
1465
1466  return 0;
1467}
1468
1469/*?
1470 * This command is used to enable/disable IP directed broadcast
1471 * If directed broadcast is enabled a packet sent to the interface's
1472 * subnet broadcast address will be sent L2 broadcast on the interface,
1473 * otherwise it is dropped.
1474 ?*/
1475/* *INDENT-OFF* */
1476VLIB_CLI_COMMAND (set_ip_directed_broadcast_command, static) = {
1477  .path = "set interface ip directed-broadcast",
1478  .short_help = "set interface enable <interface> <enable|disable>",
1479  .function = set_ip_directed_broadcast,
1480};
1481/* *INDENT-ON* */
1482
1483static clib_error_t *
1484set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1485			  u32 queue_id, vnet_hw_interface_rx_mode mode)
1486{
1487  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1488  vnet_device_class_t *dev_class =
1489    vnet_get_device_class (vnm, hw->dev_class_index);
1490  clib_error_t *error;
1491  vnet_hw_interface_rx_mode old_mode;
1492  int rv;
1493
1494  if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT)
1495    mode = hw->default_rx_mode;
1496
1497  rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode);
1498  switch (rv)
1499    {
1500    case 0:
1501      if (old_mode == mode)
1502	return 0;		/* same rx-mode, no change */
1503      break;
1504    case VNET_API_ERROR_INVALID_INTERFACE:
1505      return clib_error_return (0, "invalid interface");
1506    case VNET_API_ERROR_INVALID_QUEUE:
1507      return clib_error_return (0, "invalid queue");
1508    default:
1509      return clib_error_return (0, "unknown error");
1510    }
1511
1512  if (dev_class->rx_mode_change_function)
1513    {
1514      error = dev_class->rx_mode_change_function (vnm, hw_if_index, queue_id,
1515						  mode);
1516      if (error)
1517	return (error);
1518    }
1519
1520  rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1521  switch (rv)
1522    {
1523    case 0:
1524      break;
1525    case VNET_API_ERROR_UNSUPPORTED:
1526      return clib_error_return (0, "unsupported");
1527    case VNET_API_ERROR_INVALID_INTERFACE:
1528      return clib_error_return (0, "invalid interface");
1529    case VNET_API_ERROR_INVALID_QUEUE:
1530      return clib_error_return (0, "invalid queue");
1531    default:
1532      return clib_error_return (0, "unknown error");
1533    }
1534
1535  return 0;
1536}
1537
1538clib_error_t *
1539set_hw_interface_change_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1540				 u8 queue_id_valid, u32 queue_id,
1541				 vnet_hw_interface_rx_mode mode)
1542{
1543  clib_error_t *error = 0;
1544  vnet_hw_interface_t *hw;
1545  int i;
1546
1547  hw = vnet_get_hw_interface (vnm, hw_if_index);
1548
1549  if (queue_id_valid == 0)
1550    {
1551      for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++)
1552	{
1553	  error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode);
1554	  if (error)
1555	    break;
1556	}
1557      hw->default_rx_mode = mode;
1558    }
1559  else
1560    error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode);
1561
1562  return (error);
1563}
1564
1565static clib_error_t *
1566set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input,
1567		       vlib_cli_command_t * cmd)
1568{
1569  clib_error_t *error = 0;
1570  unformat_input_t _line_input, *line_input = &_line_input;
1571  vnet_main_t *vnm = vnet_get_main ();
1572  u32 hw_if_index = (u32) ~ 0;
1573  u32 queue_id = (u32) ~ 0;
1574  vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN;
1575  u8 queue_id_valid = 0;
1576
1577  if (!unformat_user (input, unformat_line_input, line_input))
1578    return 0;
1579
1580  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1581    {
1582      if (unformat
1583	  (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1584	;
1585      else if (unformat (line_input, "queue %d", &queue_id))
1586	queue_id_valid = 1;
1587      else if (unformat (line_input, "polling"))
1588	mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
1589      else if (unformat (line_input, "interrupt"))
1590	mode = VNET_HW_INTERFACE_RX_MODE_INTERRUPT;
1591      else if (unformat (line_input, "adaptive"))
1592	mode = VNET_HW_INTERFACE_RX_MODE_ADAPTIVE;
1593      else
1594	{
1595	  error = clib_error_return (0, "parse error: '%U'",
1596				     format_unformat_error, line_input);
1597	  unformat_free (line_input);
1598	  return error;
1599	}
1600    }
1601
1602  unformat_free (line_input);
1603
1604  if (hw_if_index == (u32) ~ 0)
1605    return clib_error_return (0, "please specify valid interface name");
1606
1607  if (mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
1608    return clib_error_return (0, "please specify valid rx-mode");
1609
1610  error = set_hw_interface_change_rx_mode (vnm, hw_if_index, queue_id_valid,
1611					   queue_id, mode);
1612
1613  return (error);
1614}
1615
1616/*?
1617 * This command is used to assign the RX packet processing mode (polling,
1618 * interrupt, adaptive) of the a given interface, and optionally a
1619 * given queue. If the '<em>queue</em>' is not provided, the '<em>mode</em>'
1620 * is applied to all queues of the interface. Not all interfaces support
1621 * all modes. To display the current rx-mode use the command
1622 * '<em>show interface rx-placement</em>'.
1623 *
1624 * @cliexpar
1625 * Example of how to assign rx-mode to all queues on an interface:
1626 * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 polling}
1627 * Example of how to assign rx-mode to one queue of an interface:
1628 * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 queue 0 interrupt}
1629 * Example of how to display the rx-mode of all interfaces:
1630 * @cliexstart{show interface rx-placement}
1631 * Thread 1 (vpp_wk_0):
1632 *   node dpdk-input:
1633 *     GigabitEthernet7/0/0 queue 0 (polling)
1634 *   node vhost-user-input:
1635 *     VirtualEthernet0/0/12 queue 0 (interrupt)
1636 *     VirtualEthernet0/0/12 queue 2 (polling)
1637 *     VirtualEthernet0/0/13 queue 0 (polling)
1638 *     VirtualEthernet0/0/13 queue 2 (polling)
1639 * Thread 2 (vpp_wk_1):
1640 *   node dpdk-input:
1641 *     GigabitEthernet7/0/1 queue 0 (polling)
1642 *   node vhost-user-input:
1643 *     VirtualEthernet0/0/12 queue 1 (polling)
1644 *     VirtualEthernet0/0/12 queue 3 (polling)
1645 *     VirtualEthernet0/0/13 queue 1 (polling)
1646 *     VirtualEthernet0/0/13 queue 3 (polling)
1647 * @cliexend
1648?*/
1649/* *INDENT-OFF* */
1650VLIB_CLI_COMMAND (cmd_set_if_rx_mode,static) = {
1651    .path = "set interface rx-mode",
1652    .short_help = "set interface rx-mode <interface> [queue <n>] [polling | interrupt | adaptive]",
1653    .function = set_interface_rx_mode,
1654};
1655/* *INDENT-ON* */
1656
1657static clib_error_t *
1658show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input,
1659				vlib_cli_command_t * cmd)
1660{
1661  u8 *s = 0;
1662  vnet_main_t *vnm = vnet_get_main ();
1663  vnet_device_input_runtime_t *rt;
1664  vnet_device_and_queue_t *dq;
1665  vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input");
1666  uword si;
1667  int index = 0;
1668
1669  /* *INDENT-OFF* */
1670  foreach_vlib_main (({
1671    clib_bitmap_foreach (si, pn->sibling_bitmap,
1672      ({
1673        rt = vlib_node_get_runtime_data (this_vlib_main, si);
1674
1675        if (vec_len (rt->devices_and_queues))
1676          s = format (s, "  node %U:\n", format_vlib_node_name, vm, si);
1677
1678        vec_foreach (dq, rt->devices_and_queues)
1679	  {
1680	    vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm,
1681							     dq->hw_if_index);
1682	    s = format (s, "    %U queue %u (%U)\n",
1683			format_vnet_sw_if_index_name, vnm, hi->sw_if_index,
1684			dq->queue_id,
1685			format_vnet_hw_interface_rx_mode, dq->mode);
1686	  }
1687      }));
1688    if (vec_len (s) > 0)
1689      {
1690        vlib_cli_output(vm, "Thread %u (%s):\n%v", index,
1691			vlib_worker_threads[index].name, s);
1692        vec_reset_length (s);
1693      }
1694    index++;
1695  }));
1696  /* *INDENT-ON* */
1697
1698  vec_free (s);
1699  return 0;
1700}
1701
1702/*?
1703 * This command is used to display the interface and queue worker
1704 * thread placement.
1705 *
1706 * @cliexpar
1707 * Example of how to display the interface placement:
1708 * @cliexstart{show interface rx-placement}
1709 * Thread 1 (vpp_wk_0):
1710 *   node dpdk-input:
1711 *     GigabitEthernet7/0/0 queue 0 (polling)
1712 *   node vhost-user-input:
1713 *     VirtualEthernet0/0/12 queue 0 (polling)
1714 *     VirtualEthernet0/0/12 queue 2 (polling)
1715 *     VirtualEthernet0/0/13 queue 0 (polling)
1716 *     VirtualEthernet0/0/13 queue 2 (polling)
1717 * Thread 2 (vpp_wk_1):
1718 *   node dpdk-input:
1719 *     GigabitEthernet7/0/1 queue 0 (polling)
1720 *   node vhost-user-input:
1721 *     VirtualEthernet0/0/12 queue 1 (polling)
1722 *     VirtualEthernet0/0/12 queue 3 (polling)
1723 *     VirtualEthernet0/0/13 queue 1 (polling)
1724 *     VirtualEthernet0/0/13 queue 3 (polling)
1725 * @cliexend
1726?*/
1727/* *INDENT-OFF* */
1728VLIB_CLI_COMMAND (show_interface_rx_placement, static) = {
1729  .path = "show interface rx-placement",
1730  .short_help = "show interface rx-placement",
1731  .function = show_interface_rx_placement_fn,
1732};
1733/* *INDENT-ON* */
1734
1735clib_error_t *
1736set_hw_interface_rx_placement (u32 hw_if_index, u32 queue_id,
1737			       u32 thread_index, u8 is_main)
1738{
1739  vnet_main_t *vnm = vnet_get_main ();
1740  vnet_device_main_t *vdm = &vnet_device_main;
1741  clib_error_t *error = 0;
1742  vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN;
1743  int rv;
1744
1745  if (is_main)
1746    thread_index = 0;
1747  else
1748    thread_index += vdm->first_worker_thread_index;
1749
1750  if (thread_index > vdm->last_worker_thread_index)
1751    return clib_error_return (0,
1752			      "please specify valid worker thread or main");
1753
1754  rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &mode);
1755
1756  if (rv)
1757    return clib_error_return (0, "not found");
1758
1759  rv = vnet_hw_interface_unassign_rx_thread (vnm, hw_if_index, queue_id);
1760
1761  if (rv)
1762    return clib_error_return (0, "not found");
1763
1764  vnet_hw_interface_assign_rx_thread (vnm, hw_if_index, queue_id,
1765				      thread_index);
1766  vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1767
1768  return (error);
1769}
1770
1771static clib_error_t *
1772set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input,
1773			    vlib_cli_command_t * cmd)
1774{
1775  clib_error_t *error = 0;
1776  unformat_input_t _line_input, *line_input = &_line_input;
1777  vnet_main_t *vnm = vnet_get_main ();
1778  u32 hw_if_index = (u32) ~ 0;
1779  u32 queue_id = (u32) 0;
1780  u32 thread_index = (u32) ~ 0;
1781  u8 is_main = 0;
1782
1783  if (!unformat_user (input, unformat_line_input, line_input))
1784    return 0;
1785
1786  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1787    {
1788      if (unformat
1789	  (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1790	;
1791      else if (unformat (line_input, "queue %d", &queue_id))
1792	;
1793      else if (unformat (line_input, "main", &thread_index))
1794	is_main = 1;
1795      else if (unformat (line_input, "worker %d", &thread_index))
1796	;
1797      else
1798	{
1799	  error = clib_error_return (0, "parse error: '%U'",
1800				     format_unformat_error, line_input);
1801	  unformat_free (line_input);
1802	  return error;
1803	}
1804    }
1805
1806  unformat_free (line_input);
1807
1808  if (hw_if_index == (u32) ~ 0)
1809    return clib_error_return (0, "please specify valid interface name");
1810
1811  error = set_hw_interface_rx_placement (hw_if_index, queue_id, thread_index,
1812					 is_main);
1813
1814  return (error);
1815}
1816
1817/*?
1818 * This command is used to assign a given interface, and optionally a
1819 * given queue, to a different thread. If the '<em>queue</em>' is not provided,
1820 * it defaults to 0. The '<em>worker</em>' parameter is zero based and the index
1821 * in the thread name, for example, 0 in the thread name '<em>vpp_wk_0</em>'.
1822 *
1823 * @cliexpar
1824 * Example of how to display the interface placement:
1825 * @cliexstart{show interface rx-placement}
1826 * Thread 1 (vpp_wk_0):
1827 *   node dpdk-input:
1828 *     GigabitEthernet7/0/0 queue 0 (polling)
1829 *   node vhost-user-input:
1830 *     VirtualEthernet0/0/12 queue 0 (polling)
1831 *     VirtualEthernet0/0/12 queue 2 (polling)
1832 *     VirtualEthernet0/0/13 queue 0 (polling)
1833 *     VirtualEthernet0/0/13 queue 2 (polling)
1834 * Thread 2 (vpp_wk_1):
1835 *   node dpdk-input:
1836 *     GigabitEthernet7/0/1 queue 0 (polling)
1837 *   node vhost-user-input:
1838 *     VirtualEthernet0/0/12 queue 1 (polling)
1839 *     VirtualEthernet0/0/12 queue 3 (polling)
1840 *     VirtualEthernet0/0/13 queue 1 (polling)
1841 *     VirtualEthernet0/0/13 queue 3 (polling)
1842 * @cliexend
1843 * Example of how to assign a interface and queue to a worker thread:
1844 * @cliexcmd{set interface rx-placement VirtualEthernet0/0/12 queue 1 worker 0}
1845 * Example of how to display the interface placement:
1846 * @cliexstart{show interface rx-placement}
1847 * Thread 1 (vpp_wk_0):
1848 *   node dpdk-input:
1849 *     GigabitEthernet7/0/0 queue 0 (polling)
1850 *   node vhost-user-input:
1851 *     VirtualEthernet0/0/12 queue 0 (polling)
1852 *     VirtualEthernet0/0/12 queue 1 (polling)
1853 *     VirtualEthernet0/0/12 queue 2 (polling)
1854 *     VirtualEthernet0/0/13 queue 0 (polling)
1855 *     VirtualEthernet0/0/13 queue 2 (polling)
1856 * Thread 2 (vpp_wk_1):
1857 *   node dpdk-input:
1858 *     GigabitEthernet7/0/1 queue 0 (polling)
1859 *   node vhost-user-input:
1860 *     VirtualEthernet0/0/12 queue 3 (polling)
1861 *     VirtualEthernet0/0/13 queue 1 (polling)
1862 *     VirtualEthernet0/0/13 queue 3 (polling)
1863 * @cliexend
1864?*/
1865/* *INDENT-OFF* */
1866VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = {
1867    .path = "set interface rx-placement",
1868    .short_help = "set interface rx-placement <interface> [queue <n>] "
1869      "[worker <n> | main]",
1870    .function = set_interface_rx_placement,
1871    .is_mp_safe = 1,
1872};
1873/* *INDENT-ON* */
1874
1875static u8 *
1876format_vnet_pcap (u8 * s, va_list * args)
1877{
1878  vnet_pcap_t *pp = va_arg (*args, vnet_pcap_t *);
1879  int type = va_arg (*args, int);
1880  int printed = 0;
1881
1882  if (type == 0)
1883    {
1884      if (pp->pcap_rx_enable)
1885	{
1886	  s = format (s, "rx");
1887	  printed = 1;
1888	}
1889      if (pp->pcap_tx_enable)
1890	{
1891	  if (printed)
1892	    s = format (s, " and ");
1893	  s = format (s, "tx");
1894	  printed = 1;
1895	}
1896      if (pp->pcap_drop_enable)
1897	{
1898	  if (printed)
1899	    s = format (s, " and ");
1900	  s = format (s, "drop");
1901	  printed = 1;
1902	}
1903      return s;
1904    }
1905  s = format (s, "unknown type %d!", type);
1906  return s;
1907}
1908
1909
1910int
1911vnet_pcap_dispatch_trace_configure (vnet_pcap_dispatch_trace_args_t * a)
1912{
1913  vlib_main_t *vm = vlib_get_main ();
1914  vnet_pcap_t *pp = &vm->pcap;
1915  pcap_main_t *pm = &pp->pcap_main;
1916  vnet_classify_main_t *cm = &vnet_classify_main;
1917  vnet_classify_filter_set_t *set = 0;
1918
1919  if (a->status)
1920    {
1921      if (pp->pcap_rx_enable || pp->pcap_tx_enable || pp->pcap_drop_enable)
1922	{
1923	  vlib_cli_output
1924	    (vm, "pcap %U dispatch capture enabled: %d of %d pkts...",
1925	     format_vnet_pcap, pp, 0 /* print type */ ,
1926	     pm->n_packets_captured, pm->n_packets_to_capture);
1927	  vlib_cli_output (vm, "capture to file %s", pm->file_name);
1928	}
1929      else
1930	vlib_cli_output (vm, "pcap dispatch capture disabled");
1931
1932      return 0;
1933    }
1934
1935  /* Consistency checks */
1936
1937  /* Enable w/ capture already enabled not allowed */
1938  if ((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable)
1939      && (a->rx_enable + a->tx_enable + a->drop_enable))
1940    return VNET_API_ERROR_INVALID_VALUE;
1941
1942  /* Disable capture with capture already disabled, not interesting */
1943  if (((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable) == 0)
1944      && ((a->rx_enable + a->tx_enable + a->drop_enable == 0)))
1945    return VNET_API_ERROR_VALUE_EXIST;
1946
1947  /* Change number of packets to capture while capturing */
1948  if ((pp->pcap_rx_enable + pp->pcap_tx_enable + pp->pcap_drop_enable)
1949      && (a->rx_enable + a->tx_enable + a->drop_enable)
1950      && (pm->n_packets_to_capture != a->packets_to_capture))
1951    return VNET_API_ERROR_INVALID_VALUE_2;
1952
1953  set = pool_elt_at_index (cm->filter_sets, cm->filter_set_by_sw_if_index[0]);
1954
1955  /* Classify filter specified, but no classify filter configured */
1956  if ((a->rx_enable + a->tx_enable + a->drop_enable) && a->filter &&
1957      (set->table_indices == 0 || set->table_indices[0] == ~0))
1958    return VNET_API_ERROR_NO_SUCH_LABEL;
1959
1960  if (a->rx_enable + a->tx_enable + a->drop_enable)
1961    {
1962      /* Sanity check max bytes per pkt */
1963      if (a->max_bytes_per_pkt < 32 || a->max_bytes_per_pkt > 9000)
1964	return VNET_API_ERROR_INVALID_MEMORY_SIZE;
1965
1966      /* Clean up from previous run, if any */
1967      vec_free (pm->file_name);
1968      vec_free (pm->pcap_data);
1969      memset (pm, 0, sizeof (*pm));
1970
1971      vec_validate_aligned (vnet_trace_dummy, 2048, CLIB_CACHE_LINE_BYTES);
1972      if (pm->lock == 0)
1973	clib_spinlock_init (&(pm->lock));
1974
1975      if (a->filename == 0)
1976	{
1977	  u8 *stem = 0;
1978
1979	  if (a->rx_enable)
1980	    stem = format (stem, "rx");
1981	  if (a->tx_enable)
1982	    stem = format (stem, "tx");
1983	  if (a->drop_enable)
1984	    stem = format (stem, "drop");
1985	  a->filename = format (0, "/tmp/%s.pcap%c", stem, 0);
1986	  vec_free (stem);
1987	}
1988
1989      pm->file_name = (char *) a->filename;
1990      pm->n_packets_captured = 0;
1991      pm->packet_type = PCAP_PACKET_TYPE_ethernet;
1992      pm->n_packets_to_capture = a->packets_to_capture;
1993      pp->pcap_sw_if_index = a->sw_if_index;
1994      if (a->filter)
1995	pp->filter_classify_table_index = set->table_indices[0];
1996      else
1997	pp->filter_classify_table_index = ~0;
1998      pp->pcap_rx_enable = a->rx_enable;
1999      pp->pcap_tx_enable = a->tx_enable;
2000      pp->pcap_drop_enable = a->drop_enable;
2001      pp->max_bytes_per_pkt = a->max_bytes_per_pkt;
2002    }
2003  else
2004    {
2005      pp->pcap_rx_enable = 0;
2006      pp->pcap_tx_enable = 0;
2007      pp->pcap_drop_enable = 0;
2008      pp->filter_classify_table_index = ~0;
2009      if (pm->n_packets_captured)
2010	{
2011	  clib_error_t *error;
2012	  pm->n_packets_to_capture = pm->n_packets_captured;
2013	  vlib_cli_output (vm, "Write %d packets to %s, and stop capture...",
2014			   pm->n_packets_captured, pm->file_name);
2015	  error = pcap_write (pm);
2016	  if (pm->flags & PCAP_MAIN_INIT_DONE)
2017	    pcap_close (pm);
2018	  /* Report I/O errors... */
2019	  if (error)
2020	    {
2021	      clib_error_report (error);
2022	      return VNET_API_ERROR_SYSCALL_ERROR_1;
2023	    }
2024	  return 0;
2025	}
2026      else
2027	return VNET_API_ERROR_NO_SUCH_ENTRY;
2028    }
2029
2030  return 0;
2031}
2032
2033static clib_error_t *
2034pcap_trace_command_fn (vlib_main_t * vm,
2035		       unformat_input_t * input, vlib_cli_command_t * cmd)
2036{
2037  unformat_input_t _line_input, *line_input = &_line_input;
2038  vnet_pcap_dispatch_trace_args_t _a, *a = &_a;
2039  vnet_main_t *vnm = vnet_get_main ();
2040  u8 *filename = 0;
2041  u32 max = 1000;
2042  u32 max_bytes_per_pkt = 512;
2043  int rv;
2044  int rx_enable = 0;
2045  int tx_enable = 0;
2046  int drop_enable = 0;
2047  int status = 0;
2048  int filter = 0;
2049  u32 sw_if_index = ~0;
2050
2051  /* Get a line of input. */
2052  if (!unformat_user (input, unformat_line_input, line_input))
2053    return 0;
2054
2055  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2056    {
2057      if (unformat (line_input, "rx"))
2058	rx_enable = 1;
2059      else if (unformat (line_input, "tx"))
2060	tx_enable = 1;
2061      else if (unformat (line_input, "drop"))
2062	drop_enable = 1;
2063      else if (unformat (line_input, "off"))
2064	rx_enable = tx_enable = drop_enable = 0;
2065      else if (unformat (line_input, "max-bytes-per-pkt %u",
2066			 &max_bytes_per_pkt))
2067	;
2068      else if (unformat (line_input, "max %d", &max))
2069	;
2070      else if (unformat (line_input, "packets-to-capture %d", &max))
2071	;
2072      else if (unformat (line_input, "file %U", unformat_vlib_tmpfile,
2073			 &filename))
2074	;
2075      else if (unformat (line_input, "status %=", &status, 1))
2076	;
2077      else if (unformat (line_input, "intfc %U",
2078			 unformat_vnet_sw_interface, vnm, &sw_if_index))
2079	;
2080      else if (unformat (line_input, "intfc any"))
2081	sw_if_index = 0;
2082      else if (unformat (line_input, "filter"))
2083	filter = 1;
2084      else
2085	{
2086	  return clib_error_return (0, "unknown input `%U'",
2087				    format_unformat_error, line_input);
2088	}
2089    }
2090
2091  unformat_free (line_input);
2092
2093  /* no need for memset (a, 0, sizeof (*a)), set all fields here. */
2094  a->filename = filename;
2095  a->rx_enable = rx_enable;
2096  a->tx_enable = tx_enable;
2097  a->drop_enable = drop_enable;
2098  a->status = status;
2099  a->packets_to_capture = max;
2100  a->sw_if_index = sw_if_index;
2101  a->filter = filter;
2102  a->max_bytes_per_pkt = max_bytes_per_pkt;
2103
2104  rv = vnet_pcap_dispatch_trace_configure (a);
2105
2106  switch (rv)
2107    {
2108    case 0:
2109      break;
2110
2111    case VNET_API_ERROR_INVALID_VALUE:
2112      return clib_error_return (0, "dispatch trace already enabled...");
2113
2114    case VNET_API_ERROR_VALUE_EXIST:
2115      return clib_error_return (0, "dispatch trace already disabled...");
2116
2117    case VNET_API_ERROR_INVALID_VALUE_2:
2118      return clib_error_return
2119	(0, "can't change number of records to capture while tracing...");
2120
2121    case VNET_API_ERROR_SYSCALL_ERROR_1:
2122      return clib_error_return (0, "I/O writing trace capture...");
2123
2124    case VNET_API_ERROR_NO_SUCH_ENTRY:
2125      return clib_error_return (0, "No packets captured...");
2126
2127    case VNET_API_ERROR_INVALID_MEMORY_SIZE:
2128      return clib_error_return (0,
2129				"Max bytes per pkt must be > 32, < 9000...");
2130
2131    case VNET_API_ERROR_NO_SUCH_LABEL:
2132      return clib_error_return
2133	(0, "No classify filter configured, see 'classify filter...'");
2134
2135    default:
2136      vlib_cli_output (vm, "WARNING: trace configure returned %d", rv);
2137      break;
2138    }
2139  return 0;
2140}
2141
2142/*?
2143 * This command is used to start or stop a packet capture, or show
2144 * the status of packet capture.
2145 *
2146 * This command has the following optional parameters:
2147 *
2148 *
2149 * - <b>rx</b> - Capture received packets
2150 *
2151 * - <b>tx</b> - Capture transmitted packets
2152 *
2153 * - <b>drop</b> - Capture dropped packets
2154 *
2155 * - <b>off</b> - Stop capturing packets, write results to the specified file
2156 *
2157 * - <b>max <nn></b> - Depth of local buffer. Once '<em>nn</em>' number
2158 *   of packets have been received, buffer is flushed to file. Once another
2159 *   '<em>nn</em>' number of packets have been received, buffer is flushed
2160 *   to file, overwriting previous write. If not entered, value defaults
2161 *   to 100. Can only be updated if packet capture is off.
2162 *
2163 * - <b>max-bytes-per-pkt <nnnn></b> - Maximum number of bytes to capture
2164 *   for each packet. Must be >= 32, <= 9000.
2165 *
2166 * - <b>intfc <interface-name>|any</b> - Used to specify a given interface,
2167 *   or use '<em>any</em>' to run packet capture on all interfaces.
2168 *   '<em>any</em>' is the default if not provided. Settings from a previous
2169 *   packet capture are preserved, so '<em>any</em>' can be used to reset
2170 *   the interface setting.
2171 *
2172 * - <b>filter</b> - Use the pcap rx / tx / drop trace filter, which
2173 *   must be configured. Use <b>classify filter pcap...</b> to configure the
2174 *   filter. The filter will only be executed if the per-interface or
2175 *   any-interface tests fail.
2176 *
2177 * - <b>file <name></b> - Used to specify the output filename. The file will
2178 *   be placed in the '<em>/tmp</em>' directory, so only the filename is
2179 *   supported. Directory should not be entered. If file already exists, file
2180 *   will be overwritten. If no filename is provided, the file will be
2181 *   named "/tmp/rx.pcap", "/tmp/tx.pcap", "/tmp/rxandtx.pcap", etc.
2182 *   Can only be updated if packet capture is off.
2183 *
2184 * - <b>status</b> - Displays the current status and configured attributes
2185 *   associated with a packet capture. If packet capture is in progress,
2186 *   '<em>status</em>' also will return the number of packets currently in
2187 *   the local buffer. All additional attributes entered on command line
2188 *   with '<em>status</em>' will be ignored and not applied.
2189 *
2190 * @cliexpar
2191 * Example of how to display the status of a tx packet capture when off:
2192 * @cliexstart{pcap trace status}
2193 * max is 100, for any interface to file /tmp/vpe.pcap
2194 * pcap tx capture is off...
2195 * @cliexend
2196 * Example of how to start a tx packet capture:
2197 * @cliexstart{pcap trace tx max 35 intfc GigabitEthernet0/8/0 file vppTest.pcap}
2198 * @cliexend
2199 * Example of how to display the status of a tx packet capture in progress:
2200 * @cliexstart{pcap trace status}
2201 * max is 35, for interface GigabitEthernet0/8/0 to file /tmp/vppTest.pcap
2202 * pcap tx capture is on: 20 of 35 pkts...
2203 * @cliexend
2204 * Example of how to stop a tx packet capture:
2205 * @cliexstart{pcap trace off}
2206 * captured 21 pkts...
2207 * saved to /tmp/vppTest.pcap...
2208 * @cliexend
2209?*/
2210/* *INDENT-OFF* */
2211
2212VLIB_CLI_COMMAND (pcap_tx_trace_command, static) = {
2213    .path = "pcap trace",
2214    .short_help =
2215    "pcap trace rx tx drop off [max <nn>] [intfc <interface>|any] [file <name>] [status] [max-bytes-per-pkt <nnnn>][filter]",
2216    .function = pcap_trace_command_fn,
2217};
2218/* *INDENT-ON* */
2219
2220/*
2221 * fd.io coding-style-patch-verification: ON
2222 *
2223 * Local Variables:
2224 * eval: (c-set-style "gnu")
2225 * End:
2226 */
2227