Improve MTU handling
[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;
938   u32 inherit_from_sw_if_index;
939   vnet_sw_interface_t *si;
940   int is_set = 0;
941   int is_del = 0;
942   u32 was_unnum;
943
944   if (unformat (input, "%U use %U",
945                 unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
946                 unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index))
947     is_set = 1;
948   else if (unformat (input, "del %U",
949                      unformat_vnet_sw_interface, vnm,
950                      &unnumbered_sw_if_index))
951     is_del = 1;
952   else
953     return clib_error_return (0, "parse error '%U'",
954                               format_unformat_error, input);
955
956   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
957   was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
958
959   if (is_del)
960     {
961       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
962       si->unnumbered_sw_if_index = (u32) ~ 0;
963
964       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
965         [unnumbered_sw_if_index] = ~0;
966       ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
967         [unnumbered_sw_if_index] = ~0;
968     }
969   else if (is_set)
970     {
971       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
972       si->unnumbered_sw_if_index = inherit_from_sw_if_index;
973
974       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
975         [unnumbered_sw_if_index] =
976         ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
977         [inherit_from_sw_if_index];
978       ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
979         [unnumbered_sw_if_index] =
980         ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
981         [inherit_from_sw_if_index];
982     }
983
984   if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
985     {
986       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del);
987       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del);
988     }
989
990   return 0;
991 }
992
993 /* *INDENT-OFF* */
994 VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
995   .path = "set interface unnumbered",
996   .short_help = "set interface unnumbered [<interface> use <interface> | del <interface>]",
997   .function = set_unnumbered,
998 };
999 /* *INDENT-ON* */
1000
1001
1002
1003 static clib_error_t *
1004 set_hw_class (vlib_main_t * vm,
1005               unformat_input_t * input, vlib_cli_command_t * cmd)
1006 {
1007   vnet_main_t *vnm = vnet_get_main ();
1008   vnet_interface_main_t *im = &vnm->interface_main;
1009   clib_error_t *error;
1010   u32 hw_if_index, hw_class_index;
1011
1012   hw_if_index = ~0;
1013   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
1014     {
1015       error = clib_error_return (0, "unknown hardware interface `%U'",
1016                                  format_unformat_error, input);
1017       goto done;
1018     }
1019
1020   if (!unformat_user (input, unformat_hash_string,
1021                       im->hw_interface_class_by_name, &hw_class_index))
1022     {
1023       error = clib_error_return (0, "unknown hardware class `%U'",
1024                                  format_unformat_error, input);
1025       goto done;
1026     }
1027
1028   error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index);
1029   if (error)
1030     goto done;
1031
1032 done:
1033   return error;
1034 }
1035
1036 /* *INDENT-OFF* */
1037 VLIB_CLI_COMMAND (set_hw_class_command, static) = {
1038   .path = "set interface hw-class",
1039   .short_help = "Set interface hardware class",
1040   .function = set_hw_class,
1041 };
1042 /* *INDENT-ON* */
1043
1044 static clib_error_t *
1045 vnet_interface_cli_init (vlib_main_t * vm)
1046 {
1047   return 0;
1048 }
1049
1050 VLIB_INIT_FUNCTION (vnet_interface_cli_init);
1051
1052 static clib_error_t *
1053 renumber_interface_command_fn (vlib_main_t * vm,
1054                                unformat_input_t * input,
1055                                vlib_cli_command_t * cmd)
1056 {
1057   u32 hw_if_index;
1058   u32 new_dev_instance;
1059   vnet_main_t *vnm = vnet_get_main ();
1060   int rv;
1061
1062   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
1063     return clib_error_return (0, "unknown hardware interface `%U'",
1064                               format_unformat_error, input);
1065
1066   if (!unformat (input, "%d", &new_dev_instance))
1067     return clib_error_return (0, "new dev instance missing");
1068
1069   rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance);
1070
1071   switch (rv)
1072     {
1073     case 0:
1074       break;
1075
1076     default:
1077       return clib_error_return (0, "vnet_interface_name_renumber returned %d",
1078                                 rv);
1079
1080     }
1081
1082   return 0;
1083 }
1084
1085
1086 /* *INDENT-OFF* */
1087 VLIB_CLI_COMMAND (renumber_interface_command, static) = {
1088   .path = "renumber interface",
1089   .short_help = "renumber interface <interface> <new-dev-instance>",
1090   .function = renumber_interface_command_fn,
1091 };
1092 /* *INDENT-ON* */
1093
1094 static clib_error_t *
1095 promiscuous_cmd (vlib_main_t * vm,
1096                  unformat_input_t * input, vlib_cli_command_t * cmd)
1097 {
1098   vnet_main_t *vnm = vnet_get_main ();
1099   u32 hw_if_index;
1100   u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL;
1101   ethernet_main_t *em = &ethernet_main;
1102   ethernet_interface_t *eif;
1103
1104   if (unformat (input, "on %U",
1105                 unformat_vnet_hw_interface, vnm, &hw_if_index))
1106     ;
1107   else if (unformat (input, "off %U",
1108                      unformat_ethernet_interface, vnm, &hw_if_index))
1109     flags = 0;
1110   else
1111     return clib_error_return (0, "unknown input `%U'",
1112                               format_unformat_error, input);
1113
1114   eif = ethernet_get_interface (em, hw_if_index);
1115   if (!eif)
1116     return clib_error_return (0, "not supported");
1117
1118   ethernet_set_flags (vnm, hw_if_index, flags);
1119   return 0;
1120 }
1121
1122 /* *INDENT-OFF* */
1123 VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = {
1124   .path = "set interface promiscuous",
1125   .short_help = "set interface promiscuous [on|off] <interface>",
1126   .function = promiscuous_cmd,
1127 };
1128 /* *INDENT-ON* */
1129
1130 static clib_error_t *
1131 mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1132 {
1133   vnet_main_t *vnm = vnet_get_main ();
1134   u32 hw_if_index, mtu;
1135   ethernet_main_t *em = &ethernet_main;
1136
1137   if (unformat (input, "%d %U", &mtu,
1138                 unformat_vnet_hw_interface, vnm, &hw_if_index))
1139     {
1140       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1141       ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index);
1142
1143       if (!eif)
1144         return clib_error_return (0, "not supported");
1145
1146       if (mtu < hi->min_supported_packet_bytes)
1147         return clib_error_return (0, "Invalid mtu (%d): "
1148                                   "must be >= min pkt bytes (%d)", mtu,
1149                                   hi->min_supported_packet_bytes);
1150
1151       if (mtu > hi->max_supported_packet_bytes)
1152         return clib_error_return (0, "Invalid mtu (%d): must be <= (%d)", mtu,
1153                                   hi->max_supported_packet_bytes);
1154
1155       vnet_hw_interface_set_mtu (vnm, hw_if_index, mtu);
1156     }
1157   else
1158     return clib_error_return (0, "unknown input `%U'",
1159                               format_unformat_error, input);
1160   return 0;
1161 }
1162
1163 /* *INDENT-OFF* */
1164 VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
1165   .path = "set interface mtu",
1166   .short_help = "set interface mtu <value> <interface>",
1167   .function = mtu_cmd,
1168 };
1169 /* *INDENT-ON* */
1170
1171 static clib_error_t *
1172 set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input,
1173                            vlib_cli_command_t * cmd)
1174 {
1175   vnet_main_t *vnm = vnet_get_main ();
1176   vnet_sw_interface_t *si = NULL;
1177   clib_error_t *error = 0;
1178   u32 sw_if_index = ~0;
1179   u8 mac[6] = { 0 };
1180
1181   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1182     {
1183       error = clib_error_return (0, "unknown interface `%U'",
1184                                  format_unformat_error, input);
1185       goto done;
1186     }
1187   if (!unformat_user (input, unformat_ethernet_address, mac))
1188     {
1189       error = clib_error_return (0, "expected mac address `%U'",
1190                                  format_unformat_error, input);
1191       goto done;
1192     }
1193   si = vnet_get_sw_interface (vnm, sw_if_index);
1194   error = vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, mac);
1195 done:
1196   return error;
1197 }
1198
1199 /*?
1200  * The '<em>set interface mac address </em>' command allows to set MAC address of given interface.
1201  * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address
1202  * change are changes of MAC addresses in FIB tables (ipv4 and ipv6).
1203  *
1204  * @cliexpar
1205  * @parblock
1206  * Example of how to change MAC Address of interface:
1207  * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01}
1208  * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02}
1209  * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03}
1210  * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04}
1211  * @endparblock
1212 ?*/
1213 /* *INDENT-OFF* */
1214 VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
1215   .path = "set interface mac address",
1216   .short_help = "set interface mac address <interface> <mac-address>",
1217   .function = set_interface_mac_address,
1218 };
1219 /* *INDENT-ON* */
1220
1221 static clib_error_t *
1222 set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1223 {
1224   vnet_main_t *vnm = vnet_get_main ();
1225   u32 sw_if_index = ~0;
1226   u8 *tag = 0;
1227
1228   if (!unformat (input, "%U %s", unformat_vnet_sw_interface,
1229                  vnm, &sw_if_index, &tag))
1230     return clib_error_return (0, "unknown input `%U'",
1231                               format_unformat_error, input);
1232
1233   vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
1234
1235   return 0;
1236 }
1237
1238 /* *INDENT-OFF* */
1239 VLIB_CLI_COMMAND (set_tag_command, static) = {
1240   .path = "set interface tag",
1241   .short_help = "set interface tag <interface> <tag>",
1242   .function = set_tag,
1243 };
1244 /* *INDENT-ON* */
1245
1246 static clib_error_t *
1247 clear_tag (vlib_main_t * vm, unformat_input_t * input,
1248            vlib_cli_command_t * cmd)
1249 {
1250   vnet_main_t *vnm = vnet_get_main ();
1251   u32 sw_if_index = ~0;
1252
1253   if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1254     return clib_error_return (0, "unknown input `%U'",
1255                               format_unformat_error, input);
1256
1257   vnet_clear_sw_interface_tag (vnm, sw_if_index);
1258
1259   return 0;
1260 }
1261
1262 /* *INDENT-OFF* */
1263 VLIB_CLI_COMMAND (clear_tag_command, static) = {
1264   .path = "clear interface tag",
1265   .short_help = "clear interface tag <interface>",
1266   .function = clear_tag,
1267 };
1268 /* *INDENT-ON* */
1269
1270 static clib_error_t *
1271 set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1272                           u32 queue_id, vnet_hw_interface_rx_mode mode)
1273 {
1274   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1275   vnet_device_class_t *dev_class =
1276     vnet_get_device_class (vnm, hw->dev_class_index);
1277   clib_error_t *error;
1278   vnet_hw_interface_rx_mode old_mode;
1279   int rv;
1280
1281   if (mode == VNET_HW_INTERFACE_RX_MODE_DEFAULT)
1282     mode = hw->default_rx_mode;
1283
1284   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode);
1285   switch (rv)
1286     {
1287     case 0:
1288       if (old_mode == mode)
1289         return 0;               /* same rx-mode, no change */
1290       break;
1291     case VNET_API_ERROR_INVALID_INTERFACE:
1292       return clib_error_return (0, "invalid interface");
1293     case VNET_API_ERROR_INVALID_QUEUE:
1294       return clib_error_return (0, "invalid queue");
1295     default:
1296       return clib_error_return (0, "unknown error");
1297     }
1298
1299   if (dev_class->rx_mode_change_function)
1300     {
1301       error = dev_class->rx_mode_change_function (vnm, hw_if_index, queue_id,
1302                                                   mode);
1303       if (error)
1304         return (error);
1305     }
1306
1307   rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1308   switch (rv)
1309     {
1310     case 0:
1311       break;
1312     case VNET_API_ERROR_UNSUPPORTED:
1313       return clib_error_return (0, "unsupported");
1314     case VNET_API_ERROR_INVALID_INTERFACE:
1315       return clib_error_return (0, "invalid interface");
1316     case VNET_API_ERROR_INVALID_QUEUE:
1317       return clib_error_return (0, "invalid queue");
1318     default:
1319       return clib_error_return (0, "unknown error");
1320     }
1321
1322   return 0;
1323 }
1324
1325 clib_error_t *
1326 set_hw_interface_change_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1327                                  u8 queue_id_valid, u32 queue_id,
1328                                  vnet_hw_interface_rx_mode mode)
1329 {
1330   clib_error_t *error = 0;
1331   vnet_hw_interface_t *hw;
1332   int i;
1333
1334   hw = vnet_get_hw_interface (vnm, hw_if_index);
1335
1336   if (queue_id_valid == 0)
1337     {
1338       for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++)
1339         {
1340           error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode);
1341           if (error)
1342             break;
1343         }
1344       hw->default_rx_mode = mode;
1345     }
1346   else
1347     error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode);
1348
1349   return (error);
1350 }
1351
1352 static clib_error_t *
1353 set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input,
1354                        vlib_cli_command_t * cmd)
1355 {
1356   clib_error_t *error = 0;
1357   unformat_input_t _line_input, *line_input = &_line_input;
1358   vnet_main_t *vnm = vnet_get_main ();
1359   u32 hw_if_index = (u32) ~ 0;
1360   u32 queue_id = (u32) ~ 0;
1361   vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN;
1362   u8 queue_id_valid = 0;
1363
1364   if (!unformat_user (input, unformat_line_input, line_input))
1365     return 0;
1366
1367   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1368     {
1369       if (unformat
1370           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1371         ;
1372       else if (unformat (line_input, "queue %d", &queue_id))
1373         queue_id_valid = 1;
1374       else if (unformat (line_input, "polling"))
1375         mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
1376       else if (unformat (line_input, "interrupt"))
1377         mode = VNET_HW_INTERFACE_RX_MODE_INTERRUPT;
1378       else if (unformat (line_input, "adaptive"))
1379         mode = VNET_HW_INTERFACE_RX_MODE_ADAPTIVE;
1380       else
1381         {
1382           error = clib_error_return (0, "parse error: '%U'",
1383                                      format_unformat_error, line_input);
1384           unformat_free (line_input);
1385           return error;
1386         }
1387     }
1388
1389   unformat_free (line_input);
1390
1391   if (hw_if_index == (u32) ~ 0)
1392     return clib_error_return (0, "please specify valid interface name");
1393
1394   if (mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
1395     return clib_error_return (0, "please specify valid rx-mode");
1396
1397   error = set_hw_interface_change_rx_mode (vnm, hw_if_index, queue_id_valid,
1398                                            queue_id, mode);
1399
1400   return (error);
1401 }
1402
1403 /*?
1404  * This command is used to assign the RX packet processing mode (polling,
1405  * interrupt, adaptive) of the a given interface, and optionally a
1406  * given queue. If the '<em>queue</em>' is not provided, the '<em>mode</em>'
1407  * is applied to all queues of the interface. Not all interfaces support
1408  * all modes. To display the current rx-mode use the command
1409  * '<em>show interface rx-placement</em>'.
1410  *
1411  * @cliexpar
1412  * Example of how to assign rx-mode to all queues on an interface:
1413  * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 polling}
1414  * Example of how to assign rx-mode to one queue of an interface:
1415  * @cliexcmd{set interface rx-mode VirtualEthernet0/0/12 queue 0 interrupt}
1416  * Example of how to display the rx-mode of all interfaces:
1417  * @cliexstart{show interface rx-placement}
1418  * Thread 1 (vpp_wk_0):
1419  *   node dpdk-input:
1420  *     GigabitEthernet7/0/0 queue 0 (polling)
1421  *   node vhost-user-input:
1422  *     VirtualEthernet0/0/12 queue 0 (interrupt)
1423  *     VirtualEthernet0/0/12 queue 2 (polling)
1424  *     VirtualEthernet0/0/13 queue 0 (polling)
1425  *     VirtualEthernet0/0/13 queue 2 (polling)
1426  * Thread 2 (vpp_wk_1):
1427  *   node dpdk-input:
1428  *     GigabitEthernet7/0/1 queue 0 (polling)
1429  *   node vhost-user-input:
1430  *     VirtualEthernet0/0/12 queue 1 (polling)
1431  *     VirtualEthernet0/0/12 queue 3 (polling)
1432  *     VirtualEthernet0/0/13 queue 1 (polling)
1433  *     VirtualEthernet0/0/13 queue 3 (polling)
1434  * @cliexend
1435 ?*/
1436 /* *INDENT-OFF* */
1437 VLIB_CLI_COMMAND (cmd_set_if_rx_mode,static) = {
1438     .path = "set interface rx-mode",
1439     .short_help = "set interface rx-mode <interface> [queue <n>] [polling | interrupt | adaptive]",
1440     .function = set_interface_rx_mode,
1441 };
1442 /* *INDENT-ON* */
1443
1444 static clib_error_t *
1445 show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input,
1446                                 vlib_cli_command_t * cmd)
1447 {
1448   u8 *s = 0;
1449   vnet_main_t *vnm = vnet_get_main ();
1450   vnet_device_input_runtime_t *rt;
1451   vnet_device_and_queue_t *dq;
1452   vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input");
1453   uword si;
1454   int index = 0;
1455
1456   /* *INDENT-OFF* */
1457   foreach_vlib_main (({
1458     clib_bitmap_foreach (si, pn->sibling_bitmap,
1459       ({
1460         rt = vlib_node_get_runtime_data (this_vlib_main, si);
1461
1462         if (vec_len (rt->devices_and_queues))
1463           s = format (s, "  node %U:\n", format_vlib_node_name, vm, si);
1464
1465         vec_foreach (dq, rt->devices_and_queues)
1466           {
1467             vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm,
1468                                                              dq->hw_if_index);
1469             s = format (s, "    %U queue %u (%U)\n",
1470                         format_vnet_sw_if_index_name, vnm, hi->sw_if_index,
1471                         dq->queue_id,
1472                         format_vnet_hw_interface_rx_mode, dq->mode);
1473           }
1474       }));
1475     if (vec_len (s) > 0)
1476       {
1477         vlib_cli_output(vm, "Thread %u (%v):\n%v", index,
1478                         vlib_worker_threads[index].name, s);
1479         vec_reset_length (s);
1480       }
1481     index++;
1482   }));
1483   /* *INDENT-ON* */
1484
1485   vec_free (s);
1486   return 0;
1487 }
1488
1489 /*?
1490  * This command is used to display the interface and queue worker
1491  * thread placement.
1492  *
1493  * @cliexpar
1494  * Example of how to display the interface placement:
1495  * @cliexstart{show interface rx-placement}
1496  * Thread 1 (vpp_wk_0):
1497  *   node dpdk-input:
1498  *     GigabitEthernet7/0/0 queue 0 (polling)
1499  *   node vhost-user-input:
1500  *     VirtualEthernet0/0/12 queue 0 (polling)
1501  *     VirtualEthernet0/0/12 queue 2 (polling)
1502  *     VirtualEthernet0/0/13 queue 0 (polling)
1503  *     VirtualEthernet0/0/13 queue 2 (polling)
1504  * Thread 2 (vpp_wk_1):
1505  *   node dpdk-input:
1506  *     GigabitEthernet7/0/1 queue 0 (polling)
1507  *   node vhost-user-input:
1508  *     VirtualEthernet0/0/12 queue 1 (polling)
1509  *     VirtualEthernet0/0/12 queue 3 (polling)
1510  *     VirtualEthernet0/0/13 queue 1 (polling)
1511  *     VirtualEthernet0/0/13 queue 3 (polling)
1512  * @cliexend
1513 ?*/
1514 /* *INDENT-OFF* */
1515 VLIB_CLI_COMMAND (show_interface_rx_placement, static) = {
1516   .path = "show interface rx-placement",
1517   .short_help = "show interface rx-placement",
1518   .function = show_interface_rx_placement_fn,
1519 };
1520 /* *INDENT-ON* */
1521
1522 static clib_error_t *
1523 set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input,
1524                             vlib_cli_command_t * cmd)
1525 {
1526   clib_error_t *error = 0;
1527   unformat_input_t _line_input, *line_input = &_line_input;
1528   vnet_main_t *vnm = vnet_get_main ();
1529   vnet_device_main_t *vdm = &vnet_device_main;
1530   vnet_hw_interface_rx_mode mode;
1531   u32 hw_if_index = (u32) ~ 0;
1532   u32 queue_id = (u32) 0;
1533   u32 thread_index = (u32) ~ 0;
1534   int rv;
1535
1536   if (!unformat_user (input, unformat_line_input, line_input))
1537     return 0;
1538
1539   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1540     {
1541       if (unformat
1542           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1543         ;
1544       else if (unformat (line_input, "queue %d", &queue_id))
1545         ;
1546       else if (unformat (line_input, "main", &thread_index))
1547         thread_index = 0;
1548       else if (unformat (line_input, "worker %d", &thread_index))
1549         thread_index += vdm->first_worker_thread_index;
1550       else
1551         {
1552           error = clib_error_return (0, "parse error: '%U'",
1553                                      format_unformat_error, line_input);
1554           unformat_free (line_input);
1555           return error;
1556         }
1557     }
1558
1559   unformat_free (line_input);
1560
1561   if (hw_if_index == (u32) ~ 0)
1562     return clib_error_return (0, "please specify valid interface name");
1563
1564   if (thread_index > vdm->last_worker_thread_index)
1565     return clib_error_return (0,
1566                               "please specify valid worker thread or main");
1567
1568   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &mode);
1569
1570   if (rv)
1571     return clib_error_return (0, "not found");
1572
1573   rv = vnet_hw_interface_unassign_rx_thread (vnm, hw_if_index, queue_id);
1574
1575   if (rv)
1576     return clib_error_return (0, "not found");
1577
1578   vnet_hw_interface_assign_rx_thread (vnm, hw_if_index, queue_id,
1579                                       thread_index);
1580   vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1581
1582   return 0;
1583 }
1584
1585 /*?
1586  * This command is used to assign a given interface, and optionally a
1587  * given queue, to a different thread. If the '<em>queue</em>' is not provided,
1588  * it defaults to 0. The '<em>worker</em>' parameter is zero based and the index
1589  * in the thread name, for example, 0 in the thread name '<em>vpp_wk_0</em>'.
1590  *
1591  * @cliexpar
1592  * Example of how to display the interface placement:
1593  * @cliexstart{show interface rx-placement}
1594  * Thread 1 (vpp_wk_0):
1595  *   node dpdk-input:
1596  *     GigabitEthernet7/0/0 queue 0 (polling)
1597  *   node vhost-user-input:
1598  *     VirtualEthernet0/0/12 queue 0 (polling)
1599  *     VirtualEthernet0/0/12 queue 2 (polling)
1600  *     VirtualEthernet0/0/13 queue 0 (polling)
1601  *     VirtualEthernet0/0/13 queue 2 (polling)
1602  * Thread 2 (vpp_wk_1):
1603  *   node dpdk-input:
1604  *     GigabitEthernet7/0/1 queue 0 (polling)
1605  *   node vhost-user-input:
1606  *     VirtualEthernet0/0/12 queue 1 (polling)
1607  *     VirtualEthernet0/0/12 queue 3 (polling)
1608  *     VirtualEthernet0/0/13 queue 1 (polling)
1609  *     VirtualEthernet0/0/13 queue 3 (polling)
1610  * @cliexend
1611  * Example of how to assign a interface and queue to a worker thread:
1612  * @cliexcmd{set interface rx-placement VirtualEthernet0/0/12 queue 1 worker 0}
1613  * Example of how to display the interface placement:
1614  * @cliexstart{show interface rx-placement}
1615  * Thread 1 (vpp_wk_0):
1616  *   node dpdk-input:
1617  *     GigabitEthernet7/0/0 queue 0 (polling)
1618  *   node vhost-user-input:
1619  *     VirtualEthernet0/0/12 queue 0 (polling)
1620  *     VirtualEthernet0/0/12 queue 1 (polling)
1621  *     VirtualEthernet0/0/12 queue 2 (polling)
1622  *     VirtualEthernet0/0/13 queue 0 (polling)
1623  *     VirtualEthernet0/0/13 queue 2 (polling)
1624  * Thread 2 (vpp_wk_1):
1625  *   node dpdk-input:
1626  *     GigabitEthernet7/0/1 queue 0 (polling)
1627  *   node vhost-user-input:
1628  *     VirtualEthernet0/0/12 queue 3 (polling)
1629  *     VirtualEthernet0/0/13 queue 1 (polling)
1630  *     VirtualEthernet0/0/13 queue 3 (polling)
1631  * @cliexend
1632 ?*/
1633 /* *INDENT-OFF* */
1634 VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = {
1635     .path = "set interface rx-placement",
1636     .short_help = "set interface rx-placement <interface> [queue <n>] "
1637       "[worker <n> | main]",
1638     .function = set_interface_rx_placement,
1639     .is_mp_safe = 1,
1640 };
1641 /* *INDENT-ON* */
1642 /*
1643  * fd.io coding-style-patch-verification: ON
1644  *
1645  * Local Variables:
1646  * eval: (c-set-style "gnu")
1647  * End:
1648  */