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