device: Add callback for set interface rx-mode
[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  * Interface CLI.
43  */
44
45 #include <vnet/vnet.h>
46 #include <vnet/ip/ip.h>
47 #include <vppinfra/bitmap.h>
48 #include <vnet/fib/ip4_fib.h>
49 #include <vnet/fib/ip6_fib.h>
50
51 static int
52 compare_interface_names (void *a1, void *a2)
53 {
54   u32 *hi1 = a1;
55   u32 *hi2 = a2;
56
57   return vnet_hw_interface_compare (vnet_get_main (), *hi1, *hi2);
58 }
59
60 static clib_error_t *
61 show_or_clear_hw_interfaces (vlib_main_t * vm,
62                              unformat_input_t * input,
63                              vlib_cli_command_t * cmd)
64 {
65   clib_error_t *error = 0;
66   vnet_main_t *vnm = vnet_get_main ();
67   vnet_interface_main_t *im = &vnm->interface_main;
68   vnet_hw_interface_t *hi;
69   u32 hw_if_index, *hw_if_indices = 0;
70   int i, verbose = -1, is_show, show_bond = 0;
71
72   is_show = strstr (cmd->path, "show") != 0;
73   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
74     {
75       /* See if user wants to show a specific interface. */
76       if (unformat
77           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
78         vec_add1 (hw_if_indices, hw_if_index);
79
80       /* See if user wants to show an interface with a specific hw_if_index. */
81       else if (unformat (input, "%u", &hw_if_index))
82         vec_add1 (hw_if_indices, hw_if_index);
83
84       else if (unformat (input, "verbose"))
85         verbose = 1;            /* this is also the default */
86
87       else if (unformat (input, "detail"))
88         verbose = 2;
89
90       else if (unformat (input, "brief"))
91         verbose = 0;
92
93       else if (unformat (input, "bond"))
94         {
95           show_bond = 1;
96           if (verbose < 0)
97             verbose = 0;        /* default to brief for link bonding */
98         }
99
100       else
101         {
102           error = clib_error_return (0, "unknown input `%U'",
103                                      format_unformat_error, input);
104           goto done;
105         }
106     }
107
108   /* Gather interfaces. */
109   if (vec_len (hw_if_indices) == 0)
110     pool_foreach (hi, im->hw_interfaces,
111                   vec_add1 (hw_if_indices, hi - im->hw_interfaces));
112
113   if (verbose < 0)
114     verbose = 1;                /* default to verbose (except bond) */
115
116   if (is_show)
117     {
118       /* Sort by name. */
119       vec_sort_with_function (hw_if_indices, compare_interface_names);
120
121       vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, 0, verbose);
122       for (i = 0; i < vec_len (hw_if_indices); i++)
123         {
124           hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
125           if (show_bond == 0)   /* show all interfaces */
126             vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
127                              hi, verbose);
128           else if ((hi->bond_info) &&
129                    (hi->bond_info != VNET_HW_INTERFACE_BOND_INFO_SLAVE))
130             {                   /* show only bonded interface and all its slave interfaces */
131               int hw_idx;
132               vnet_hw_interface_t *shi;
133               vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
134                                hi, verbose);
135
136               /* *INDENT-OFF* */
137               clib_bitmap_foreach (hw_idx, hi->bond_info,
138               ({
139                 shi = vnet_get_hw_interface(vnm, hw_idx);
140                 vlib_cli_output (vm, "%U\n",
141                                  format_vnet_hw_interface, vnm, shi, verbose);
142               }));
143               /* *INDENT-ON* */
144             }
145         }
146     }
147   else
148     {
149       for (i = 0; i < vec_len (hw_if_indices); i++)
150         {
151           vnet_device_class_t *dc;
152
153           hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
154           dc = vec_elt_at_index (im->device_classes, hi->dev_class_index);
155
156           if (dc->clear_counters)
157             dc->clear_counters (hi->dev_instance);
158         }
159     }
160
161 done:
162   vec_free (hw_if_indices);
163   return error;
164 }
165
166 /* *INDENT-OFF* */
167 /*?
168  * Displays various information about the state of the current terminal
169  * session.
170  *
171  * @cliexpar
172  * @cliexstart{show hardware}
173  * Name                Link  Hardware
174  * GigabitEthernet2/0/0               up   GigabitEthernet2/0/0
175  * Ethernet address 00:50:56:b7:7c:83
176  * Intel 82545em_copper
177  *   link up, media 1000T full-duplex, master,
178  *   0 unprocessed, 384 total buffers on rx queue 0 ring
179  *   237 buffers in driver rx cache
180  *   rx total packets                                    1816
181  *   rx total bytes                                    181084
182  *   rx good packets                                     1816
183  *   rx good bytes                                     181084
184  *   rx 65 127 byte packets                              1586
185  *   rx 256 511 byte packets                              230
186  *   tx total packets                                     346
187  *   tx total bytes                                     90224
188  *   tx good packets                                      346
189  *   tx good bytes                                      88840
190  *   tx 64 byte packets                                     1
191  *   tx 65 127 byte packets                               115
192  *   tx 256 511 byte packets                              230
193  * @cliexend
194  ?*/
195 VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = {
196   .path = "show hardware-interfaces",
197   .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] [<if-name1> <if-name2> ...]",
198   .function = show_or_clear_hw_interfaces,
199 };
200 /* *INDENT-ON* */
201
202 /* *INDENT-OFF* */
203 VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = {
204   .path = "clear hardware-interfaces",
205   .short_help = "Clear hardware interfaces statistics",
206   .function = show_or_clear_hw_interfaces,
207 };
208 /* *INDENT-ON* */
209
210 static int
211 sw_interface_name_compare (void *a1, void *a2)
212 {
213   vnet_sw_interface_t *si1 = a1;
214   vnet_sw_interface_t *si2 = a2;
215
216   return vnet_sw_interface_compare (vnet_get_main (),
217                                     si1->sw_if_index, si2->sw_if_index);
218 }
219
220 static clib_error_t *
221 show_sw_interfaces (vlib_main_t * vm,
222                     unformat_input_t * input, vlib_cli_command_t * cmd)
223 {
224   clib_error_t *error = 0;
225   vnet_main_t *vnm = vnet_get_main ();
226   vnet_interface_main_t *im = &vnm->interface_main;
227   vnet_sw_interface_t *si, *sorted_sis = 0;
228   u32 sw_if_index = ~(u32) 0;
229   u8 show_addresses = 0;
230   u8 show_features = 0;
231   u8 show_tag = 0;
232
233   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
234     {
235       /* See if user wants to show specific interface */
236       if (unformat
237           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
238         {
239           si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
240           vec_add1 (sorted_sis, si[0]);
241         }
242       else if (unformat (input, "address") || unformat (input, "addr"))
243         show_addresses = 1;
244       else if (unformat (input, "features") || unformat (input, "feat"))
245         show_features = 1;
246       else if (unformat (input, "tag"))
247         show_tag = 1;
248       else
249         {
250           error = clib_error_return (0, "unknown input `%U'",
251                                      format_unformat_error, input);
252           goto done;
253         }
254     }
255
256   if (show_features || show_tag)
257     {
258       if (sw_if_index == ~(u32) 0)
259         return clib_error_return (0, "Interface not specified...");
260     }
261
262   if (show_features)
263     {
264       vnet_interface_features_show (vm, sw_if_index);
265       return 0;
266     }
267   if (show_tag)
268     {
269       u8 *tag;
270       tag = vnet_get_sw_interface_tag (vnm, sw_if_index);
271       vlib_cli_output (vm, "%U: %s",
272                        format_vnet_sw_if_index_name, vnm, sw_if_index,
273                        tag ? (char *) tag : "(none)");
274       return 0;
275     }
276
277   if (!show_addresses)
278     vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0);
279
280   if (vec_len (sorted_sis) == 0)        /* Get all interfaces */
281     {
282       /* Gather interfaces. */
283       sorted_sis =
284         vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
285       _vec_len (sorted_sis) = 0;
286       pool_foreach (si, im->sw_interfaces, (
287                                              {
288                                              if (vnet_swif_is_api_visible
289                                                  (si)) vec_add1 (sorted_sis,
290                                                                  si[0]);}
291                     ));
292
293       /* Sort by name. */
294       vec_sort_with_function (sorted_sis, sw_interface_name_compare);
295     }
296
297   if (show_addresses)
298     {
299       vec_foreach (si, sorted_sis)
300       {
301         l2input_main_t *l2m = &l2input_main;
302         ip4_main_t *im4 = &ip4_main;
303         ip6_main_t *im6 = &ip6_main;
304         ip_lookup_main_t *lm4 = &im4->lookup_main;
305         ip_lookup_main_t *lm6 = &im6->lookup_main;
306         ip_interface_address_t *ia = 0;
307         ip4_address_t *r4;
308         ip6_address_t *r6;
309         u32 fib_index4 = 0, fib_index6 = 0;
310         ip4_fib_t *fib4;
311         ip6_fib_t *fib6;
312         l2_input_config_t *config;
313
314         if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index)
315           fib_index4 = vec_elt (im4->fib_index_by_sw_if_index,
316                                 si->sw_if_index);
317
318         if (vec_len (im6->fib_index_by_sw_if_index) > si->sw_if_index)
319           fib_index6 = vec_elt (im6->fib_index_by_sw_if_index,
320                                 si->sw_if_index);
321
322         fib4 = ip4_fib_get (fib_index4);
323         fib6 = ip6_fib_get (fib_index6);
324
325         if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
326           vlib_cli_output
327             (vm, "%U (%s): \n  unnumbered, use %U",
328              format_vnet_sw_if_index_name,
329              vnm, si->sw_if_index,
330              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn",
331              format_vnet_sw_if_index_name, vnm, si->unnumbered_sw_if_index);
332
333         else
334           {
335             vlib_cli_output (vm, "%U (%s):",
336                              format_vnet_sw_if_index_name,
337                              vnm, si->sw_if_index,
338                              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
339                              ? "up" : "dn");
340           }
341
342         /* Display any L2 addressing info */
343         vec_validate (l2m->configs, si->sw_if_index);
344         config = vec_elt_at_index (l2m->configs, si->sw_if_index);
345         if (config->bridge)
346           {
347             u32 bd_id = l2input_main.bd_configs[config->bd_index].bd_id;
348             vlib_cli_output (vm, "  l2 bridge bd_id %d%s%d", bd_id,
349                              config->bvi ? " bvi shg " : " shg ",
350                              config->shg);
351           }
352         else if (config->xconnect)
353           {
354             vlib_cli_output (vm, "  l2 xconnect %U",
355                              format_vnet_sw_if_index_name,
356                              vnm, config->output_sw_if_index);
357           }
358
359         /* Display any IP4 addressing info */
360           /* *INDENT-OFF* */
361           foreach_ip_interface_address (lm4, ia, si->sw_if_index,
362                                         1 /* honor unnumbered */,
363           ({
364             r4 = ip_interface_address_get_address (lm4, ia);
365             if (fib4->table_id)
366               {
367                 vlib_cli_output (vm, "  %U/%d table %d",
368                                  format_ip4_address, r4,
369                                  ia->address_length,
370                                  fib4->table_id);
371               }
372             else
373               {
374                 vlib_cli_output (vm, "  %U/%d",
375                                  format_ip4_address, r4,
376                                  ia->address_length);
377               }
378           }));
379           /* *INDENT-ON* */
380
381         /* Display any IP6 addressing info */
382           /* *INDENT-OFF* */
383           foreach_ip_interface_address (lm6, ia, si->sw_if_index,
384                                         1 /* honor unnumbered */,
385           ({
386             r6 = ip_interface_address_get_address (lm6, ia);
387             if (fib6->table_id)
388               {
389                 vlib_cli_output (vm, "  %U/%d table %d",
390                                  format_ip6_address, r6,
391                                  ia->address_length,
392                                  fib6->table_id);
393               }
394             else
395               {
396                 vlib_cli_output (vm, "  %U/%d",
397                                  format_ip6_address, r6,
398                                  ia->address_length);
399               }
400           }));
401           /* *INDENT-ON* */
402       }
403     }
404   else
405     {
406       vec_foreach (si, sorted_sis)
407       {
408         vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, si);
409       }
410     }
411
412 done:
413   vec_free (sorted_sis);
414   return error;
415 }
416
417 /* *INDENT-OFF* */
418 VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = {
419   .path = "show interface",
420   .short_help = "show interface [address|addr|features|feat] [<if-name1> <if-name2> ...]",
421   .function = show_sw_interfaces,
422 };
423 /* *INDENT-ON* */
424
425 /* Root of all interface commands. */
426 /* *INDENT-OFF* */
427 VLIB_CLI_COMMAND (vnet_cli_interface_command, static) = {
428   .path = "interface",
429   .short_help = "Interface commands",
430 };
431 /* *INDENT-ON* */
432
433 /* *INDENT-OFF* */
434 VLIB_CLI_COMMAND (vnet_cli_set_interface_command, static) = {
435   .path = "set interface",
436   .short_help = "Interface commands",
437 };
438 /* *INDENT-ON* */
439
440 static clib_error_t *
441 clear_interface_counters (vlib_main_t * vm,
442                           unformat_input_t * input, vlib_cli_command_t * cmd)
443 {
444   vnet_main_t *vnm = vnet_get_main ();
445   vnet_interface_main_t *im = &vnm->interface_main;
446   vlib_simple_counter_main_t *sm;
447   vlib_combined_counter_main_t *cm;
448   static vnet_main_t **my_vnet_mains;
449   int i, j, n_counters;
450
451   vec_reset_length (my_vnet_mains);
452
453   for (i = 0; i < vec_len (vnet_mains); i++)
454     {
455       if (vnet_mains[i])
456         vec_add1 (my_vnet_mains, vnet_mains[i]);
457     }
458
459   if (vec_len (vnet_mains) == 0)
460     vec_add1 (my_vnet_mains, vnm);
461
462   n_counters = vec_len (im->combined_sw_if_counters);
463
464   for (j = 0; j < n_counters; j++)
465     {
466       for (i = 0; i < vec_len (my_vnet_mains); i++)
467         {
468           im = &my_vnet_mains[i]->interface_main;
469           cm = im->combined_sw_if_counters + j;
470           vlib_clear_combined_counters (cm);
471         }
472     }
473
474   n_counters = vec_len (im->sw_if_counters);
475
476   for (j = 0; j < n_counters; j++)
477     {
478       for (i = 0; i < vec_len (my_vnet_mains); i++)
479         {
480           im = &my_vnet_mains[i]->interface_main;
481           sm = im->sw_if_counters + j;
482           vlib_clear_simple_counters (sm);
483         }
484     }
485
486   return 0;
487 }
488
489 /* *INDENT-OFF* */
490 VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
491   .path = "clear interfaces",
492   .short_help = "Clear interfaces statistics",
493   .function = clear_interface_counters,
494 };
495 /* *INDENT-ON* */
496
497 /**
498  * Parse subinterface names.
499  *
500  * The following subinterface syntax is supported. The first two are for
501  * backwards compatability:
502  *
503  * <intf-name> <id>
504  *     - a subinterface with the name <intf-name>.<id>. The subinterface
505  *       is a single dot1q vlan with vlan id <id> and exact-match semantics.
506  *
507  * <intf-name> <min_id>-<max_id>
508  *     - a set of the above subinterfaces, repeating for each id
509  *       in the range <min_id> to <max_id>
510  *
511  * In the following, exact-match semantics (i.e. the number of vlan tags on the
512  * packet must match the number of tags in the configuration) are used only if
513  * the keyword exact-match is present. Non-exact match is the default.
514  *
515  * <intf-name> <id> dot1q <outer_id> [exact-match]
516  *     - a subinterface with the name <intf-name>.<id>. The subinterface
517  *       is a single dot1q vlan with vlan id <outer_id>.
518  *
519  * <intf-name> <id> dot1q any [exact-match]
520  *     - a subinterface with the name <intf-name>.<id>. The subinterface
521  *       is a single dot1q vlan with any vlan id.
522  *
523  * <intf-name> <id> dot1q <outer_id> inner-dot1q <inner_id> [exact-match]
524  *     - a subinterface with the name <intf-name>.<id>. The subinterface
525  *       is a double dot1q vlan with outer vlan id <outer_id> and inner vlan id
526  *       <inner_id>.
527  *
528  * <intf-name> <id> dot1q <outer_id> inner-dot1q any [exact-match]
529  *     - a subinterface with the name <intf-name>.<id>. The subinterface
530  *       is a double dot1q vlan with outer vlan id <id> and any inner vlan id.
531  *
532  * <intf-name> <id> dot1q any inner-dot1q any [exact-match]
533  *
534  *     - a subinterface with the name <intf-name>.<id>. The subinterface
535  *       is a double dot1q vlan with any outer vlan id and any inner vlan id.
536  *
537  * For each of the above CLI, there is a duplicate that uses the keyword
538  * "dot1ad" in place of the first "dot1q". These interfaces use ethertype
539  * 0x88ad in place of 0x8100 for the outer ethertype. Note that for double-
540  * tagged packets the inner ethertype is always 0x8100. Also note that
541  * the dot1q and dot1ad naming spaces are independent, so it is legal to
542  * have both "Gig3/0/0.1 dot1q 100" and "Gig3/0/0.2 dot1ad 100". For example:
543  *
544  * <intf-name> <id> dot1ad <outer_id> inner-dot1q <inner_id> [exact-match]
545  *     - a subinterface with the name <intf-name>.<id>. The subinterface
546  *       is a double dot1ad vlan with outer vlan id <outer_id> and inner vlan
547  *       id <inner_id>.
548  *
549  * <intf-name> <id> untagged
550  *     - a subinterface with the name <intf-name>.<id>. The subinterface
551  *       has no vlan tags. Only one can be specified per interface.
552  *
553  * <intf-name> <id> default
554  *     - a subinterface with the name <intf-name>.<id>. This is associated
555  *       with a packet that did not match any other configured subinterface
556  *       on this interface. Only one can be specified per interface.
557  */
558
559 static clib_error_t *
560 parse_vlan_sub_interfaces (unformat_input_t * input,
561                            vnet_sw_interface_t * template)
562 {
563   clib_error_t *error = 0;
564   u32 inner_vlan, outer_vlan;
565
566   if (unformat (input, "any inner-dot1q any"))
567     {
568       template->sub.eth.flags.two_tags = 1;
569       template->sub.eth.flags.outer_vlan_id_any = 1;
570       template->sub.eth.flags.inner_vlan_id_any = 1;
571     }
572   else if (unformat (input, "any"))
573     {
574       template->sub.eth.flags.one_tag = 1;
575       template->sub.eth.flags.outer_vlan_id_any = 1;
576     }
577   else if (unformat (input, "%d inner-dot1q any", &outer_vlan))
578     {
579       template->sub.eth.flags.two_tags = 1;
580       template->sub.eth.flags.inner_vlan_id_any = 1;
581       template->sub.eth.outer_vlan_id = outer_vlan;
582     }
583   else if (unformat (input, "%d inner-dot1q %d", &outer_vlan, &inner_vlan))
584     {
585       template->sub.eth.flags.two_tags = 1;
586       template->sub.eth.outer_vlan_id = outer_vlan;
587       template->sub.eth.inner_vlan_id = inner_vlan;
588     }
589   else if (unformat (input, "%d", &outer_vlan))
590     {
591       template->sub.eth.flags.one_tag = 1;
592       template->sub.eth.outer_vlan_id = outer_vlan;
593     }
594   else
595     {
596       error = clib_error_return (0, "expected dot1q config, got `%U'",
597                                  format_unformat_error, input);
598       goto done;
599     }
600
601   if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
602     {
603       if (unformat (input, "exact-match"))
604         {
605           template->sub.eth.flags.exact_match = 1;
606         }
607     }
608
609 done:
610   return error;
611 }
612
613 static clib_error_t *
614 create_sub_interfaces (vlib_main_t * vm,
615                        unformat_input_t * input, vlib_cli_command_t * cmd)
616 {
617   vnet_main_t *vnm = vnet_get_main ();
618   clib_error_t *error = 0;
619   u32 hw_if_index, sw_if_index;
620   vnet_hw_interface_t *hi;
621   u32 id, id_min, id_max;
622   vnet_sw_interface_t template;
623
624   hw_if_index = ~0;
625   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
626     {
627       error = clib_error_return (0, "unknown interface `%U'",
628                                  format_unformat_error, input);
629       goto done;
630     }
631
632   memset (&template, 0, sizeof (template));
633   template.sub.eth.raw_flags = 0;
634
635   if (unformat (input, "%d default", &id_min))
636     {
637       id_max = id_min;
638       template.sub.eth.flags.default_sub = 1;
639     }
640   else if (unformat (input, "%d untagged", &id_min))
641     {
642       id_max = id_min;
643       template.sub.eth.flags.no_tags = 1;
644       template.sub.eth.flags.exact_match = 1;
645     }
646   else if (unformat (input, "%d dot1q", &id_min))
647     {
648       /* parse dot1q config */
649       id_max = id_min;
650       error = parse_vlan_sub_interfaces (input, &template);
651       if (error)
652         goto done;
653     }
654   else if (unformat (input, "%d dot1ad", &id_min))
655     {
656       /* parse dot1ad config */
657       id_max = id_min;
658       template.sub.eth.flags.dot1ad = 1;
659       error = parse_vlan_sub_interfaces (input, &template);
660       if (error)
661         goto done;
662     }
663   else if (unformat (input, "%d-%d", &id_min, &id_max))
664     {
665       template.sub.eth.flags.one_tag = 1;
666       template.sub.eth.flags.exact_match = 1;
667       if (id_min > id_max)
668         goto id_error;
669     }
670   else if (unformat (input, "%d", &id_min))
671     {
672       id_max = id_min;
673       template.sub.eth.flags.one_tag = 1;
674       template.sub.eth.outer_vlan_id = id_min;
675       template.sub.eth.flags.exact_match = 1;
676     }
677   else
678     {
679     id_error:
680       error = clib_error_return (0, "expected ID or ID MIN-MAX, got `%U'",
681                                  format_unformat_error, input);
682       goto done;
683     }
684
685   hi = vnet_get_hw_interface (vnm, hw_if_index);
686
687   if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
688     {
689       error =
690         clib_error_return (0,
691                            "not allowed as %v belong to a BondEthernet interface",
692                            hi->name);
693       goto done;
694     }
695
696   for (id = id_min; id <= id_max; id++)
697     {
698       uword *p;
699       vnet_interface_main_t *im = &vnm->interface_main;
700       u64 sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
701       u64 *kp;
702
703       p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
704       if (p)
705         {
706           if (CLIB_DEBUG > 0)
707             clib_warning ("sup sw_if_index %d, sub id %d already exists\n",
708                           hi->sw_if_index, id);
709           continue;
710         }
711
712       kp = clib_mem_alloc (sizeof (*kp));
713       *kp = sup_and_sub_key;
714
715       template.type = VNET_SW_INTERFACE_TYPE_SUB;
716       template.flood_class = VNET_FLOOD_CLASS_NORMAL;
717       template.sup_sw_if_index = hi->sw_if_index;
718       template.sub.id = id;
719       if (id_min < id_max)
720         template.sub.eth.outer_vlan_id = id;
721
722       error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
723       if (error)
724         goto done;
725
726       hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index);
727       hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
728       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
729                        vnet_get_main (), sw_if_index);
730     }
731
732 done:
733   return error;
734 }
735
736 /* *INDENT-OFF* */
737 /*?
738  * Create vlan subinterfaces
739  *
740  * @cliexpar
741  * @cliexstart{create sub-interfaces}
742  *
743  * To create a vlan subinterface 11 to process packets on 802.1q VLAN id 11, use:
744  *
745  *  vpp# create sub GigabitEthernet2/0/0 11
746  *
747  * This shorthand is equivalent to:
748  *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 11 exact-match
749  *
750  * You can specify a subinterface number that is different from the vlan id:
751  *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 100
752  *
753  * You can create qinq and q-in-any interfaces:
754  *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200
755  *  vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any
756  *
757  * You can also create dot1ad interfaces:
758  *  vpp# create sub GigabitEthernet2/0/0 11 dot1ad 11
759  *  vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q 200
760  *
761  * Subinterfaces can be configured as either exact-match or non-exact match.
762  * Non-exact match is the CLI default. If exact-match is specified,
763  * packets must have the same number of vlan tags as the configuration.
764  * For non-exact-match, packets must at least that number of tags.
765  * L3 (routed) interfaces must be configured as exact-match.
766  * L2 interfaces are typically configured as non-exact-match.
767  *
768  * For example, a packet with outer vlan 100 and inner 200 would match this interface:
769  *  vpp# create sub GigabitEthernet2/0/0 5 dot1q 100
770  *
771  * but would not match this interface:
772  *  vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 exact-match
773  *
774  * There are two special subinterfaces that can be configured. Subinterface untagged has no vlan tags:
775  *  vpp# create sub GigabitEthernet2/0/0 5 untagged
776  *
777  * The subinterface default matches any packet that does not match any other subinterface:
778  *  vpp# create sub GigabitEthernet2/0/0 7 default
779  * @cliexend
780  ?*/
781 VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = {
782   .path = "create sub-interfaces",
783   .short_help = "create sub-interfaces <nn>[-<nn>] [dot1q|dot1ad|default|untagged]",
784   .function = create_sub_interfaces,
785 };
786 /* *INDENT-ON* */
787
788 static clib_error_t *
789 set_state (vlib_main_t * vm,
790            unformat_input_t * input, vlib_cli_command_t * cmd)
791 {
792   vnet_main_t *vnm = vnet_get_main ();
793   clib_error_t *error;
794   u32 sw_if_index, flags;
795
796   sw_if_index = ~0;
797   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
798     {
799       error = clib_error_return (0, "unknown interface `%U'",
800                                  format_unformat_error, input);
801       goto done;
802     }
803
804   if (!unformat (input, "%U", unformat_vnet_sw_interface_flags, &flags))
805     {
806       error = clib_error_return (0, "unknown flags `%U'",
807                                  format_unformat_error, input);
808       goto done;
809     }
810
811   error = vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
812   if (error)
813     goto done;
814
815 done:
816   return error;
817 }
818
819
820 /* *INDENT-OFF* */
821 /*?
822  * Interface admin up/down
823  *
824  * @cliexpar
825  * @cliexstart{set interface state}
826  *  vpp# set interface state GigabitEthernet2/0/0 up
827  *  vpp# set interface state GigabitEthernet2/0/0 down
828  * @cliexend
829  ?*/
830 VLIB_CLI_COMMAND (set_state_command, static) = {
831   .path = "set interface state",
832   .short_help = "set interface state <if-name> [up|down|punt|enable]",
833   .function = set_state,
834 };
835 /* *INDENT-ON* */
836
837 static clib_error_t *
838 set_unnumbered (vlib_main_t * vm,
839                 unformat_input_t * input, vlib_cli_command_t * cmd)
840 {
841   vnet_main_t *vnm = vnet_get_main ();
842   u32 unnumbered_sw_if_index;
843   u32 inherit_from_sw_if_index;
844   vnet_sw_interface_t *si;
845   int is_set = 0;
846   int is_del = 0;
847   u32 was_unnum;
848
849   if (unformat (input, "%U use %U",
850                 unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
851                 unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index))
852     is_set = 1;
853   else if (unformat (input, "del %U",
854                      unformat_vnet_sw_interface, vnm,
855                      &unnumbered_sw_if_index))
856     is_del = 1;
857   else
858     return clib_error_return (0, "parse error '%U'",
859                               format_unformat_error, input);
860
861   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
862   was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
863
864   if (is_del)
865     {
866       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
867       si->unnumbered_sw_if_index = (u32) ~ 0;
868
869       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
870         [unnumbered_sw_if_index] = ~0;
871       ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
872         [unnumbered_sw_if_index] = ~0;
873     }
874   else if (is_set)
875     {
876       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
877       si->unnumbered_sw_if_index = inherit_from_sw_if_index;
878
879       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
880         [unnumbered_sw_if_index] =
881         ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
882         [inherit_from_sw_if_index];
883       ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
884         [unnumbered_sw_if_index] =
885         ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
886         [inherit_from_sw_if_index];
887     }
888
889   if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
890     {
891       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del);
892       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, !is_del);
893     }
894
895   return 0;
896 }
897
898 /* *INDENT-OFF* */
899 VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
900   .path = "set interface unnumbered",
901   .short_help = "set interface unnumbered [<intfc> use <intfc> | del <intfc>]",
902   .function = set_unnumbered,
903 };
904 /* *INDENT-ON* */
905
906
907
908 static clib_error_t *
909 set_hw_class (vlib_main_t * vm,
910               unformat_input_t * input, vlib_cli_command_t * cmd)
911 {
912   vnet_main_t *vnm = vnet_get_main ();
913   vnet_interface_main_t *im = &vnm->interface_main;
914   clib_error_t *error;
915   u32 hw_if_index, hw_class_index;
916
917   hw_if_index = ~0;
918   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
919     {
920       error = clib_error_return (0, "unknown hardware interface `%U'",
921                                  format_unformat_error, input);
922       goto done;
923     }
924
925   if (!unformat_user (input, unformat_hash_string,
926                       im->hw_interface_class_by_name, &hw_class_index))
927     {
928       error = clib_error_return (0, "unknown hardware class `%U'",
929                                  format_unformat_error, input);
930       goto done;
931     }
932
933   error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index);
934   if (error)
935     goto done;
936
937 done:
938   return error;
939 }
940
941 /* *INDENT-OFF* */
942 VLIB_CLI_COMMAND (set_hw_class_command, static) = {
943   .path = "set interface hw-class",
944   .short_help = "Set interface hardware class",
945   .function = set_hw_class,
946 };
947 /* *INDENT-ON* */
948
949 static clib_error_t *
950 vnet_interface_cli_init (vlib_main_t * vm)
951 {
952   return 0;
953 }
954
955 VLIB_INIT_FUNCTION (vnet_interface_cli_init);
956
957 static clib_error_t *
958 renumber_interface_command_fn (vlib_main_t * vm,
959                                unformat_input_t * input,
960                                vlib_cli_command_t * cmd)
961 {
962   u32 hw_if_index;
963   u32 new_dev_instance;
964   vnet_main_t *vnm = vnet_get_main ();
965   int rv;
966
967   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
968     return clib_error_return (0, "unknown hardware interface `%U'",
969                               format_unformat_error, input);
970
971   if (!unformat (input, "%d", &new_dev_instance))
972     return clib_error_return (0, "new dev instance missing");
973
974   rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance);
975
976   switch (rv)
977     {
978     case 0:
979       break;
980
981     default:
982       return clib_error_return (0, "vnet_interface_name_renumber returned %d",
983                                 rv);
984
985     }
986
987   return 0;
988 }
989
990
991 /* *INDENT-OFF* */
992 VLIB_CLI_COMMAND (renumber_interface_command, static) = {
993   .path = "renumber interface",
994   .short_help = "renumber interface <if-name> <new-dev-instance>",
995   .function = renumber_interface_command_fn,
996 };
997 /* *INDENT-ON* */
998
999 static clib_error_t *
1000 promiscuous_cmd (vlib_main_t * vm,
1001                  unformat_input_t * input, vlib_cli_command_t * cmd)
1002 {
1003   vnet_main_t *vnm = vnet_get_main ();
1004   u32 hw_if_index;
1005   u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL;
1006   ethernet_main_t *em = &ethernet_main;
1007   ethernet_interface_t *eif;
1008
1009   if (unformat (input, "on %U",
1010                 unformat_vnet_hw_interface, vnm, &hw_if_index))
1011     ;
1012   else if (unformat (input, "off %U",
1013                      unformat_ethernet_interface, vnm, &hw_if_index))
1014     flags = 0;
1015   else
1016     return clib_error_return (0, "unknown input `%U'",
1017                               format_unformat_error, input);
1018
1019   eif = ethernet_get_interface (em, hw_if_index);
1020   if (!eif)
1021     return clib_error_return (0, "not supported");
1022
1023   ethernet_set_flags (vnm, hw_if_index, flags);
1024   return 0;
1025 }
1026
1027 /* *INDENT-OFF* */
1028 VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = {
1029   .path = "set interface promiscuous",
1030   .short_help = "set interface promiscuous [on | off] <intfc>",
1031   .function = promiscuous_cmd,
1032 };
1033 /* *INDENT-ON* */
1034
1035 static clib_error_t *
1036 mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1037 {
1038   vnet_main_t *vnm = vnet_get_main ();
1039   u32 hw_if_index, mtu;
1040   u32 flags = ETHERNET_INTERFACE_FLAG_MTU;
1041   ethernet_main_t *em = &ethernet_main;
1042
1043   if (unformat (input, "%d %U", &mtu,
1044                 unformat_vnet_hw_interface, vnm, &hw_if_index))
1045     {
1046       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1047       ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index);
1048
1049       if (!eif)
1050         return clib_error_return (0, "not supported");
1051
1052       if (mtu < hi->min_supported_packet_bytes)
1053         return clib_error_return (0, "Invalid mtu (%d): "
1054                                   "must be >= min pkt bytes (%d)", mtu,
1055                                   hi->min_supported_packet_bytes);
1056
1057       if (mtu > hi->max_supported_packet_bytes)
1058         return clib_error_return (0, "Invalid mtu (%d): must be <= (%d)", mtu,
1059                                   hi->max_supported_packet_bytes);
1060
1061       if (hi->max_packet_bytes != mtu)
1062         {
1063           hi->max_packet_bytes = mtu;
1064           ethernet_set_flags (vnm, hw_if_index, flags);
1065         }
1066     }
1067   else
1068     return clib_error_return (0, "unknown input `%U'",
1069                               format_unformat_error, input);
1070   return 0;
1071 }
1072
1073 /* *INDENT-OFF* */
1074 VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
1075   .path = "set interface mtu",
1076   .short_help = "set interface mtu <value> <intfc>",
1077   .function = mtu_cmd,
1078 };
1079 /* *INDENT-ON* */
1080
1081 static clib_error_t *
1082 set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input,
1083                            vlib_cli_command_t * cmd)
1084 {
1085   vnet_main_t *vnm = vnet_get_main ();
1086   clib_error_t *error = 0;
1087   u32 sw_if_index = ~0;
1088   u64 mac = 0;
1089
1090   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
1091     {
1092       error = clib_error_return (0, "unknown interface `%U'",
1093                                  format_unformat_error, input);
1094       goto done;
1095     }
1096   if (!unformat_user (input, unformat_ethernet_address, &mac))
1097     {
1098       error = clib_error_return (0, "expected mac address `%U'",
1099                                  format_unformat_error, input);
1100       goto done;
1101     }
1102   error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac);
1103 done:
1104   return error;
1105 }
1106
1107 /*?
1108  * The '<em>set interface mac address </em>' command allows to set MAC address of given interface.
1109  * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address
1110  * change are changes of MAC addresses in FIB tables (ipv4 and ipv6).
1111  *
1112  * @cliexpar
1113  * @parblock
1114  * Example of how to change MAC Address of interface:
1115  * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01}
1116  * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02}
1117  * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03}
1118  * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04}
1119  * @endparblock
1120 ?*/
1121 /* *INDENT-OFF* */
1122 VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
1123   .path = "set interface mac address",
1124   .short_help = "set interface mac address <intfc> <mac-address>",
1125   .function = set_interface_mac_address,
1126 };
1127 /* *INDENT-ON* */
1128
1129 static clib_error_t *
1130 set_tag (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
1131 {
1132   vnet_main_t *vnm = vnet_get_main ();
1133   u32 sw_if_index = ~0;
1134   u8 *tag = 0;
1135
1136   if (!unformat (input, "%U %s", unformat_vnet_sw_interface,
1137                  vnm, &sw_if_index, &tag))
1138     return clib_error_return (0, "unknown input `%U'",
1139                               format_unformat_error, input);
1140
1141   vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
1142
1143   return 0;
1144 }
1145
1146 /* *INDENT-OFF* */
1147 VLIB_CLI_COMMAND (set_tag_command, static) = {
1148   .path = "set interface tag",
1149   .short_help = "set interface tag <intfc> <tag>",
1150   .function = set_tag,
1151 };
1152 /* *INDENT-ON* */
1153
1154 static clib_error_t *
1155 clear_tag (vlib_main_t * vm, unformat_input_t * input,
1156            vlib_cli_command_t * cmd)
1157 {
1158   vnet_main_t *vnm = vnet_get_main ();
1159   u32 sw_if_index = ~0;
1160
1161   if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1162     return clib_error_return (0, "unknown input `%U'",
1163                               format_unformat_error, input);
1164
1165   vnet_clear_sw_interface_tag (vnm, sw_if_index);
1166
1167   return 0;
1168 }
1169
1170 /* *INDENT-OFF* */
1171 VLIB_CLI_COMMAND (clear_tag_command, static) = {
1172   .path = "clear interface tag",
1173   .short_help = "clear interface tag <intfc>",
1174   .function = clear_tag,
1175 };
1176 /* *INDENT-ON* */
1177
1178 static clib_error_t *
1179 set_hw_interface_rx_mode (vnet_main_t * vnm, u32 hw_if_index,
1180                           u32 queue_id, vnet_hw_interface_rx_mode mode)
1181 {
1182   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1183   vnet_device_class_t *dev_class =
1184     vnet_get_device_class (vnm, hw->dev_class_index);
1185   clib_error_t *error;
1186   vnet_hw_interface_rx_mode old_mode;
1187   int rv;
1188
1189   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &old_mode);
1190   switch (rv)
1191     {
1192     case 0:
1193       if (old_mode == mode)
1194         return 0;               /* same rx-mode, no change */
1195       break;
1196     case VNET_API_ERROR_INVALID_INTERFACE:
1197       return clib_error_return (0, "invalid interface");
1198     default:
1199       return clib_error_return (0, "unknown error");
1200     }
1201
1202   if (dev_class->rx_mode_change_function)
1203     {
1204       error = dev_class->rx_mode_change_function (vnm, hw_if_index, queue_id,
1205                                                   mode);
1206       if (error)
1207         return (error);
1208     }
1209
1210   rv = vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1211   switch (rv)
1212     {
1213     case 0:
1214       break;
1215     case VNET_API_ERROR_UNSUPPORTED:
1216       return clib_error_return (0, "unsupported");
1217     case VNET_API_ERROR_INVALID_INTERFACE:
1218       return clib_error_return (0, "invalid interface");
1219     default:
1220       return clib_error_return (0, "unknown error");
1221     }
1222
1223   return 0;
1224 }
1225
1226 static clib_error_t *
1227 set_interface_rx_mode (vlib_main_t * vm, unformat_input_t * input,
1228                        vlib_cli_command_t * cmd)
1229 {
1230   clib_error_t *error = 0;
1231   unformat_input_t _line_input, *line_input = &_line_input;
1232   vnet_main_t *vnm = vnet_get_main ();
1233   vnet_hw_interface_t *hw;
1234   u32 hw_if_index = (u32) ~ 0;
1235   u32 queue_id = (u32) ~ 0;
1236   vnet_hw_interface_rx_mode mode = VNET_HW_INTERFACE_RX_MODE_UNKNOWN;
1237   int i;
1238
1239   if (!unformat_user (input, unformat_line_input, line_input))
1240     return 0;
1241
1242   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1243     {
1244       if (unformat
1245           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1246         ;
1247       else if (unformat (line_input, "queue %d", &queue_id))
1248         ;
1249       else if (unformat (line_input, "polling"))
1250         mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
1251       else if (unformat (line_input, "interrupt"))
1252         mode = VNET_HW_INTERFACE_RX_MODE_INTERRUPT;
1253       else if (unformat (line_input, "adaptive"))
1254         mode = VNET_HW_INTERFACE_RX_MODE_ADAPTIVE;
1255       else
1256         {
1257           error = clib_error_return (0, "parse error: '%U'",
1258                                      format_unformat_error, line_input);
1259           unformat_free (line_input);
1260           return error;
1261         }
1262     }
1263
1264   unformat_free (line_input);
1265
1266   if (hw_if_index == (u32) ~ 0)
1267     return clib_error_return (0, "please specify valid interface name");
1268
1269   if (mode == VNET_HW_INTERFACE_RX_MODE_UNKNOWN)
1270     return clib_error_return (0, "please specify valid rx-mode");
1271
1272   hw = vnet_get_hw_interface (vnm, hw_if_index);
1273
1274   if (queue_id == ~0)
1275     for (i = 0; i < vec_len (hw->dq_runtime_index_by_queue); i++)
1276       {
1277         error = set_hw_interface_rx_mode (vnm, hw_if_index, i, mode);
1278         if (error)
1279           break;
1280       }
1281   else
1282     error = set_hw_interface_rx_mode (vnm, hw_if_index, queue_id, mode);
1283
1284   return (error);
1285 }
1286
1287 /*?
1288  * This command is used to assign a given interface, and optionally a
1289  * given queue, to a different thread. If the '<em>queue</em>' is not provided,
1290  * it defaults to 0.
1291  *
1292  * @cliexpar
1293  * Example of how to display the interface placement:
1294  * @cliexstart{show interface rx-placement}
1295  * Thread 1 (vpp_wk_0):
1296  *   GigabitEthernet0/8/0 queue 0
1297  *   GigabitEthernet0/9/0 queue 0
1298  * Thread 2 (vpp_wk_1):
1299  *   GigabitEthernet0/8/0 queue 1
1300  *   GigabitEthernet0/9/0 queue 1
1301  * @cliexend
1302  * Example of how to assign a interface and queue to a thread:
1303  * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1}
1304 ?*/
1305 /* *INDENT-OFF* */
1306 VLIB_CLI_COMMAND (cmd_set_if_rx_mode,static) = {
1307     .path = "set interface rx-mode",
1308     .short_help = "set interface rx-mode <interface> [queue <n>] [polling | interrupt | adaptive]",
1309     .function = set_interface_rx_mode,
1310 };
1311 /* *INDENT-ON* */
1312
1313 static clib_error_t *
1314 show_interface_rx_placement_fn (vlib_main_t * vm, unformat_input_t * input,
1315                                 vlib_cli_command_t * cmd)
1316 {
1317   u8 *s = 0;
1318   vnet_main_t *vnm = vnet_get_main ();
1319   vnet_device_input_runtime_t *rt;
1320   vnet_device_and_queue_t *dq;
1321   vlib_node_t *pn = vlib_get_node_by_name (vm, (u8 *) "device-input");
1322   uword si;
1323   int index = 0;
1324
1325   /* *INDENT-OFF* */
1326   foreach_vlib_main (({
1327     clib_bitmap_foreach (si, pn->sibling_bitmap,
1328       ({
1329         rt = vlib_node_get_runtime_data (this_vlib_main, si);
1330
1331         if (vec_len (rt->devices_and_queues))
1332           s = format (s, "  node %U:\n", format_vlib_node_name, vm, si);
1333
1334         vec_foreach (dq, rt->devices_and_queues)
1335           {
1336             s = format (s, "    %U queue %u (%U)\n",
1337                         format_vnet_sw_if_index_name, vnm, dq->hw_if_index,
1338                         dq->queue_id,
1339                         format_vnet_hw_interface_rx_mode, dq->mode);
1340           }
1341       }));
1342     if (vec_len (s) > 0)
1343       {
1344         vlib_cli_output(vm, "Thread %u (%v):\n%v", index,
1345                         vlib_worker_threads[index].name, s);
1346         vec_reset_length (s);
1347       }
1348     index++;
1349   }));
1350   /* *INDENT-ON* */
1351
1352   vec_free (s);
1353   return 0;
1354 }
1355
1356 /* *INDENT-OFF* */
1357 VLIB_CLI_COMMAND (show_interface_rx_placement, static) = {
1358   .path = "show interface rx-placement",
1359   .short_help = "show interface rx-placement",
1360   .function = show_interface_rx_placement_fn,
1361 };
1362 /* *INDENT-ON* */
1363
1364 static clib_error_t *
1365 set_interface_rx_placement (vlib_main_t * vm, unformat_input_t * input,
1366                             vlib_cli_command_t * cmd)
1367 {
1368   clib_error_t *error = 0;
1369   unformat_input_t _line_input, *line_input = &_line_input;
1370   vnet_main_t *vnm = vnet_get_main ();
1371   vnet_device_main_t *vdm = &vnet_device_main;
1372   vnet_hw_interface_rx_mode mode;
1373   u32 hw_if_index = (u32) ~ 0;
1374   u32 queue_id = (u32) 0;
1375   u32 thread_index = (u32) ~ 0;
1376   int rv;
1377
1378   if (!unformat_user (input, unformat_line_input, line_input))
1379     return 0;
1380
1381   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1382     {
1383       if (unformat
1384           (line_input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
1385         ;
1386       else if (unformat (line_input, "queue %d", &queue_id))
1387         ;
1388       else if (unformat (line_input, "main", &thread_index))
1389         thread_index = 0;
1390       else if (unformat (line_input, "worker %d", &thread_index))
1391         thread_index += vdm->first_worker_thread_index;
1392       else
1393         {
1394           error = clib_error_return (0, "parse error: '%U'",
1395                                      format_unformat_error, line_input);
1396           unformat_free (line_input);
1397           return error;
1398         }
1399     }
1400
1401   unformat_free (line_input);
1402
1403   if (hw_if_index == (u32) ~ 0)
1404     return clib_error_return (0, "please specify valid interface name");
1405
1406   if (thread_index > vdm->last_worker_thread_index)
1407     return clib_error_return (0,
1408                               "please specify valid worker thread or main");
1409
1410   rv = vnet_hw_interface_get_rx_mode (vnm, hw_if_index, queue_id, &mode);
1411
1412   if (rv)
1413     return clib_error_return (0, "not found");
1414
1415   rv = vnet_hw_interface_unassign_rx_thread (vnm, hw_if_index, queue_id);
1416
1417   if (rv)
1418     return clib_error_return (0, "not found");
1419
1420   vnet_hw_interface_assign_rx_thread (vnm, hw_if_index, queue_id,
1421                                       thread_index);
1422   vnet_hw_interface_set_rx_mode (vnm, hw_if_index, queue_id, mode);
1423
1424   return 0;
1425 }
1426
1427 /*?
1428  * This command is used to assign a given interface, and optionally a
1429  * given queue, to a different thread. If the '<em>queue</em>' is not provided,
1430  * it defaults to 0.
1431  *
1432  * @cliexpar
1433  * Example of how to display the interface placement:
1434  * @cliexstart{show interface placement}
1435  * Thread 1 (vpp_wk_0):
1436  *   GigabitEthernet0/8/0 queue 0
1437  *   GigabitEthernet0/9/0 queue 0
1438  * Thread 2 (vpp_wk_1):
1439  *   GigabitEthernet0/8/0 queue 1
1440  *   GigabitEthernet0/9/0 queue 1
1441  * @cliexend
1442  * Example of how to assign a interface and queue to a thread:
1443  * @cliexcmd{set interface placement GigabitEthernet0/8/0 queue 1 thread 1}
1444 ?*/
1445 /* *INDENT-OFF* */
1446 VLIB_CLI_COMMAND (cmd_set_if_rx_placement,static) = {
1447     .path = "set interface rx-placement",
1448     .short_help = "set interface rx-placement <hw-interface> [queue <n>] [thread <n> | main]",
1449     .function = set_interface_rx_placement,
1450 };
1451
1452 /* *INDENT-ON* */
1453 /*
1454  * fd.io coding-style-patch-verification: ON
1455  *
1456  * Local Variables:
1457  * eval: (c-set-style "gnu")
1458  * End:
1459  */