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