MTU: Setting of MTU on software interface (instead of hardware interface)
[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
56 static int
57 compare_interface_names (void *a1, void *a2)
58 {
59   u32 *hi1 = a1;
60   u32 *hi2 = a2;
61
62   return vnet_hw_interface_compare (vnet_get_main (), *hi1, *hi2);
63 }
64
65 static clib_error_t *
66 show_or_clear_hw_interfaces (vlib_main_t * vm,
67                              unformat_input_t * input,
68                              vlib_cli_command_t * cmd)
69 {
70   clib_error_t *error = 0;
71   vnet_main_t *vnm = vnet_get_main ();
72   vnet_interface_main_t *im = &vnm->interface_main;
73   vnet_hw_interface_t *hi;
74   u32 hw_if_index, *hw_if_indices = 0;
75   int i, verbose = -1, is_show, show_bond = 0;
76
77   is_show = strstr (cmd->path, "show") != 0;
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 /*?
172  * Display more detailed information about all or a list of given interfaces.
173  * The verboseness of the output can be controlled by the following optional
174  * parameters:
175  * - brief: Only show name, index and state (default for bonded interfaces).
176  * - verbose: Also display additional attributes (default for all other interfaces).
177  * - detail: Also display all remaining attributes and extended statistics.
178  *
179  * To limit the output of the command to bonded interfaces and their slave
180  * interfaces, use the '<em>bond</em>' optional parameter.
181  *
182  * @cliexpar
183  * Example of how to display default data for all interfaces:
184  * @cliexstart{show hardware-interfaces}
185  *               Name                Idx   Link  Hardware
186  * GigabitEthernet7/0/0               1     up   GigabitEthernet7/0/0
187  *   Ethernet address ec:f4:bb:c0:bc:fc
188  *   Intel e1000
189  *     carrier up full duplex speed 1000 mtu 9216
190  *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
191  *     cpu socket 0
192  * GigabitEthernet7/0/1               2     up   GigabitEthernet7/0/1
193  *   Ethernet address ec:f4:bb:c0:bc:fd
194  *   Intel e1000
195  *     carrier up full duplex speed 1000 mtu 9216
196  *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
197  *     cpu socket 0
198  * VirtualEthernet0/0/0               3     up   VirtualEthernet0/0/0
199  *   Ethernet address 02:fe:a5:a9:8b:8e
200  * VirtualEthernet0/0/1               4     up   VirtualEthernet0/0/1
201  *   Ethernet address 02:fe:c0:4e:3b:b0
202  * VirtualEthernet0/0/2               5     up   VirtualEthernet0/0/2
203  *   Ethernet address 02:fe:1f:73:92:81
204  * VirtualEthernet0/0/3               6     up   VirtualEthernet0/0/3
205  *   Ethernet address 02:fe:f2:25:c4:68
206  * local0                             0    down  local0
207  *   local
208  * @cliexend
209  * Example of how to display '<em>verbose</em>' data for an interface by name and
210  * software index (where 2 is the software index):
211  * @cliexstart{show hardware-interfaces GigabitEthernet7/0/0 2 verbose}
212  *               Name                Idx   Link  Hardware
213  * GigabitEthernet7/0/0               1     up   GigabitEthernet7/0/0
214  *   Ethernet address ec:f4:bb:c0:bc:fc
215  *   Intel e1000
216  *     carrier up full duplex speed 1000 mtu 9216
217  *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
218  *     cpu socket 0
219  * GigabitEthernet7/0/1               2    down  GigabitEthernet7/0/1
220  *   Ethernet address ec:f4:bb:c0:bc:fd
221  *   Intel e1000
222  *     carrier up full duplex speed 1000 mtu 9216
223  *     rx queues 1, rx desc 1024, tx queues 3, tx desc 1024
224  *     cpu socket 0
225  * @cliexend
226  ?*/
227 /* *INDENT-OFF* */
228 VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = {
229   .path = "show hardware-interfaces",
230   .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] "
231     "[<interface> [<interface> [..]]] [<sw_idx> [<sw_idx> [..]]]",
232   .function = show_or_clear_hw_interfaces,
233 };
234 /* *INDENT-ON* */
235
236
237 /*?
238  * Clear the extended statistics for all or a list of given interfaces
239  * (statistics associated with the '<em>show hardware-interfaces</em>' command).
240  *
241  * @cliexpar
242  * Example of how to clear the extended statistics for all interfaces:
243  * @cliexcmd{clear hardware-interfaces}
244  * Example of how to clear the extended statistics for an interface by
245  * name and software index (where 2 is the software index):
246  * @cliexcmd{clear hardware-interfaces GigabitEthernet7/0/0 2}
247  ?*/
248 /* *INDENT-OFF* */
249 VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = {
250   .path = "clear hardware-interfaces",
251   .short_help = "clear hardware-interfaces "
252     "[<interface> [<interface> [..]]] [<sw_idx> [<sw_idx> [..]]]",
253   .function = show_or_clear_hw_interfaces,
254 };
255 /* *INDENT-ON* */
256
257 static int
258 sw_interface_name_compare (void *a1, void *a2)
259 {
260   vnet_sw_interface_t *si1 = a1;
261   vnet_sw_interface_t *si2 = a2;
262
263   return vnet_sw_interface_compare (vnet_get_main (),
264                                     si1->sw_if_index, si2->sw_if_index);
265 }
266
267 static clib_error_t *
268 show_sw_interfaces (vlib_main_t * vm,
269                     unformat_input_t * input, vlib_cli_command_t * cmd)
270 {
271   clib_error_t *error = 0;
272   vnet_main_t *vnm = vnet_get_main ();
273   vnet_interface_main_t *im = &vnm->interface_main;
274   vnet_sw_interface_t *si, *sorted_sis = 0;
275   u32 sw_if_index = ~(u32) 0;
276   u8 show_addresses = 0;
277   u8 show_features = 0;
278   u8 show_tag = 0;
279
280   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
281     {
282       /* See if user wants to show specific interface */
283       if (unformat
284           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
285         {
286           si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
287           vec_add1 (sorted_sis, si[0]);
288         }
289       else if (unformat (input, "address") || unformat (input, "addr"))
290         show_addresses = 1;
291       else if (unformat (input, "features") || unformat (input, "feat"))
292         show_features = 1;
293       else if (unformat (input, "tag"))
294         show_tag = 1;
295       else
296         {
297           error = clib_error_return (0, "unknown input `%U'",
298                                      format_unformat_error, input);
299           goto done;
300         }
301     }
302
303   if (show_features || show_tag)
304     {
305       if (sw_if_index == ~(u32) 0)
306         return clib_error_return (0, "Interface not specified...");
307     }
308
309   if (show_features)
310     {
311       vnet_interface_features_show (vm, sw_if_index);
312
313       l2_input_config_t *l2_input = l2input_intf_config (sw_if_index);
314       u32 fb = l2_input->feature_bitmap;
315       /* intf input features are masked by bridge domain */
316       if (l2_input->bridge)
317         fb &= l2input_bd_config (l2_input->bd_index)->feature_bitmap;
318       vlib_cli_output (vm, "\nl2-input:\n%U", format_l2_input_features, fb);
319
320       l2_output_config_t *l2_output = l2output_intf_config (sw_if_index);
321       vlib_cli_output (vm, "\nl2-output:");
322       if (l2_output->out_vtr_flag)
323         vlib_cli_output (vm, "%10s (%s)", "VTR", "--internal--");
324       vlib_cli_output (vm, "%U", format_l2_output_features,
325                        l2_output->feature_bitmap);
326       return 0;
327     }
328   if (show_tag)
329     {
330       u8 *tag;
331       tag = vnet_get_sw_interface_tag (vnm, sw_if_index);
332       vlib_cli_output (vm, "%U: %s",
333                        format_vnet_sw_if_index_name, vnm, sw_if_index,
334                        tag ? (char *) tag : "(none)");
335       return 0;
336     }
337
338   if (!show_addresses)
339     vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0);
340
341   if (vec_len (sorted_sis) == 0)        /* Get all interfaces */
342     {
343       /* Gather interfaces. */
344       sorted_sis =
345         vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
346       _vec_len (sorted_sis) = 0;
347       pool_foreach (si, im->sw_interfaces, (
348                                              {
349                                              int visible =
350                                              vnet_swif_is_api_visible (si);
351                                              if (visible)
352                                              vec_add1 (sorted_sis, si[0]);}
353                     ));
354
355       /* Sort by name. */
356       vec_sort_with_function (sorted_sis, sw_interface_name_compare);
357     }
358
359   if (show_addresses)
360     {
361       vec_foreach (si, sorted_sis)
362       {
363         ip4_main_t *im4 = &ip4_main;
364         ip6_main_t *im6 = &ip6_main;
365         ip_lookup_main_t *lm4 = &im4->lookup_main;
366         ip_lookup_main_t *lm6 = &im6->lookup_main;
367         ip_interface_address_t *ia = 0;
368         u32 fib_index4 = 0, fib_index6 = 0;
369
370         if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index)
371           fib_index4 = vec_elt (im4->fib_index_by_sw_if_index,
372                                 si->sw_if_index);
373
374         if (vec_len (im6->fib_index_by_sw_if_index) > si->sw_if_index)
375           fib_index6 = vec_elt (im6->fib_index_by_sw_if_index,
376                                 si->sw_if_index);
377
378         ip4_fib_t *fib4 = ip4_fib_get (fib_index4);
379         ip6_fib_t *fib6 = ip6_fib_get (fib_index6);
380
381         if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
382           vlib_cli_output
383             (vm, "%U (%s): \n  unnumbered, use %U",
384              format_vnet_sw_if_index_name, vnm, si->sw_if_index,
385              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn",
386              format_vnet_sw_if_index_name, vnm, si->unnumbered_sw_if_index);
387         else
388           vlib_cli_output
389             (vm, "%U (%s):",
390              format_vnet_sw_if_index_name, vnm, si->sw_if_index,
391              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn");
392
393         /* Display any L2 info */
394         l2_input_config_t *l2_input = l2input_intf_config (si->sw_if_index);
395         if (l2_input->bridge)
396           {
397             bd_main_t *bdm = &bd_main;
398             u32 bd_id = l2input_main.bd_configs[l2_input->bd_index].bd_id;
399             vlib_cli_output (vm, "  L2 bridge bd-id %d idx %d shg %d %s",
400                              bd_id, bd_find_index (bdm, bd_id), l2_input->shg,
401                              l2_input->bvi ? "bvi" : " ");
402           }
403         else if (l2_input->xconnect)
404           vlib_cli_output (vm, "  L2 xconnect %U",
405                            format_vnet_sw_if_index_name, vnm,
406                            l2_input->output_sw_if_index);
407
408         /* *INDENT-OFF* */
409         /* Display any IP4 addressing info */
410         foreach_ip_interface_address (lm4, ia, si->sw_if_index,
411                                       1 /* honor unnumbered */,
412         ({
413           ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia);
414           if (fib4->table_id)
415             vlib_cli_output (vm, "  L3 %U/%d ip4 table-id %d fib-idx %d",
416                              format_ip4_address, r4, ia->address_length,
417                              fib4->table_id,
418                              ip4_fib_index_from_table_id (fib4->table_id));
419           else
420             vlib_cli_output (vm, "  L3 %U/%d",
421                              format_ip4_address, r4, ia->address_length);
422         }));
423         /* *INDENT-ON* */
424
425         /* *INDENT-OFF* */
426         /* Display any IP6 addressing info */
427         foreach_ip_interface_address (lm6, ia, si->sw_if_index,
428                                       1 /* honor unnumbered */,
429         ({
430           ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia);
431           if (fib6->table_id)
432             vlib_cli_output (vm, "  L3 %U/%d ip6 table-id %d fib-idx %d",
433                              format_ip6_address, r6, ia->address_length,
434                              fib6->table_id,
435                              ip6_fib_index_from_table_id (fib6->table_id));
436           else
437             vlib_cli_output (vm, "  L3 %U/%d",
438                              format_ip6_address, r6, ia->address_length);
439         }));
440         /* *INDENT-ON* */
441       }
442     }
443   else
444     {
445       vec_foreach (si, sorted_sis)
446       {
447         vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, si);
448       }
449     }
450
451 done:
452   vec_free (sorted_sis);
453   return error;
454 }
455
456 /* *INDENT-OFF* */
457 VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = {
458   .path = "show interface",
459   .short_help = "show interface [address|addr|features|feat] [<interface> [<interface> [..]]]",
460   .function = show_sw_interfaces,
461 };
462 /* *INDENT-ON* */
463
464 /* Root of all interface commands. */
465 /* *INDENT-OFF* */
466 VLIB_CLI_COMMAND (vnet_cli_interface_command, static) = {
467   .path = "interface",
468   .short_help = "Interface commands",
469 };
470 /* *INDENT-ON* */
471
472 /* *INDENT-OFF* */
473 VLIB_CLI_COMMAND (vnet_cli_set_interface_command, static) = {
474   .path = "set interface",
475   .short_help = "Interface commands",
476 };
477 /* *INDENT-ON* */
478
479 static clib_error_t *
480 clear_interface_counters (vlib_main_t * vm,
481                           unformat_input_t * input, vlib_cli_command_t * cmd)
482 {
483   vnet_main_t *vnm = vnet_get_main ();
484   vnet_interface_main_t *im = &vnm->interface_main;
485   vlib_simple_counter_main_t *sm;
486   vlib_combined_counter_main_t *cm;
487   static vnet_main_t **my_vnet_mains;
488   int i, j, n_counters;
489
490   vec_reset_length (my_vnet_mains);
491
492   for (i = 0; i < vec_len (vnet_mains); i++)
493     {
494       if (vnet_mains[i])
495         vec_add1 (my_vnet_mains, vnet_mains[i]);
496     }
497
498   if (vec_len (vnet_mains) == 0)
499     vec_add1 (my_vnet_mains, vnm);
500
501   n_counters = vec_len (im->combined_sw_if_counters);
502
503   for (j = 0; j < n_counters; j++)
504     {
505       for (i = 0; i < vec_len (my_vnet_mains); i++)
506         {
507           im = &my_vnet_mains[i]->interface_main;
508           cm = im->combined_sw_if_counters + j;
509           vlib_clear_combined_counters (cm);
510         }
511     }
512
513   n_counters = vec_len (im->sw_if_counters);
514
515   for (j = 0; j < n_counters; j++)
516     {
517       for (i = 0; i < vec_len (my_vnet_mains); i++)
518         {
519           im = &my_vnet_mains[i]->interface_main;
520           sm = im->sw_if_counters + j;
521           vlib_clear_simple_counters (sm);
522         }
523     }
524
525   return 0;
526 }
527
528 /*?
529  * Clear the statistics for all interfaces (statistics associated with the
530  * '<em>show interface</em>' command).
531  *
532  * @cliexpar
533  * Example of how to clear the statistics for all interfaces:
534  * @cliexcmd{clear interfaces}
535  ?*/
536 /* *INDENT-OFF* */
537 VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
538   .path = "clear interfaces",
539   .short_help = "clear interfaces",
540   .function = clear_interface_counters,
541 };
542 /* *INDENT-ON* */
543
544 /**
545  * Parse subinterface names.
546  *
547  * The following subinterface syntax is supported. The first two are for
548  * backwards compatability:
549  *
550  * <intf-name> <id>
551  *     - a subinterface with the name <intf-name>.<id>. The subinterface
552  *       is a single dot1q vlan with vlan id <id> and exact-match semantics.
553  *
554  * <intf-name> <min_id>-<max_id>
555  *     - a set of the above subinterfaces, repeating for each id
556  *       in the range <min_id> to <max_id>
557  *
558  * In the following, exact-match semantics (i.e. the number of vlan tags on the
559  * packet must match the number of tags in the configuration) are used only if
560  * the keyword exact-match is present. Non-exact match is the default.
561  *
562  * <intf-name> <id> dot1q <outer_id> [exact-match]
563  *     - a subinterface with the name <intf-name>.<id>. The subinterface
564  *       is a single dot1q vlan with vlan id <outer_id>.
565  *
566  * <intf-name> <id> dot1q any [exact-match]
567  *     - a subinterface with the name <intf-name>.<id>. The subinterface
568  *       is a single dot1q vlan with any vlan id.
569  *
570  * <intf-name> <id> dot1q <outer_id> inner-dot1q <inner_id> [exact-match]
571  *     - a subinterface with the name <intf-name>.<id>. The subinterface
572  *       is a double dot1q vlan with outer vlan id <outer_id> and inner vlan id
573  *       <inner_id>.
574  *
575  * <intf-name> <id> dot1q <outer_id> inner-dot1q any [exact-match]
576  *     - a subinterface with the name <intf-name>.<id>. The subinterface
577  *       is a double dot1q vlan with outer vlan id <id> and any inner vlan id.
578  *
579  * <intf-name> <id> dot1q any inner-dot1q any [exact-match]
580  *
581  *     - a subinterface with the name <intf-name>.<id>. The subinterface
582  *       is a double dot1q vlan with any outer vlan id and any inner vlan id.
583  *
584  * For each of the above CLI, there is a duplicate that uses the keyword
585  * "dot1ad" in place of the first "dot1q". These interfaces use ethertype
586  * 0x88ad in place of 0x8100 for the outer ethertype. Note that for double-
587  * tagged packets the inner ethertype is always 0x8100. Also note that
588  * the dot1q and dot1ad naming spaces are independent, so it is legal to
589  * have both "Gig3/0/0.1 dot1q 100" and "Gig3/0/0.2 dot1ad 100". For example:
590  *
591  * <intf-name> <id> dot1ad <outer_id> inner-dot1q <inner_id> [exact-match]
592  *     - a subinterface with the name <intf-name>.<id>. The subinterface
593  *       is a double dot1ad vlan with outer vlan id <outer_id> and inner vlan
594  *       id <inner_id>.
595  *
596  * <intf-name> <id> untagged
597  *     - a subinterface with the name <intf-name>.<id>. The subinterface
598  *       has no vlan tags. Only one can be specified per interface.
599  *
600  * <intf-name> <id> default
601  *     - a subinterface with the name <intf-name>.<id>. This is associated
602  *       with a packet that did not match any other configured subinterface
603  *       on this interface. Only one can be specified per interface.
604  */
605
606 static clib_error_t *
607 parse_vlan_sub_interfaces (unformat_input_t * input,
608                            vnet_sw_interface_t * template)
609 {
610   clib_error_t *error = 0;
611   u32 inner_vlan, outer_vlan;
612
613   if (unformat (input, "any inner-dot1q any"))
614     {
615       template->sub.eth.flags.two_tags = 1;
616       template->sub.eth.flags.outer_vlan_id_any = 1;
617       template->sub.eth.flags.inner_vlan_id_any = 1;
618     }
619   else if (unformat (input, "any"))
620     {
621       template->sub.eth.flags.one_tag = 1;
622       template->sub.eth.flags.outer_vlan_id_any = 1;
623     }
624   else if (unformat (input, "%d inner-dot1q any", &outer_vlan))
625     {
626       template->sub.eth.flags.two_tags = 1;
627       template->sub.eth.flags.inner_vlan_id_any = 1;
628       template->sub.eth.outer_vlan_id = outer_vlan;
629     }
630   else if (unformat (input, "%d inner-dot1q %d", &outer_vlan, &inner_vlan))
631     {
632       template->sub.eth.flags.two_tags = 1;
633       template->sub.eth.outer_vlan_id = outer_vlan;
634       template->sub.eth.inner_vlan_id = inner_vlan;
635     }
636   else if (unformat (input, "%d", &outer_vlan))
637     {
638       template->sub.eth.flags.one_tag = 1;
639       template->sub.eth.outer_vlan_id = outer_vlan;
640     }
641   else
642     {
643       error = clib_error_return (0, "expected dot1q config, got `%U'",
644                                  format_unformat_error, input);
645       goto done;
646     }
647
648   if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
649     {
650       if (unformat (input, "exact-match"))
651         {
652           template->sub.eth.flags.exact_match = 1;
653         }
654     }
655
656 done:
657   return error;
658 }
659
660 static clib_error_t *
661 create_sub_interfaces (vlib_main_t * vm,
662                        unformat_input_t * input, vlib_cli_command_t * cmd)
663 {
664   vnet_main_t *vnm = vnet_get_main ();
665   clib_error_t *error = 0;
666   u32 hw_if_index, sw_if_index;
667   vnet_hw_interface_t *hi;
668   u32 id, id_min, id_max;
669   vnet_sw_interface_t template;
670
671   hw_if_index = ~0;
672   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
673     {
674       error = clib_error_return (0, "unknown interface `%U'",
675                                  format_unformat_error, input);
676       goto done;
677     }
678
679   memset (&template, 0, sizeof (template));
680   template.sub.eth.raw_flags = 0;
681
682   if (unformat (input, "%d default", &id_min))
683     {
684       id_max = id_min;
685       template.sub.eth.flags.default_sub = 1;
686     }
687   else if (unformat (input, "%d untagged", &id_min))
688     {
689       id_max = id_min;
690       template.sub.eth.flags.no_tags = 1;
691       template.sub.eth.flags.exact_match = 1;
692     }
693   else if (unformat (input, "%d dot1q", &id_min))
694     {
695       /* parse dot1q config */
696       id_max = id_min;
697       error = parse_vlan_sub_interfaces (input, &template);
698       if (error)
699         goto done;
700     }
701   else if (unformat (input, "%d dot1ad", &id_min))
702     {
703       /* parse dot1ad config */
704       id_max = id_min;
705       template.sub.eth.flags.dot1ad = 1;
706       error = parse_vlan_sub_interfaces (input, &template);
707       if (error)
708         goto done;
709     }
710   else if (unformat (input, "%d-%d", &id_min, &id_max))
711     {
712       template.sub.eth.flags.one_tag = 1;
713       template.sub.eth.flags.exact_match = 1;
714       if (id_min > id_max)
715         goto id_error;
716     }
717   else if (unformat (input, "%d", &id_min))
718     {
719       id_max = id_min;
720       template.sub.eth.flags.one_tag = 1;
721       template.sub.eth.outer_vlan_id = id_min;
722       template.sub.eth.flags.exact_match = 1;
723     }
724   else
725     {
726     id_error:
727       error = clib_error_return (0, "expected ID or ID MIN-MAX, got `%U'",
728                                  format_unformat_error, input);
729       goto done;
730     }
731
732   hi = vnet_get_hw_interface (vnm, hw_if_index);
733
734   if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
735     {
736       error =
737         clib_error_return (0,
738                            "not allowed as %v belong to a BondEthernet interface",
739                            hi->name);
740       goto done;
741     }
742
743   for (id = id_min; id <= id_max; id++)
744     {
745       uword *p;
746       vnet_interface_main_t *im = &vnm->interface_main;
747       u64 sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
748       u64 *kp;
749
750       p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
751       if (p)
752         {
753           if (CLIB_DEBUG > 0)
754             clib_warning ("sup sw_if_index %d, sub id %d already exists\n",
755                           hi->sw_if_index, id);
756           continue;
757         }
758
759       kp = clib_mem_alloc (sizeof (*kp));
760       *kp = sup_and_sub_key;
761
762       template.type = VNET_SW_INTERFACE_TYPE_SUB;
763       template.flood_class = VNET_FLOOD_CLASS_NORMAL;
764       template.sup_sw_if_index = hi->sw_if_index;
765       template.sub.id = id;
766       if (id_min < id_max)
767         template.sub.eth.outer_vlan_id = id;
768
769       error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
770       if (error)
771         goto done;
772
773       hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index);
774       hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
775       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
776                        vnet_get_main (), sw_if_index);
777     }
778
779 done:
780   return error;
781 }
782
783 /*?
784  * This command is used to add VLAN IDs to interfaces, also known as subinterfaces.
785  * The primary input to this command is the '<em>interface</em>' and '<em>subId</em>'
786  * (subinterface Id) parameters. If no additional VLAN ID is provide, the VLAN ID is
787  * assumed to be the '<em>subId</em>'. The VLAN ID and '<em>subId</em>' can be different,
788  * but this is not recommended.
789  *
790  * This command has several variations:
791  * - <b>create sub-interfaces <interface> <subId></b> - Create a subinterface to
792  * process packets with a given 802.1q VLAN ID (same value as the '<em>subId</em>').
793  *
794  * - <b>create sub-interfaces <interface> <subId> default</b> - Adding the
795  * '<em>default</em>' parameter indicates that packets with VLAN IDs that do not
796  * match any other subinterfaces should be sent to this subinterface.
797  *
798  * - <b>create sub-interfaces <interface> <subId> untagged</b> - Adding the
799  * '<em>untagged</em>' parameter indicates that packets no VLAN IDs should be sent
800  * to this subinterface.
801  *
802  * - <b>create sub-interfaces <interface> <subId>-<subId></b> - Create a range of
803  * subinterfaces to handle a range of VLAN IDs.
804  *
805  * - <b>create sub-interfaces <interface> <subId> dot1q|dot1ad <vlanId>|any [exact-match]</b> -
806  * Use this command to specify the outer VLAN ID, to either be explicited or to make the
807  * VLAN ID different from the '<em>subId</em>'.
808  *
809  * - <b>create sub-interfaces <interface> <subId> dot1q|dot1ad <vlanId>|any inner-dot1q
810  * <vlanId>|any [exact-match]</b> - Use this command to specify the outer VLAN ID and
811  * the innner VLAN ID.
812  *
813  * When '<em>dot1q</em>' or '<em>dot1ad</em>' is explictly entered, subinterfaces
814  * can be configured as either exact-match or non-exact match. Non-exact match is the CLI
815  * default. If '<em>exact-match</em>' is specified, packets must have the same number of
816  * VLAN tags as the configuration. For non-exact-match, packets must at least that number
817  * of tags. L3 (routed) interfaces must be configured as exact-match. L2 interfaces are
818  * typically configured as non-exact-match. If '<em>dot1q</em>' or '<em>dot1ad</em>' is NOT
819  * entered, then the default behavior is exact-match.
820  *
821  * Use the '<em>show interface</em>' command to display all subinterfaces.
822  *
823  * @cliexpar
824  * @parblock
825  * Example of how to create a VLAN subinterface 11 to process packets on 802.1q VLAN ID 11:
826  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11}
827  *
828  * The previous example is shorthand and is equivalent to:
829  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 11 exact-match}
830  *
831  *
832  * Example of how to create a subinterface number that is different from the VLAN ID:
833  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100}
834  *
835  *
836  * Examples of how to create q-in-q and q-in-any subinterfaces:
837  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200}
838  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any}
839  *
840  * Examples of how to create dot1ad interfaces:
841  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 11 dot1ad 11}
842  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 12 dot1ad 100 inner-dot1q 200}
843  *
844  *
845  * Examples of '<em>exact-match</em>' versus non-exact match. A packet with
846  * outer VLAN 100 and inner VLAN 200 would match this interface, because the default
847  * is non-exact match:
848  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100}
849  *
850  * However, the same packet would NOT match this interface because '<em>exact-match</em>'
851  * is specified and only one VLAN is configured, but packet contains two VLANs:
852  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 dot1q 100 exact-match}
853  *
854  *
855  * Example of how to created a subinterface to process untagged packets:
856  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 5 untagged}
857  *
858  * Example of how to created a subinterface to process any packet with a VLAN ID that
859  * does not match any other subinterface:
860  * @cliexcmd{create sub-interfaces GigabitEthernet2/0/0 7 default}
861  *
862  * When subinterfaces are created, they are in the down state. Example of how to
863  * enable a newly created subinterface:
864  * @cliexcmd{set interface GigabitEthernet2/0/0.7 up}
865  * @endparblock
866  ?*/
867 /* *INDENT-OFF* */
868 VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = {
869   .path = "create sub-interfaces",
870   .short_help = "create sub-interfaces <interface> "
871     "{<subId> [default|untagged]} | "
872     "{<subId>-<subId>} | "
873     "{<subId> dot1q|dot1ad <vlanId>|any [inner-dot1q <vlanId>|any] [exact-match]}",
874   .function = create_sub_interfaces,
875 };
876 /* *INDENT-ON* */
877
878 static clib_error_t *
879 set_state (vlib_main_t * vm,
880            unformat_input_t * input, vlib_cli_command_t * cmd)
881 {
882   vnet_main_t *vnm = vnet_get_main ();
883   clib_error_t *error;
884   u32 sw_if_index, flags;
885
886   sw_if_index = ~0;
887   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
888     {
889       error = clib_error_return (0, "unknown interface `%U'",
890                                  format_unformat_error, input);
891       goto done;
892     }
893
894   if (!unformat (input, "%U", unformat_vnet_sw_interface_flags, &flags))
895     {
896       error = clib_error_return (0, "unknown flags `%U'",
897                                  format_unformat_error, input);
898       goto done;
899     }
900
901   error = vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
902   if (error)
903     goto done;
904
905 done:
906   return error;
907 }
908
909
910 /*?
911  * This command is used to change the admin state (up/down) of an interface.
912  *
913  * If an interface is down, the optional '<em>punt</em>' flag can also be set.
914  * The '<em>punt</em>' flag implies the interface is disabled for forwarding
915  * but punt all traffic to slow-path. Use the '<em>enable</em>' flag to clear
916  * '<em>punt</em>' flag (interface is still down).
917  *
918  * @cliexpar
919  * Example of how to configure the admin state of an interface to '<em>up</em?':
920  * @cliexcmd{set interface state GigabitEthernet2/0/0 up}
921  * Example of how to configure the admin state of an interface to '<em>down</em?':
922  * @cliexcmd{set interface state GigabitEthernet2/0/0 down}
923  ?*/
924 /* *INDENT-OFF* */
925 VLIB_CLI_COMMAND (set_state_command, static) = {
926   .path = "set interface state",
927   .short_help = "set interface state <interface> [up|down|punt|enable]",
928   .function = set_state,
929 };
930 /* *INDENT-ON* */
931
932 static clib_error_t *
933 set_unnumbered (vlib_main_t * vm,
934                 unformat_input_t * input, vlib_cli_command_t * cmd)
935 {
936   vnet_main_t *vnm = vnet_get_main ();
937   u32 unnumbered_sw_if_index = ~0;
938   u32 inherit_from_sw_if_index = ~0;
939   int enable = 1;
940
941   if (unformat (input, "%U use %U",
942                 unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
943                 unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index))
944     enable = 1;
945   else if (unformat (input, "del %U",
946                      unformat_vnet_sw_interface, vnm,
947                      &unnumbered_sw_if_index))
948     enable = 0;
949   else
950     return clib_error_return (0, "parse error '%U'",
951                               format_unformat_error, input);
952
953   if (~0 == unnumbered_sw_if_index)
954     return clib_error_return (0, "Specify the unnumbered interface");
955   if (enable && ~0 == inherit_from_sw_if_index)
956     return clib_error_return (0, "When enabling unnumberered specify the"
957                               " IP enabled interface that it uses");
958
959   vnet_sw_interface_update_unnumbered (unnumbered_sw_if_index,
960                                        inherit_from_sw_if_index, enable);
961
962   return (NULL);
963 }
964
965 /* *INDENT-OFF* */
966 VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
967   .path = "set interface unnumbered",
968   .short_help = "set interface unnumbered [<interface> use <interface> | del <interface>]",
969   .function = set_unnumbered,
970 };
971 /* *INDENT-ON* */
972
973
974
975 static clib_error_t *
976 set_hw_class (vlib_main_t * vm,
977               unformat_input_t * input, vlib_cli_command_t * cmd)
978 {
979   vnet_main_t *vnm = vnet_get_main ();
980   vnet_interface_main_t *im = &vnm->interface_main;
981   clib_error_t *error;
982   u32 hw_if_index, hw_class_index;
983
984   hw_if_index = ~0;
985   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
986     {
987       error = clib_error_return (0, "unknown hardware interface `%U'",
988                                  format_unformat_error, input);
989       goto done;
990     }
991
992   if (!unformat_user (input, unformat_hash_string,
993                       im->hw_interface_class_by_name, &hw_class_index))
994     {
995       error = clib_error_return (0, "unknown hardware class `%U'",
996                                  format_unformat_error, input);
997       goto done;
998     }
999
1000   error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index);
1001   if (error)
1002     goto done;
1003
1004 done:
1005   return error;
1006 }
1007
1008 /* *INDENT-OFF* */
1009 VLIB_CLI_COMMAND (set_hw_class_command, static) = {
1010   .path = "set interface hw-class",
1011   .short_help = "Set interface hardware class",
1012   .function = set_hw_class,
1013 };
1014 /* *INDENT-ON* */
1015
1016 static clib_error_t *
1017 vnet_interface_cli_init (vlib_main_t * vm)
1018 {
1019   return 0;
1020 }
1021
1022 VLIB_INIT_FUNCTION (vnet_interface_cli_init);
1023
1024 static clib_error_t *
1025 renumber_interface_command_fn (vlib_main_t * vm,
1026                                unformat_input_t * input,
1027                                vlib_cli_command_t * cmd)
1028 {
1029   u32 hw_if_index;
1030   u32 new_dev_instance;
1031   vnet_main_t *vnm = vnet_get_main ();
1032   int rv;
1033
1034   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
1035     return clib_error_return (0, "unknown hardware interface `%U'",
1036                               format_unformat_error, input);
1037
1038   if (!unformat (input, "%d", &new_dev_instance))
1039     return clib_error_return (0, "new dev instance missing");
1040
1041   rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance);
1042
1043   switch (rv)
1044     {
1045     case 0:
1046       break;
1047
1048     default:
1049       return clib_error_return (0, "vnet_interface_name_renumber returned %d",
1050                                 rv);
1051
1052     }
1053
1054   return 0;
1055 }
1056
1057
1058 /* *INDENT-OFF* */
1059 VLIB_CLI_COMMAND (renumber_interface_command, static) = {
1060   .path = "renumber interface",
1061   .short_help = "renumber interface <interface> <new-dev-instance>",
1062   .function = renumber_interface_command_fn,
1063 };
1064 /* *INDENT-ON* */
1065
1066 static clib_error_t *
1067 promiscuous_cmd (vlib_main_t * vm,
1068                  unformat_input_t * input, vlib_cli_command_t * cmd)
1069 {
1070   vnet_main_t *vnm = vnet_get_main ();
1071   u32 hw_if_index;
1072   u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL;
1073   ethernet_main_t *em = &ethernet_main;
1074   ethernet_interface_t *eif;
1075
1076   if (unformat (input, "on %U",
1077                 unformat_vnet_hw_interface, vnm, &hw_if_index))
1078     ;
1079   else if (unformat (input, "off %U",
1080                      unformat_ethernet_interface, vnm, &hw_if_index))
1081     flags = 0;
1082   else
1083     return clib_error_return (0, "unknown input `%U'",
1084                               format_unformat_error, input);
1085
1086   eif = ethernet_get_interface (em, hw_if_index);
1087   if (!eif)
1088     return clib_error_return (0, "not supported");
1089
1090   ethernet_set_flags (vnm, hw_if_index, flags);
1091   return 0;
1092 }
1093
1094 /* *INDENT-OFF* */
1095 VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = {
1096   .path = "set interface promiscuous",
1097   .short_help = "set interface promiscuous [on|off] <interface>",
1098   .function = promiscuous_cmd,
1099 };
1100 /* *INDENT-ON* */
1101
1102 static clib_error_t *
1103 mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1104 {
1105   vnet_main_t *vnm = vnet_get_main ();
1106   u32 sw_if_index, mtu;
1107
1108   if (unformat (input, "%d %U", &mtu, unformat_vnet_sw_interface, vnm,
1109                 &sw_if_index))
1110     {
1111       ;
1112     }
1113   else
1114     {
1115       return clib_error_return (0, "unknown input `%U'",
1116                                 format_unformat_error, input);
1117     }
1118
1119   int rv = vnet_sw_interface_set_mtu (vnm, sw_if_index, mtu);
1120   if (rv < 0)
1121     {
1122       vnet_hw_interface_t *hi = vnet_get_sw_hw_interface (vnm, sw_if_index);
1123       ASSERT (hi);
1124       return clib_error_return (0, "Invalid mtu (%d): "
1125                                 "must be  between min pkt bytes (%d) and max pkt bytes (%d)",
1126                                 mtu, hi->min_packet_bytes,
1127                                 hi->max_packet_bytes);
1128     }
1129   return 0;
1130 }
1131
1132 /* *INDENT-OFF* */
1133 VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
1134   .path = "set interface mtu",
1135   .short_help = "set interface mtu <value> <interface>",
1136   .function = mtu_cmd,
1137 };
1138 /* *INDENT-ON* */
1139
1140 static clib_error_t *
1141 set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input,
1142                            vlib_cli_command_t * cmd)
1143 {
1144   vnet_main_t *vnm = vnet_get_main ();
1145   vnet_sw_interface_t *si = NULL;
1146   clib_error_t *error = 0;
1147   u32 sw_if_index = ~0;
1148   u8 mac[6] = { 0 };
1149
1150   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1151     {
1152       error = clib_error_return (0, "unknown interface `%U'",
1153                                  format_unformat_error, input);
1154       goto done;
1155     }
1156   if (!unformat_user (input, unformat_ethernet_address, mac))
1157     {
1158       error = clib_error_return (0, "expected mac address `%U'",
1159                                  format_unformat_error, input);
1160       goto done;
1161     }
1162   si = vnet_get_sw_interface (vnm, sw_if_index);
1163   error = vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, mac);
1164 done:
1165   return error;
1166 }
1167
1168 /*?
1169  * The '<em>set interface mac address </em>' command allows to set MAC address of given interface.
1170  * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address
1171  * change are changes of MAC addresses in FIB tables (ipv4 and ipv6).
1172  *
1173  * @cliexpar
1174  * @parblock
1175  * Example of how to change MAC Address of interface:
1176  * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01}
1177  * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02}
1178  * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03}
1179  * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04}
1180  * @endparblock
1181 ?*/
1182 /* *INDENT-OFF* */
1183 VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
1184   .path = "set interface mac address",
1185   .short_help = "set interface mac address <interface> <mac-address>",
1186   .function = set_interface_mac_address,
1187 };
1188 /* *INDENT-ON* */
1189
1190 static clib_error_t *
1191 set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1192 {
1193   vnet_main_t *vnm = vnet_get_main ();
1194   u32 sw_if_index = ~0;
1195   u8 *tag = 0;
1196
1197   if (!unformat (input, "%U %s", unformat_vnet_sw_interface,
1198                  vnm, &sw_if_index, &tag))
1199     return clib_error_return (0, "unknown input `%U'",
1200                               format_unformat_error, input);
1201
1202   vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
1203
1204   return 0;
1205 }
1206
1207 /* *INDENT-OFF* */
1208 VLIB_CLI_COMMAND (set_tag_command, static) = {
1209   .path = "set interface tag",
1210   .short_help = "set interface tag <interface> <tag>",
1211   .function = set_tag,
1212 };
1213 /* *INDENT-ON* */
1214
1215 static clib_error_t *
1216 clear_tag (vlib_main_t * vm, unformat_input_t * input,
1217            vlib_cli_command_t * cmd)
1218 {
1219   vnet_main_t *vnm = vnet_get_main ();
1220   u32 sw_if_index = ~0;
1221
1222   if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1223     return clib_error_return (0, "unknown input `%U'",
1224                               format_unformat_error, input);
1225
1226   vnet_clear_sw_interface_tag (vnm, sw_if_index);
1227
1228   return 0;
1229 }
1230
1231 /* *INDENT-OFF* */
1232 VLIB_CLI_COMMAND (clear_tag_command, static) = {
1233   .path = "clear interface tag",
1234   .short_help = "clear interface tag <interface>",
1235   .function = clear_tag,
1236 };
1237 /* *INDENT-ON* */
1238
1239 static clib_error_t *
1240 set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1241                           u32 queue_id, vnet_hw_interface_rx_mode mode)
1242 {
1243   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1244   vnet_device_class_t *dev_class =
1245     vnet_get_device_class (vnm, hw->dev_class_index);
1246   clib_error_t *error;
1247   vnet_hw_interface_rx_mode old_mode;
1248   int rv;
1249
1250   if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT)
1251     mode = hw->default_rx_mode;
1252
1253   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode);
1254   switch (rv)
1255     {
1256     case 0:
1257       if (old_mode == mode)
1258         return 0;               /* same rx-mode, no change */
1259       break;
1260     case VNET_API_ERROR_INVALID_INTERFACE:
1261       return clib_error_return (0, "invalid interface");
1262     case VNET_API_ERROR_INVALID_QUEUE:
1263       return clib_error_return (0, "invalid queue");
1264     default:
1265       return clib_error_return (0, "unknown error");
1266     }
1267
1268   if (dev_class->rx_mode_change_function)
1269     {
1270       error = dev_class->rx_mode_change_function (vnm, hw_if_index, queue_id,
1271                                                   mode);
1272       if (error)
1273         return (error);
1274     }
1275
1276   rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1277   switch (rv)
1278     {
1279     case 0:
1280       break;
1281     case VNET_API_ERROR_UNSUPPORTED:
1282       return clib_error_return (0, "unsupported");
1283     case VNET_API_ERROR_INVALID_INTERFACE:
1284       return clib_error_return (0, "invalid interface");
1285     case VNET_API_ERROR_INVALID_QUEUE:
1286       return clib_error_return (0, "invalid queue");
1287     default:
1288       return clib_error_return (0, "unknown error");
1289     }
1290
1291   return 0;
1292 }
1293
1294 clib_error_t *
1295 set_hw_interface_change_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1296                                  u8 queue_id_valid, u32 queue_id,
1297                                  vnet_hw_interface_rx_mode mode)
1298 {
1299   clib_error_t *error = 0;
1300   vnet_hw_interface_t *hw;
1301   int i;
1302
1303   hw = vnet_get_hw_interface (vnm, hw_if_index);
1304
1305   if (queue_id_valid == 0)
1306     {
1307       for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++)
1308         {
1309           error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode);
1310           if (error)
1311             break;
1312         }
1313       hw->default_rx_mode = mode;
1314     }
1315   else
1316     error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode);
1317
1318   return (error);
1319 }
1320
1321 static clib_error_t *
1322 set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input,
1323                        vlib_cli_command_t * cmd)
1324 {
1325   clib_error_t *error = 0;
1326   unformat_input_t _line_input, *line_input = &_line_input;
1327   vnet_main_t *vnm = vnet_get_main ();
1328   u32 hw_if_index = (u32) ~ 0;
1329   u32 queue_id = (u32) ~ 0;
1330   vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN;
1331   u8 queue_id_valid = 0;
1332
1333   if (!unformat_user (input, unformat_line_input, line_input))
1334     return 0;
1335
1336   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1337     {
1338       if (unformat
1339           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1340         ;
1341       else if (unformat (line_input, "queue %d", &queue_id))
1342         queue_id_valid = 1;
1343       else if (unformat (line_input, "polling"))
1344         mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
1345       else if (unformat (line_input, "interrupt"))
1346         mode = VNET_HW_INTERFACE_RX_MODE_INTERRUPT;
1347       else if (unformat (line_input, "adaptive"))
1348         mode = VNET_HW_INTERFACE_RX_MODE_ADAPTIVE;
1349       else
1350         {
1351           error = clib_error_return (0, "parse error: '%U'",
1352                                      format_unformat_error, line_input);
1353           unformat_free (line_input);
1354           return error;
1355         }
1356     }
1357
1358   unformat_free (line_input);
1359
1360   if (hw_if_index == (u32) ~ 0)
1361     return clib_error_return (0, "please specify valid interface name");
1362
1363   if (mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
1364     return clib_error_return (0, "please specify valid rx-mode");
1365
1366   error = set_hw_interface_change_rx_mode (vnm, hw_if_index, queue_id_valid,
1367                                            queue_id, mode);
1368
1369   return (error);
1370 }
1371
1372 /*?
1373  * This command is used to assign the RX packet processing mode (polling,
1374  * interrupt, adaptive) of the a given interface, and optionally a
1375  * given queue. If the '<em>queue</em>' is not provided, the '<em>mode</em>'
1376  * is applied to all queues of the interface. Not all interfaces support
1377  * all modes. To display the current rx-mode use the command
1378  * '<em>show interface rx-placement</em>'.
1379  *
1380  * @cliexpar
1381  * Example of how to assign rx-mode to all queues on an interface:
1382  * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 polling}
1383  * Example of how to assign rx-mode to one queue of an interface:
1384  * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 queue 0 interrupt}
1385  * Example of how to display the rx-mode of all interfaces:
1386  * @cliexstart{show interface rx-placement}
1387  * Thread 1 (vpp_wk_0):
1388  *   node dpdk-input:
1389  *     GigabitEthernet7/0/0 queue 0 (polling)
1390  *   node vhost-user-input:
1391  *     VirtualEthernet0/0/12 queue 0 (interrupt)
1392  *     VirtualEthernet0/0/12 queue 2 (polling)
1393  *     VirtualEthernet0/0/13 queue 0 (polling)
1394  *     VirtualEthernet0/0/13 queue 2 (polling)
1395  * Thread 2 (vpp_wk_1):
1396  *   node dpdk-input:
1397  *     GigabitEthernet7/0/1 queue 0 (polling)
1398  *   node vhost-user-input:
1399  *     VirtualEthernet0/0/12 queue 1 (polling)
1400  *     VirtualEthernet0/0/12 queue 3 (polling)
1401  *     VirtualEthernet0/0/13 queue 1 (polling)
1402  *     VirtualEthernet0/0/13 queue 3 (polling)
1403  * @cliexend
1404 ?*/
1405 /* *INDENT-OFF* */
1406 VLIB_CLI_COMMAND (cmd_set_if_rx_mode, static) = {
1407     .path = "set interface rx-mode",
1408     .short_help = "set interface rx-mode <interface> [queue <n>] [polling | interrupt | adaptive]",
1409     .function = set_interface_rx_mode,
1410 };
1411 /* *INDENT-ON* */
1412
1413 static clib_error_t *
1414 show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input,
1415                                 vlib_cli_command_t * cmd)
1416 {
1417   u8 *s = 0;
1418   vnet_main_t *vnm = vnet_get_main ();
1419   vnet_device_input_runtime_t *rt;
1420   vnet_device_and_queue_t *dq;
1421   vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input");
1422   uword si;
1423   int index = 0;
1424
1425   /* *INDENT-OFF* */
1426   foreach_vlib_main (({
1427     clib_bitmap_foreach (si, pn->sibling_bitmap,
1428       ({
1429         rt = vlib_node_get_runtime_data (this_vlib_main, si);
1430
1431         if (vec_len (rt->devices_and_queues))
1432           s = format (s, "  node %U:\n", format_vlib_node_name, vm, si);
1433
1434         vec_foreach (dq, rt->devices_and_queues)
1435           {
1436             vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm,
1437                                                              dq->hw_if_index);
1438             s = format (s, "    %U queue %u (%U)\n",
1439                         format_vnet_sw_if_index_name, vnm, hi->sw_if_index,
1440                         dq->queue_id,
1441                         format_vnet_hw_interface_rx_mode, dq->mode);
1442           }
1443       }));
1444     if (vec_len (s) > 0)
1445       {
1446         vlib_cli_output(vm, "Thread %u (%v):\n%v", index,
1447                         vlib_worker_threads[index].name, s);
1448         vec_reset_length (s);
1449       }
1450     index++;
1451   }));
1452   /* *INDENT-ON* */
1453
1454   vec_free (s);
1455   return 0;
1456 }
1457
1458 /*?
1459  * This command is used to display the interface and queue worker
1460  * thread placement.
1461  *
1462  * @cliexpar
1463  * Example of how to display the interface placement:
1464  * @cliexstart{show interface rx-placement}
1465  * Thread 1 (vpp_wk_0):
1466  *   node dpdk-input:
1467  *     GigabitEthernet7/0/0 queue 0 (polling)
1468  *   node vhost-user-input:
1469  *     VirtualEthernet0/0/12 queue 0 (polling)
1470  *     VirtualEthernet0/0/12 queue 2 (polling)
1471  *     VirtualEthernet0/0/13 queue 0 (polling)
1472  *     VirtualEthernet0/0/13 queue 2 (polling)
1473  * Thread 2 (vpp_wk_1):
1474  *   node dpdk-input:
1475  *     GigabitEthernet7/0/1 queue 0 (polling)
1476  *   node vhost-user-input:
1477  *     VirtualEthernet0/0/12 queue 1 (polling)
1478  *     VirtualEthernet0/0/12 queue 3 (polling)
1479  *     VirtualEthernet0/0/13 queue 1 (polling)
1480  *     VirtualEthernet0/0/13 queue 3 (polling)
1481  * @cliexend
1482 ?*/
1483 /* *INDENT-OFF* */
1484 VLIB_CLI_COMMAND (show_interface_rx_placement, static) = {
1485   .path = "show interface rx-placement",
1486   .short_help = "show interface rx-placement",
1487   .function = show_interface_rx_placement_fn,
1488 };
1489 /* *INDENT-ON* */
1490
1491 static clib_error_t *
1492 set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input,
1493                             vlib_cli_command_t * cmd)
1494 {
1495   clib_error_t *error = 0;
1496   unformat_input_t _line_input, *line_input = &_line_input;
1497   vnet_main_t *vnm = vnet_get_main ();
1498   vnet_device_main_t *vdm = &vnet_device_main;
1499   vnet_hw_interface_rx_mode mode;
1500   u32 hw_if_index = (u32) ~ 0;
1501   u32 queue_id = (u32) 0;
1502   u32 thread_index = (u32) ~ 0;
1503   int rv;
1504
1505   if (!unformat_user (input, unformat_line_input, line_input))
1506     return 0;
1507
1508   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1509     {
1510       if (unformat
1511           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1512         ;
1513       else if (unformat (line_input, "queue %d", &queue_id))
1514         ;
1515       else if (unformat (line_input, "main", &thread_index))
1516         thread_index = 0;
1517       else if (unformat (line_input, "worker %d", &thread_index))
1518         thread_index += vdm->first_worker_thread_index;
1519       else
1520         {
1521           error = clib_error_return (0, "parse error: '%U'",
1522                                      format_unformat_error, line_input);
1523           unformat_free (line_input);
1524           return error;
1525         }
1526     }
1527
1528   unformat_free (line_input);
1529
1530   if (hw_if_index == (u32) ~ 0)
1531     return clib_error_return (0, "please specify valid interface name");
1532
1533   if (thread_index > vdm->last_worker_thread_index)
1534     return clib_error_return (0,
1535                               "please specify valid worker thread or main");
1536
1537   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &mode);
1538
1539   if (rv)
1540     return clib_error_return (0, "not found");
1541
1542   rv = vnet_hw_interface_unassign_rx_thread (vnm, hw_if_index, queue_id);
1543
1544   if (rv)
1545     return clib_error_return (0, "not found");
1546
1547   vnet_hw_interface_assign_rx_thread (vnm, hw_if_index, queue_id,
1548                                       thread_index);
1549   vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1550
1551   return 0;
1552 }
1553
1554 /*?
1555  * This command is used to assign a given interface, and optionally a
1556  * given queue, to a different thread. If the '<em>queue</em>' is not provided,
1557  * it defaults to 0. The '<em>worker</em>' parameter is zero based and the index
1558  * in the thread name, for example, 0 in the thread name '<em>vpp_wk_0</em>'.
1559  *
1560  * @cliexpar
1561  * Example of how to display the interface placement:
1562  * @cliexstart{show interface rx-placement}
1563  * Thread 1 (vpp_wk_0):
1564  *   node dpdk-input:
1565  *     GigabitEthernet7/0/0 queue 0 (polling)
1566  *   node vhost-user-input:
1567  *     VirtualEthernet0/0/12 queue 0 (polling)
1568  *     VirtualEthernet0/0/12 queue 2 (polling)
1569  *     VirtualEthernet0/0/13 queue 0 (polling)
1570  *     VirtualEthernet0/0/13 queue 2 (polling)
1571  * Thread 2 (vpp_wk_1):
1572  *   node dpdk-input:
1573  *     GigabitEthernet7/0/1 queue 0 (polling)
1574  *   node vhost-user-input:
1575  *     VirtualEthernet0/0/12 queue 1 (polling)
1576  *     VirtualEthernet0/0/12 queue 3 (polling)
1577  *     VirtualEthernet0/0/13 queue 1 (polling)
1578  *     VirtualEthernet0/0/13 queue 3 (polling)
1579  * @cliexend
1580  * Example of how to assign a interface and queue to a worker thread:
1581  * @cliexcmd{set interface rx-placement VirtualEthernet0/0/12 queue 1 worker 0}
1582  * Example of how to display the interface placement:
1583  * @cliexstart{show interface rx-placement}
1584  * Thread 1 (vpp_wk_0):
1585  *   node dpdk-input:
1586  *     GigabitEthernet7/0/0 queue 0 (polling)
1587  *   node vhost-user-input:
1588  *     VirtualEthernet0/0/12 queue 0 (polling)
1589  *     VirtualEthernet0/0/12 queue 1 (polling)
1590  *     VirtualEthernet0/0/12 queue 2 (polling)
1591  *     VirtualEthernet0/0/13 queue 0 (polling)
1592  *     VirtualEthernet0/0/13 queue 2 (polling)
1593  * Thread 2 (vpp_wk_1):
1594  *   node dpdk-input:
1595  *     GigabitEthernet7/0/1 queue 0 (polling)
1596  *   node vhost-user-input:
1597  *     VirtualEthernet0/0/12 queue 3 (polling)
1598  *     VirtualEthernet0/0/13 queue 1 (polling)
1599  *     VirtualEthernet0/0/13 queue 3 (polling)
1600  * @cliexend
1601 ?*/
1602 /* *INDENT-OFF* */
1603 VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = {
1604     .path = "set interface rx-placement",
1605     .short_help = "set interface rx-placement <interface> [queue <n>] "
1606       "[worker <n> | main]",
1607     .function = set_interface_rx_placement,
1608     .is_mp_safe = 1,
1609 };
1610 /* *INDENT-ON* */
1611 /*
1612  * fd.io coding-style-patch-verification: ON
1613  *
1614  * Local Variables:
1615  * eval: (c-set-style "gnu")
1616  * End:
1617  */