VPP-346 A swathe of doc fixes
[vpp.git] / vnet / 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
49 static int
50 compare_interface_names (void *a1, void *a2)
51 {
52   u32 *hi1 = a1;
53   u32 *hi2 = a2;
54
55   return vnet_hw_interface_compare (vnet_get_main (), *hi1, *hi2);
56 }
57
58 static clib_error_t *
59 show_or_clear_hw_interfaces (vlib_main_t * vm,
60                              unformat_input_t * input,
61                              vlib_cli_command_t * cmd)
62 {
63   clib_error_t *error = 0;
64   vnet_main_t *vnm = vnet_get_main ();
65   vnet_interface_main_t *im = &vnm->interface_main;
66   vnet_hw_interface_t *hi;
67   u32 hw_if_index, *hw_if_indices = 0;
68   int i, verbose = -1, is_show, show_bond = 0;
69
70   is_show = strstr (cmd->path, "show") != 0;
71   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
72     {
73       /* See if user wants to show a specific interface. */
74       if (unformat
75           (input, "%U", unformat_vnet_hw_interface, vnm, &hw_if_index))
76         vec_add1 (hw_if_indices, hw_if_index);
77
78       /* See if user wants to show an interface with a specific hw_if_index. */
79       else if (unformat (input, "%u", &hw_if_index))
80         vec_add1 (hw_if_indices, hw_if_index);
81
82       else if (unformat (input, "verbose"))
83         verbose = 1;            /* this is also the default */
84
85       else if (unformat (input, "detail"))
86         verbose = 2;
87
88       else if (unformat (input, "brief"))
89         verbose = 0;
90
91       else if (unformat (input, "bond"))
92         {
93           show_bond = 1;
94           if (verbose < 0)
95             verbose = 0;        /* default to brief for link bonding */
96         }
97
98       else
99         {
100           error = clib_error_return (0, "unknown input `%U'",
101                                      format_unformat_error, input);
102           goto done;
103         }
104     }
105
106   /* Gather interfaces. */
107   if (vec_len (hw_if_indices) == 0)
108     pool_foreach (hi, im->hw_interfaces,
109                   vec_add1 (hw_if_indices, hi - im->hw_interfaces));
110
111   if (verbose < 0)
112     verbose = 1;                /* default to verbose (except bond) */
113
114   if (is_show)
115     {
116       /* Sort by name. */
117       vec_sort_with_function (hw_if_indices, compare_interface_names);
118
119       vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm, 0, verbose);
120       for (i = 0; i < vec_len (hw_if_indices); i++)
121         {
122           hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
123           if (show_bond == 0)   /* show all interfaces */
124             vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
125                              hi, verbose);
126           else if ((hi->bond_info) &&
127                    (hi->bond_info != VNET_HW_INTERFACE_BOND_INFO_SLAVE))
128             {                   /* show only bonded interface and all its slave interfaces */
129               int hw_idx;
130               vnet_hw_interface_t *shi;
131               vlib_cli_output (vm, "%U\n", format_vnet_hw_interface, vnm,
132                                hi, verbose);
133
134               /* *INDENT-OFF* */
135               clib_bitmap_foreach (hw_idx, hi->bond_info,
136               ({
137                 shi = vnet_get_hw_interface(vnm, hw_idx);
138                 vlib_cli_output (vm, "%U\n",
139                                  format_vnet_hw_interface, vnm, shi, verbose);
140               }));
141               /* *INDENT-ON* */
142             }
143         }
144     }
145   else
146     {
147       for (i = 0; i < vec_len (hw_if_indices); i++)
148         {
149           vnet_device_class_t *dc;
150
151           hi = vnet_get_hw_interface (vnm, hw_if_indices[i]);
152           dc = vec_elt_at_index (im->device_classes, hi->dev_class_index);
153
154           if (dc->clear_counters)
155             dc->clear_counters (hi->dev_instance);
156         }
157     }
158
159 done:
160   vec_free (hw_if_indices);
161   return error;
162 }
163
164 /* *INDENT-OFF* */
165 VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = {
166   .path = "show hardware-interfaces",
167   .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] [<if-name1> <if-name2> ...]",
168   .function = show_or_clear_hw_interfaces,
169 };
170 /* *INDENT-ON* */
171
172 /* *INDENT-OFF* */
173 VLIB_CLI_COMMAND (clear_hw_interface_counters_command, static) = {
174   .path = "clear hardware-interfaces",
175   .short_help = "Clear hardware interfaces statistics",
176   .function = show_or_clear_hw_interfaces,
177 };
178 /* *INDENT-ON* */
179
180 static int
181 sw_interface_name_compare (void *a1, void *a2)
182 {
183   vnet_sw_interface_t *si1 = a1;
184   vnet_sw_interface_t *si2 = a2;
185
186   return vnet_sw_interface_compare (vnet_get_main (),
187                                     si1->sw_if_index, si2->sw_if_index);
188 }
189
190 static clib_error_t *
191 show_sw_interfaces (vlib_main_t * vm,
192                     unformat_input_t * input, vlib_cli_command_t * cmd)
193 {
194   clib_error_t *error = 0;
195   vnet_main_t *vnm = vnet_get_main ();
196   vnet_interface_main_t *im = &vnm->interface_main;
197   vnet_sw_interface_t *si, *sorted_sis = 0;
198   u8 show_addresses = 0;
199
200   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
201     {
202       u32 sw_if_index;
203
204       /* See if user wants to show specific interface */
205       if (unformat
206           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
207         {
208           si = pool_elt_at_index (im->sw_interfaces, sw_if_index);
209           vec_add1 (sorted_sis, si[0]);
210         }
211       else if (unformat (input, "address") || unformat (input, "addr"))
212         show_addresses = 1;
213       else
214         {
215           error = clib_error_return (0, "unknown input `%U'",
216                                      format_unformat_error, input);
217           goto done;
218         }
219     }
220
221   if (!show_addresses)
222     vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, 0);
223
224   if (vec_len (sorted_sis) == 0)        /* Get all interfaces */
225     {
226       /* Gather interfaces. */
227       sorted_sis =
228         vec_new (vnet_sw_interface_t, pool_elts (im->sw_interfaces));
229       _vec_len (sorted_sis) = 0;
230       pool_foreach (si, im->sw_interfaces, (
231                                              {
232                                              vec_add1 (sorted_sis, si[0]);
233                                              }
234                     ));
235
236       /* Sort by name. */
237       vec_sort_with_function (sorted_sis, sw_interface_name_compare);
238     }
239
240   if (show_addresses)
241     {
242       vec_foreach (si, sorted_sis)
243       {
244         l2input_main_t *l2m = &l2input_main;
245         ip4_main_t *im4 = &ip4_main;
246         ip6_main_t *im6 = &ip6_main;
247         ip_lookup_main_t *lm4 = &im4->lookup_main;
248         ip_lookup_main_t *lm6 = &im6->lookup_main;
249         ip_interface_address_t *ia = 0;
250         ip4_address_t *r4;
251         ip6_address_t *r6;
252         u32 fib_index4 = 0, fib_index6 = 0;
253         ip4_fib_t *fib4;
254         ip6_fib_t *fib6;
255         l2_input_config_t *config;
256
257         if (vec_len (im4->fib_index_by_sw_if_index) > si->sw_if_index)
258           fib_index4 = vec_elt (im4->fib_index_by_sw_if_index,
259                                 si->sw_if_index);
260
261         if (vec_len (im6->fib_index_by_sw_if_index) > si->sw_if_index)
262           fib_index6 = vec_elt (im6->fib_index_by_sw_if_index,
263                                 si->sw_if_index);
264
265         fib4 = vec_elt_at_index (im4->fibs, fib_index4);
266         fib6 = vec_elt_at_index (im6->fibs, fib_index6);
267
268         if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
269           vlib_cli_output
270             (vm, "%U (%s): \n  unnumbered, use %U",
271              format_vnet_sw_if_index_name,
272              vnm, si->sw_if_index,
273              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? "up" : "dn",
274              format_vnet_sw_if_index_name, vnm, si->unnumbered_sw_if_index);
275
276         else
277           {
278             vlib_cli_output (vm, "%U (%s):",
279                              format_vnet_sw_if_index_name,
280                              vnm, si->sw_if_index,
281                              (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
282                              ? "up" : "dn");
283           }
284
285         /* Display any L2 addressing info */
286         vec_validate (l2m->configs, si->sw_if_index);
287         config = vec_elt_at_index (l2m->configs, si->sw_if_index);
288         if (config->bridge)
289           {
290             u32 bd_id = l2input_main.bd_configs[config->bd_index].bd_id;
291             vlib_cli_output (vm, "  l2 bridge bd_id %d%s%d", bd_id,
292                              config->bvi ? " bvi shg " : " shg ",
293                              config->shg);
294           }
295         else if (config->xconnect)
296           {
297             vlib_cli_output (vm, "  l2 xconnect %U",
298                              format_vnet_sw_if_index_name,
299                              vnm, config->output_sw_if_index);
300           }
301
302         /* Display any IP4 addressing info */
303           /* *INDENT-OFF* */
304           foreach_ip_interface_address (lm4, ia, si->sw_if_index,
305                                         1 /* honor unnumbered */,
306           ({
307             r4 = ip_interface_address_get_address (lm4, ia);
308             if (fib4->table_id)
309               {
310                 vlib_cli_output (vm, "  %U/%d table %d",
311                                  format_ip4_address, r4,
312                                  ia->address_length,
313                                  fib4->table_id);
314               }
315             else
316               {
317                 vlib_cli_output (vm, "  %U/%d",
318                                  format_ip4_address, r4,
319                                  ia->address_length);
320               }
321           }));
322           /* *INDENT-ON* */
323
324         /* Display any IP6 addressing info */
325           /* *INDENT-OFF* */
326           foreach_ip_interface_address (lm6, ia, si->sw_if_index,
327                                         1 /* honor unnumbered */,
328           ({
329             r6 = ip_interface_address_get_address (lm6, ia);
330             if (fib6->table_id)
331               {
332                 vlib_cli_output (vm, "  %U/%d table %d",
333                                  format_ip6_address, r6,
334                                  ia->address_length,
335                                  fib6->table_id);
336               }
337             else
338               {
339                 vlib_cli_output (vm, "  %U/%d",
340                                  format_ip6_address, r6,
341                                  ia->address_length);
342               }
343           }));
344           /* *INDENT-ON* */
345       }
346     }
347   else
348     {
349       vec_foreach (si, sorted_sis)
350       {
351         vlib_cli_output (vm, "%U\n", format_vnet_sw_interface, vnm, si);
352       }
353     }
354
355 done:
356   vec_free (sorted_sis);
357   return error;
358 }
359
360 /* *INDENT-OFF* */
361 VLIB_CLI_COMMAND (show_sw_interfaces_command, static) = {
362   .path = "show interfaces",
363   .short_help = "show interfaces [address|addr] [<if-name1> <if-name2> ...]",
364   .function = show_sw_interfaces,
365 };
366 /* *INDENT-ON* */
367
368 /* Root of all interface commands. */
369 /* *INDENT-OFF* */
370 VLIB_CLI_COMMAND (vnet_cli_interface_command, static) = {
371   .path = "interface",
372   .short_help = "Interface commands",
373 };
374 /* *INDENT-ON* */
375
376 /* *INDENT-OFF* */
377 VLIB_CLI_COMMAND (vnet_cli_set_interface_command, static) = {
378   .path = "set interface",
379   .short_help = "Interface commands",
380 };
381 /* *INDENT-ON* */
382
383 static clib_error_t *
384 clear_interface_counters (vlib_main_t * vm,
385                           unformat_input_t * input, vlib_cli_command_t * cmd)
386 {
387   vnet_main_t *vnm = vnet_get_main ();
388   vnet_interface_main_t *im = &vnm->interface_main;
389   vlib_simple_counter_main_t *sm;
390   vlib_combined_counter_main_t *cm;
391   static vnet_main_t **my_vnet_mains;
392   int i, j, n_counters;
393
394   vec_reset_length (my_vnet_mains);
395
396   for (i = 0; i < vec_len (vnet_mains); i++)
397     {
398       if (vnet_mains[i])
399         vec_add1 (my_vnet_mains, vnet_mains[i]);
400     }
401
402   if (vec_len (vnet_mains) == 0)
403     vec_add1 (my_vnet_mains, vnm);
404
405   n_counters = vec_len (im->combined_sw_if_counters);
406
407   for (j = 0; j < n_counters; j++)
408     {
409       for (i = 0; i < vec_len (my_vnet_mains); i++)
410         {
411           im = &my_vnet_mains[i]->interface_main;
412           cm = im->combined_sw_if_counters + j;
413           vlib_clear_combined_counters (cm);
414         }
415     }
416
417   n_counters = vec_len (im->sw_if_counters);
418
419   for (j = 0; j < n_counters; j++)
420     {
421       for (i = 0; i < vec_len (my_vnet_mains); i++)
422         {
423           im = &my_vnet_mains[i]->interface_main;
424           sm = im->sw_if_counters + j;
425           vlib_clear_simple_counters (sm);
426         }
427     }
428
429   return 0;
430 }
431
432 /* *INDENT-OFF* */
433 VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
434   .path = "clear interfaces",
435   .short_help = "Clear interfaces statistics",
436   .function = clear_interface_counters,
437 };
438 /* *INDENT-ON* */
439
440 /**
441  * Parse subinterface names.
442  *
443  * The following subinterface syntax is supported. The first two are for
444  * backwards compatability:
445  *
446  * <intf-name> <id>
447  *     - a subinterface with the name <intf-name>.<id>. The subinterface
448  *       is a single dot1q vlan with vlan id <id> and exact-match semantics.
449  *
450  * <intf-name> <min_id>-<max_id>
451  *     - a set of the above subinterfaces, repeating for each id
452  *       in the range <min_id> to <max_id>
453  *
454  * In the following, exact-match semantics (i.e. the number of vlan tags on the
455  * packet must match the number of tags in the configuration) are used only if
456  * the keyword exact-match is present. Non-exact match is the default.
457  *
458  * <intf-name> <id> dot1q <outer_id> [exact-match]
459  *     - a subinterface with the name <intf-name>.<id>. The subinterface
460  *       is a single dot1q vlan with vlan id <outer_id>.
461  *
462  * <intf-name> <id> dot1q any [exact-match]
463  *     - a subinterface with the name <intf-name>.<id>. The subinterface
464  *       is a single dot1q vlan with any vlan id.
465  *
466  * <intf-name> <id> dot1q <outer_id> inner-dot1q <inner_id> [exact-match]
467  *     - a subinterface with the name <intf-name>.<id>. The subinterface
468  *       is a double dot1q vlan with outer vlan id <outer_id> and inner vlan id
469  *       <inner_id>.
470  *
471  * <intf-name> <id> dot1q <outer_id> inner-dot1q any [exact-match]
472  *     - a subinterface with the name <intf-name>.<id>. The subinterface
473  *       is a double dot1q vlan with outer vlan id <id> and any inner vlan id.
474  *
475  * <intf-name> <id> dot1q any inner-dot1q any [exact-match]
476  *
477  *     - a subinterface with the name <intf-name>.<id>. The subinterface
478  *       is a double dot1q vlan with any outer vlan id and any inner vlan id.
479  *
480  * For each of the above CLI, there is a duplicate that uses the keyword
481  * "dot1ad" in place of the first "dot1q". These interfaces use ethertype
482  * 0x88ad in place of 0x8100 for the outer ethertype. Note that for double-
483  * tagged packets the inner ethertype is always 0x8100. Also note that
484  * the dot1q and dot1ad naming spaces are independent, so it is legal to
485  * have both "Gig3/0/0.1 dot1q 100" and "Gig3/0/0.2 dot1ad 100". For example:
486  *
487  * <intf-name> <id> dot1ad <outer_id> inner-dot1q <inner_id> [exact-match]
488  *     - a subinterface with the name <intf-name>.<id>. The subinterface
489  *       is a double dot1ad vlan with outer vlan id <outer_id> and inner vlan
490  *       id <inner_id>.
491  *
492  * <intf-name> <id> untagged
493  *     - a subinterface with the name <intf-name>.<id>. The subinterface
494  *       has no vlan tags. Only one can be specified per interface.
495  *
496  * <intf-name> <id> default
497  *     - a subinterface with the name <intf-name>.<id>. This is associated
498  *       with a packet that did not match any other configured subinterface
499  *       on this interface. Only one can be specified per interface.
500  */
501
502 static clib_error_t *
503 parse_vlan_sub_interfaces (unformat_input_t * input,
504                            vnet_sw_interface_t * template)
505 {
506   clib_error_t *error = 0;
507   u32 inner_vlan, outer_vlan;
508
509   if (unformat (input, "any inner-dot1q any"))
510     {
511       template->sub.eth.flags.two_tags = 1;
512       template->sub.eth.flags.outer_vlan_id_any = 1;
513       template->sub.eth.flags.inner_vlan_id_any = 1;
514     }
515   else if (unformat (input, "any"))
516     {
517       template->sub.eth.flags.one_tag = 1;
518       template->sub.eth.flags.outer_vlan_id_any = 1;
519     }
520   else if (unformat (input, "%d inner-dot1q any", &outer_vlan))
521     {
522       template->sub.eth.flags.two_tags = 1;
523       template->sub.eth.flags.inner_vlan_id_any = 1;
524       template->sub.eth.outer_vlan_id = outer_vlan;
525     }
526   else if (unformat (input, "%d inner-dot1q %d", &outer_vlan, &inner_vlan))
527     {
528       template->sub.eth.flags.two_tags = 1;
529       template->sub.eth.outer_vlan_id = outer_vlan;
530       template->sub.eth.inner_vlan_id = inner_vlan;
531     }
532   else if (unformat (input, "%d", &outer_vlan))
533     {
534       template->sub.eth.flags.one_tag = 1;
535       template->sub.eth.outer_vlan_id = outer_vlan;
536     }
537   else
538     {
539       error = clib_error_return (0, "expected dot1q config, got `%U'",
540                                  format_unformat_error, input);
541       goto done;
542     }
543
544   if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
545     {
546       if (unformat (input, "exact-match"))
547         {
548           template->sub.eth.flags.exact_match = 1;
549         }
550     }
551
552 done:
553   return error;
554 }
555
556 static clib_error_t *
557 create_sub_interfaces (vlib_main_t * vm,
558                        unformat_input_t * input, vlib_cli_command_t * cmd)
559 {
560   vnet_main_t *vnm = vnet_get_main ();
561   clib_error_t *error = 0;
562   u32 hw_if_index, sw_if_index;
563   vnet_hw_interface_t *hi;
564   u32 id, id_min, id_max;
565   vnet_sw_interface_t template;
566
567   hw_if_index = ~0;
568   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
569     {
570       error = clib_error_return (0, "unknown interface `%U'",
571                                  format_unformat_error, input);
572       goto done;
573     }
574
575   memset (&template, 0, sizeof (template));
576   template.sub.eth.raw_flags = 0;
577
578   if (unformat (input, "%d default", &id_min))
579     {
580       id_max = id_min;
581       template.sub.eth.flags.default_sub = 1;
582     }
583   else if (unformat (input, "%d untagged", &id_min))
584     {
585       id_max = id_min;
586       template.sub.eth.flags.no_tags = 1;
587       template.sub.eth.flags.exact_match = 1;
588     }
589   else if (unformat (input, "%d dot1q", &id_min))
590     {
591       /* parse dot1q config */
592       id_max = id_min;
593       error = parse_vlan_sub_interfaces (input, &template);
594       if (error)
595         goto done;
596     }
597   else if (unformat (input, "%d dot1ad", &id_min))
598     {
599       /* parse dot1ad config */
600       id_max = id_min;
601       template.sub.eth.flags.dot1ad = 1;
602       error = parse_vlan_sub_interfaces (input, &template);
603       if (error)
604         goto done;
605     }
606   else if (unformat (input, "%d-%d", &id_min, &id_max))
607     {
608       template.sub.eth.flags.one_tag = 1;
609       template.sub.eth.outer_vlan_id = id_min;
610       template.sub.eth.flags.exact_match = 1;
611       if (id_min > id_max)
612         goto id_error;
613     }
614   else if (unformat (input, "%d", &id_min))
615     {
616       id_max = id_min;
617       template.sub.eth.flags.one_tag = 1;
618       template.sub.eth.outer_vlan_id = id_min;
619       template.sub.eth.flags.exact_match = 1;
620     }
621   else
622     {
623     id_error:
624       error = clib_error_return (0, "expected ID or ID MIN-MAX, got `%U'",
625                                  format_unformat_error, input);
626       goto done;
627     }
628
629   hi = vnet_get_hw_interface (vnm, hw_if_index);
630
631   if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
632     {
633       error =
634         clib_error_return (0,
635                            "not allowed as %v belong to a BondEthernet interface",
636                            hi->name);
637       goto done;
638     }
639
640   for (id = id_min; id <= id_max; id++)
641     {
642       uword *p;
643       vnet_interface_main_t *im = &vnm->interface_main;
644       u64 sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
645       u64 *kp;
646
647       p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
648       if (p)
649         {
650           if (CLIB_DEBUG > 0)
651             clib_warning ("sup sw_if_index %d, sub id %d already exists\n",
652                           hi->sw_if_index, id);
653           continue;
654         }
655
656       kp = clib_mem_alloc (sizeof (*kp));
657       *kp = sup_and_sub_key;
658
659       template.type = VNET_SW_INTERFACE_TYPE_SUB;
660       template.sup_sw_if_index = hi->sw_if_index;
661       template.sub.id = id;
662       error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
663       if (error)
664         goto done;
665
666       hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index);
667       hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
668       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
669                        vnet_get_main (), sw_if_index);
670     }
671
672 done:
673   return error;
674 }
675
676 /* *INDENT-OFF* */
677 VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = {
678   .path = "create sub-interface",
679   .short_help = "create sub-interfaces <nn>[-<nn>] [dot1q|dot1ad|default|untagged]",
680   .function = create_sub_interfaces,
681 };
682 /* *INDENT-ON* */
683
684 static clib_error_t *
685 set_state (vlib_main_t * vm,
686            unformat_input_t * input, vlib_cli_command_t * cmd)
687 {
688   vnet_main_t *vnm = vnet_get_main ();
689   clib_error_t *error;
690   u32 sw_if_index, flags;
691
692   sw_if_index = ~0;
693   if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
694     {
695       error = clib_error_return (0, "unknown interface `%U'",
696                                  format_unformat_error, input);
697       goto done;
698     }
699
700   if (!unformat (input, "%U", unformat_vnet_sw_interface_flags, &flags))
701     {
702       error = clib_error_return (0, "unknown flags `%U'",
703                                  format_unformat_error, input);
704       goto done;
705     }
706
707   error = vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
708   if (error)
709     goto done;
710
711 done:
712   return error;
713 }
714
715 /* *INDENT-OFF* */
716 VLIB_CLI_COMMAND (set_state_command, static) = {
717   .path = "set interface state",
718   .short_help = "Set interface state",
719   .function = set_state,
720 };
721 /* *INDENT-ON* */
722
723 static clib_error_t *
724 set_unnumbered (vlib_main_t * vm,
725                 unformat_input_t * input, vlib_cli_command_t * cmd)
726 {
727   vnet_main_t *vnm = vnet_get_main ();
728   u32 unnumbered_sw_if_index;
729   u32 inherit_from_sw_if_index;
730   vnet_sw_interface_t *si;
731   int is_set = 0;
732   int is_del = 0;
733
734   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
735     {
736
737       if (unformat (input, "%U use %U",
738                     unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
739                     unformat_vnet_sw_interface, vnm,
740                     &inherit_from_sw_if_index))
741         is_set = 1;
742       else if (unformat (input, "del %U",
743                          unformat_vnet_sw_interface,
744                          vnm, &unnumbered_sw_if_index))
745         is_del = 1;
746       else
747         {
748           if (is_set || is_del)
749             break;
750           else
751             return clib_error_return
752               (0, "parse error '%U'", format_unformat_error, input);
753         }
754     }
755
756   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
757   if (is_del)
758     {
759       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
760       si->unnumbered_sw_if_index = (u32) ~ 0;
761     }
762   else
763     {
764       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
765       si->unnumbered_sw_if_index = inherit_from_sw_if_index;
766     }
767
768   return 0;
769 }
770
771 /* *INDENT-OFF* */
772 VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
773   .path = "set interface unnumbered",
774   .short_help = "set interface unnumbered [<intfc> use <intfc>][del <intfc>]",
775   .function = set_unnumbered,
776 };
777 /* *INDENT-ON* */
778
779
780
781 static clib_error_t *
782 set_hw_class (vlib_main_t * vm,
783               unformat_input_t * input, vlib_cli_command_t * cmd)
784 {
785   vnet_main_t *vnm = vnet_get_main ();
786   vnet_interface_main_t *im = &vnm->interface_main;
787   clib_error_t *error;
788   u32 hw_if_index, hw_class_index;
789
790   hw_if_index = ~0;
791   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
792     {
793       error = clib_error_return (0, "unknown hardware interface `%U'",
794                                  format_unformat_error, input);
795       goto done;
796     }
797
798   if (!unformat_user (input, unformat_hash_string,
799                       im->hw_interface_class_by_name, &hw_class_index))
800     {
801       error = clib_error_return (0, "unknown hardware class `%U'",
802                                  format_unformat_error, input);
803       goto done;
804     }
805
806   error = vnet_hw_interface_set_class (vnm, hw_if_index, hw_class_index);
807   if (error)
808     goto done;
809
810 done:
811   return error;
812 }
813
814 /* *INDENT-OFF* */
815 VLIB_CLI_COMMAND (set_hw_class_command, static) = {
816   .path = "set interface hw-class",
817   .short_help = "Set interface hardware class",
818   .function = set_hw_class,
819 };
820 /* *INDENT-ON* */
821
822 static clib_error_t *
823 vnet_interface_cli_init (vlib_main_t * vm)
824 {
825   return 0;
826 }
827
828 VLIB_INIT_FUNCTION (vnet_interface_cli_init);
829
830 static clib_error_t *
831 renumber_interface_command_fn (vlib_main_t * vm,
832                                unformat_input_t * input,
833                                vlib_cli_command_t * cmd)
834 {
835   u32 hw_if_index;
836   u32 new_dev_instance;
837   vnet_main_t *vnm = vnet_get_main ();
838   int rv;
839
840   if (!unformat_user (input, unformat_vnet_hw_interface, vnm, &hw_if_index))
841     return clib_error_return (0, "unknown hardware interface `%U'",
842                               format_unformat_error, input);
843
844   if (!unformat (input, "%d", &new_dev_instance))
845     return clib_error_return (0, "new dev instance missing");
846
847   rv = vnet_interface_name_renumber (hw_if_index, new_dev_instance);
848
849   switch (rv)
850     {
851     case 0:
852       break;
853
854     default:
855       return clib_error_return (0, "vnet_interface_name_renumber returned %d",
856                                 rv);
857
858     }
859
860   return 0;
861 }
862
863
864 /* *INDENT-OFF* */
865 VLIB_CLI_COMMAND (renumber_interface_command, static) = {
866   .path = "renumber interface",
867   .short_help = "renumber interface <if-name> <new-dev-instance>",
868   .function = renumber_interface_command_fn,
869 };
870 /* *INDENT-ON* */
871
872 static clib_error_t *
873 promiscuous_cmd (vlib_main_t * vm,
874                  unformat_input_t * input, vlib_cli_command_t * cmd)
875 {
876   vnet_main_t *vnm = vnet_get_main ();
877   u32 hw_if_index;
878   u32 flags = ETHERNET_INTERFACE_FLAG_ACCEPT_ALL;
879   ethernet_main_t *em = &ethernet_main;
880   ethernet_interface_t *eif;
881
882   if (unformat (input, "on %U",
883                 unformat_vnet_hw_interface, vnm, &hw_if_index))
884     ;
885   else if (unformat (input, "off %U",
886                      unformat_ethernet_interface, vnm, &hw_if_index))
887     flags = 0;
888   else
889     return clib_error_return (0, "unknown input `%U'",
890                               format_unformat_error, input);
891
892   eif = ethernet_get_interface (em, hw_if_index);
893   if (!eif)
894     return clib_error_return (0, "not supported");
895
896   ethernet_set_flags (vnm, hw_if_index, flags);
897   return 0;
898 }
899
900 /* *INDENT-OFF* */
901 VLIB_CLI_COMMAND (set_interface_promiscuous_cmd, static) = {
902   .path = "set interface promiscuous",
903   .short_help = "set interface promiscuous [on | off] <intfc>",
904   .function = promiscuous_cmd,
905 };
906 /* *INDENT-ON* */
907
908 static clib_error_t *
909 mtu_cmd (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
910 {
911   vnet_main_t *vnm = vnet_get_main ();
912   u32 hw_if_index, mtu;
913   u32 flags = ETHERNET_INTERFACE_FLAG_MTU;
914   ethernet_main_t *em = &ethernet_main;
915
916   if (unformat (input, "%d %U", &mtu,
917                 unformat_vnet_hw_interface, vnm, &hw_if_index))
918     {
919       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
920       ethernet_interface_t *eif = ethernet_get_interface (em, hw_if_index);
921
922       if (!eif)
923         return clib_error_return (0, "not supported");
924
925       if (mtu < hi->min_supported_packet_bytes)
926         return clib_error_return (0, "Invalid mtu (%d): "
927                                   "must be >= min pkt bytes (%d)", mtu,
928                                   hi->min_supported_packet_bytes);
929
930       if (mtu > hi->max_supported_packet_bytes)
931         return clib_error_return (0, "Invalid mtu (%d): must be <= (%d)", mtu,
932                                   hi->max_supported_packet_bytes);
933
934       if (hi->max_packet_bytes != mtu)
935         {
936           hi->max_packet_bytes = mtu;
937           ethernet_set_flags (vnm, hw_if_index, flags);
938         }
939     }
940   else
941     return clib_error_return (0, "unknown input `%U'",
942                               format_unformat_error, input);
943   return 0;
944 }
945
946 /* *INDENT-OFF* */
947 VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
948   .path = "set interface mtu",
949   .short_help = "set interface mtu <value> <intfc>",
950   .function = mtu_cmd,
951 };
952 /* *INDENT-ON* */
953
954 /*
955  * fd.io coding-style-patch-verification: ON
956  *
957  * Local Variables:
958  * eval: (c-set-style "gnu")
959  * End:
960  */