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