bond: send gratuitous arp when the active slave went down in active-backup mode
[vpp.git] / src / vnet / bonding / cli.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #include <stdint.h>
19 #include <vlib/vlib.h>
20 #include <vlib/unix/unix.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/bonding/node.h>
23
24 void
25 bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
26 {
27   bond_main_t *bm = &bond_main;
28   bond_if_t *bif;
29   int i;
30   uword p;
31   u8 switching_active = 0;
32
33   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
34   clib_spinlock_lock_if_init (&bif->lockp);
35   vec_foreach_index (i, bif->active_slaves)
36   {
37     p = *vec_elt_at_index (bif->active_slaves, i);
38     if (p == sif->sw_if_index)
39       {
40         /* Are we disabling the very 1st slave? */
41         if (sif->sw_if_index == *vec_elt_at_index (bif->active_slaves, 0))
42           switching_active = 1;
43
44         vec_del1 (bif->active_slaves, i);
45         hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index);
46
47         /* We got a new slave just becoming active? */
48         if ((vec_len (bif->active_slaves) >= 1) &&
49             (bif->mode == BOND_MODE_ACTIVE_BACKUP) && switching_active)
50           vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
51                                      BOND_SEND_GARP_NA, bif->hw_if_index);
52         break;
53       }
54   }
55   clib_spinlock_unlock_if_init (&bif->lockp);
56 }
57
58 void
59 bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
60 {
61   bond_if_t *bif;
62   bond_main_t *bm = &bond_main;
63
64   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
65   clib_spinlock_lock_if_init (&bif->lockp);
66   if (!hash_get (bif->active_slave_by_sw_if_index, sif->sw_if_index))
67     {
68       hash_set (bif->active_slave_by_sw_if_index, sif->sw_if_index,
69                 sif->sw_if_index);
70       vec_add1 (bif->active_slaves, sif->sw_if_index);
71
72       /* First slave becomes active? */
73       if ((vec_len (bif->active_slaves) == 1) &&
74           (bif->mode == BOND_MODE_ACTIVE_BACKUP))
75         vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
76                                    BOND_SEND_GARP_NA, bif->hw_if_index);
77     }
78   clib_spinlock_unlock_if_init (&bif->lockp);
79 }
80
81 int
82 bond_dump_ifs (bond_interface_details_t ** out_bondifs)
83 {
84   vnet_main_t *vnm = vnet_get_main ();
85   bond_main_t *bm = &bond_main;
86   bond_if_t *bif;
87   vnet_hw_interface_t *hi;
88   bond_interface_details_t *r_bondifs = NULL;
89   bond_interface_details_t *bondif = NULL;
90
91   /* *INDENT-OFF* */
92   pool_foreach (bif, bm->interfaces,
93     vec_add2(r_bondifs, bondif, 1);
94     memset (bondif, 0, sizeof (*bondif));
95     bondif->sw_if_index = bif->sw_if_index;
96     hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
97     clib_memcpy(bondif->interface_name, hi->name,
98                 MIN (ARRAY_LEN (bondif->interface_name) - 1,
99                      strlen ((const char *) hi->name)));
100     bondif->mode = bif->mode;
101     bondif->lb = bif->lb;
102     bondif->active_slaves = vec_len (bif->active_slaves);
103     bondif->slaves = vec_len (bif->slaves);
104   );
105   /* *INDENT-ON* */
106
107   *out_bondifs = r_bondifs;
108
109   return 0;
110 }
111
112 int
113 bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
114                      u32 bond_sw_if_index)
115 {
116   vnet_main_t *vnm = vnet_get_main ();
117   bond_if_t *bif;
118   vnet_hw_interface_t *hi;
119   vnet_sw_interface_t *sw;
120   slave_interface_details_t *r_slaveifs = NULL;
121   slave_interface_details_t *slaveif = NULL;
122   u32 *sw_if_index = NULL;
123   slave_if_t *sif;
124
125   bif = bond_get_master_by_sw_if_index (bond_sw_if_index);
126   if (!bif)
127     return 1;
128
129   vec_foreach (sw_if_index, bif->slaves)
130   {
131     vec_add2 (r_slaveifs, slaveif, 1);
132     memset (slaveif, 0, sizeof (*slaveif));
133     sif = bond_get_slave_by_sw_if_index (*sw_if_index);
134     if (sif)
135       {
136         sw = vnet_get_sw_interface (vnm, sif->sw_if_index);
137         hi = vnet_get_hw_interface (vnm, sw->hw_if_index);
138         clib_memcpy (slaveif->interface_name, hi->name,
139                      MIN (ARRAY_LEN (slaveif->interface_name) - 1,
140                           strlen ((const char *) hi->name)));
141         slaveif->sw_if_index = sif->sw_if_index;
142         slaveif->is_passive = sif->is_passive;
143         slaveif->is_long_timeout = sif->is_long_timeout;
144       }
145   }
146   *out_slaveifs = r_slaveifs;
147
148   return 0;
149 }
150
151 static void
152 bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif)
153 {
154   bond_main_t *bm = &bond_main;
155   vnet_main_t *vnm = vnet_get_main ();
156   int i;
157   vnet_hw_interface_t *sif_hw;
158
159   sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
160
161   bif->port_number_bitmap =
162     clib_bitmap_set (bif->port_number_bitmap,
163                      ntohs (sif->actor_admin.port_number) - 1, 0);
164   bm->slave_by_sw_if_index[sif->sw_if_index] = 0;
165   vec_free (sif->last_marker_pkt);
166   vec_free (sif->last_rx_pkt);
167   vec_foreach_index (i, bif->slaves)
168   {
169     uword p = *vec_elt_at_index (bif->slaves, i);
170     if (p == sif->sw_if_index)
171       {
172         vec_del1 (bif->slaves, i);
173         break;
174       }
175   }
176
177   bond_disable_collecting_distributing (vm, sif);
178
179   /* Put back the old mac */
180   vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
181                                         sif->persistent_hw_address);
182
183   pool_put (bm->neighbors, sif);
184
185   if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
186     (*bm->lacp_enable_disable) (vm, bif, sif, 0);
187 }
188
189 int
190 bond_delete_if (vlib_main_t * vm, u32 sw_if_index)
191 {
192   bond_main_t *bm = &bond_main;
193   vnet_main_t *vnm = vnet_get_main ();
194   bond_if_t *bif;
195   slave_if_t *sif;
196   vnet_hw_interface_t *hw;
197   u32 *sif_sw_if_index;
198   u32 thread_index;
199   u32 **s_list = 0;
200   u32 i;
201
202   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
203   if (hw == NULL || bond_dev_class.index != hw->dev_class_index)
204     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
205
206   bif = bond_get_master_by_dev_instance (hw->dev_instance);
207
208   vec_foreach (sif_sw_if_index, bif->slaves)
209   {
210     vec_add1 (s_list, sif_sw_if_index);
211   }
212
213   for (i = 0; i < vec_len (s_list); i++)
214     {
215       sif_sw_if_index = s_list[i];
216       sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index);
217       if (sif)
218         bond_delete_neighbor (vm, bif, sif);
219     }
220
221   if (s_list)
222     vec_free (s_list);
223
224   /* bring down the interface */
225   vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
226   vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
227
228   ethernet_delete_interface (vnm, bif->hw_if_index);
229
230   clib_bitmap_free (bif->port_number_bitmap);
231   hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
232   for (thread_index = 0; thread_index < vlib_get_thread_main ()->n_vlib_mains;
233        thread_index++)
234     {
235       vec_free (bif->per_thread_info[thread_index].frame);
236     }
237   vec_free (bif->per_thread_info);
238   memset (bif, 0, sizeof (*bif));
239   pool_put (bm->interfaces, bif);
240
241   return 0;
242 }
243
244 void
245 bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
246 {
247   bond_main_t *bm = &bond_main;
248   vnet_main_t *vnm = vnet_get_main ();
249   vnet_sw_interface_t *sw;
250   bond_if_t *bif;
251
252   if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
253     {
254       args->rv = VNET_API_ERROR_FEATURE_DISABLED;
255       args->error = clib_error_return (0, "LACP plugin is not loaded");
256       return;
257     }
258   if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
259     {
260       args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
261       args->error = clib_error_return (0, "Invalid mode");
262       return;
263     }
264   if (args->lb > BOND_LB_L23)
265     {
266       args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
267       args->error = clib_error_return (0, "Invalid load-balance");
268       return;
269     }
270   pool_get (bm->interfaces, bif);
271   memset (bif, 0, sizeof (*bif));
272   bif->dev_instance = bif - bm->interfaces;
273   bif->lb = args->lb;
274   bif->mode = args->mode;
275
276   // Special load-balance mode used for rr and bc
277   if (bif->mode == BOND_MODE_ROUND_ROBIN)
278     bif->lb = BOND_LB_RR;
279   else if (bif->mode == BOND_MODE_BROADCAST)
280     bif->lb = BOND_LB_BC;
281
282   bif->use_custom_mac = args->hw_addr_set;
283   if (!args->hw_addr_set)
284     {
285       f64 now = vlib_time_now (vm);
286       u32 rnd;
287       rnd = (u32) (now * 1e6);
288       rnd = random_u32 (&rnd);
289
290       memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
291       args->hw_addr[0] = 2;
292       args->hw_addr[1] = 0xfe;
293     }
294   memcpy (bif->hw_address, args->hw_addr, 6);
295   args->error = ethernet_register_interface
296     (vnm, bond_dev_class.index, bif - bm->interfaces /* device instance */ ,
297      bif->hw_address /* ethernet address */ ,
298      &bif->hw_if_index, 0 /* flag change */ );
299
300   if (args->error)
301     {
302       args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
303       pool_put (bm->interfaces, bif);
304       return;
305     }
306
307   sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
308   bif->sw_if_index = sw->sw_if_index;
309   bif->group = bif->sw_if_index;
310   vec_validate_aligned (bif->per_thread_info,
311                         vlib_get_thread_main ()->n_vlib_mains - 1,
312                         CLIB_CACHE_LINE_BYTES);
313   if (vlib_get_thread_main ()->n_vlib_mains > 1)
314     clib_spinlock_init (&bif->lockp);
315
316   vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
317                                VNET_HW_INTERFACE_FLAG_LINK_UP);
318
319   hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
320
321   // for return
322   args->sw_if_index = bif->sw_if_index;
323 }
324
325 static clib_error_t *
326 bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
327                         vlib_cli_command_t * cmd)
328 {
329   unformat_input_t _line_input, *line_input = &_line_input;
330   bond_create_if_args_t args = { 0 };
331   u8 mode_is_set = 0;
332
333   /* Get a line of input. */
334   if (!unformat_user (input, unformat_line_input, line_input))
335     return clib_error_return (0, "Missing required arguments.");
336
337   args.mode = -1;
338   args.lb = BOND_LB_L2;
339   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
340     {
341       if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
342         mode_is_set = 1;
343       else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
344                && unformat (line_input, "load-balance %U",
345                             unformat_bond_load_balance, &args.lb))
346         ;
347       else if (unformat (line_input, "hw-addr %U",
348                          unformat_ethernet_address, args.hw_addr))
349         args.hw_addr_set = 1;
350       else
351         return clib_error_return (0, "unknown input `%U'",
352                                   format_unformat_error, input);
353     }
354   unformat_free (line_input);
355
356   if (mode_is_set == 0)
357     return clib_error_return (0, "Missing bond mode");
358
359   bond_create_if (vm, &args);
360
361   return args.error;
362 }
363
364 /* *INDENT-OFF* */
365 VLIB_CLI_COMMAND (bond_create_command, static) = {
366   .path = "create bond",
367   .short_help = "create bond mode {round-robin | active-backup | broadcast | "
368     "{lacp | xor} [load-balance { l2 | l23 | l34 }]} [hw-addr <mac-address>]",
369   .function = bond_create_command_fn,
370 };
371 /* *INDENT-ON* */
372
373 static clib_error_t *
374 bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
375                         vlib_cli_command_t * cmd)
376 {
377   unformat_input_t _line_input, *line_input = &_line_input;
378   u32 sw_if_index = ~0;
379   vnet_main_t *vnm = vnet_get_main ();
380   int rv;
381
382   /* Get a line of input. */
383   if (!unformat_user (input, unformat_line_input, line_input))
384     return clib_error_return (0, "Missing <interface>");
385
386   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
387     {
388       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
389         ;
390       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
391                          vnm, &sw_if_index))
392         ;
393       else
394         return clib_error_return (0, "unknown input `%U'",
395                                   format_unformat_error, input);
396     }
397   unformat_free (line_input);
398
399   if (sw_if_index == ~0)
400     return clib_error_return (0,
401                               "please specify interface name or sw_if_index");
402
403   rv = bond_delete_if (vm, sw_if_index);
404   if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
405     return clib_error_return (0, "not a bond interface");
406   else if (rv != 0)
407     return clib_error_return (0, "error on deleting bond interface");
408
409   return 0;
410 }
411
412 /* *INDENT-OFF* */
413 VLIB_CLI_COMMAND (bond_delete__command, static) =
414 {
415   .path = "delete bond",
416   .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
417   .function = bond_delete_command_fn,
418 };
419 /* *INDENT-ON* */
420
421 void
422 bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args)
423 {
424   bond_main_t *bm = &bond_main;
425   vnet_main_t *vnm = vnet_get_main ();
426   bond_if_t *bif;
427   slave_if_t *sif;
428   vnet_interface_main_t *im = &vnm->interface_main;
429   vnet_hw_interface_t *bif_hw, *sif_hw;
430   vnet_sw_interface_t *sw;
431
432   bif = bond_get_master_by_sw_if_index (args->group);
433   if (!bif)
434     {
435       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
436       args->error = clib_error_return (0, "bond interface not found");
437       return;
438     }
439   // make sure the interface is not already enslaved
440   if (bond_get_slave_by_sw_if_index (args->slave))
441     {
442       args->rv = VNET_API_ERROR_VALUE_EXIST;
443       args->error = clib_error_return (0, "interface was already enslaved");
444       return;
445     }
446   sif_hw = vnet_get_sup_hw_interface (vnm, args->slave);
447   if (sif_hw->dev_class_index == bond_dev_class.index)
448     {
449       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
450       args->error =
451         clib_error_return (0, "bond interface cannot be enslaved");
452       return;
453     }
454   pool_get (bm->neighbors, sif);
455   memset (sif, 0, sizeof (*sif));
456   clib_spinlock_init (&sif->lockp);
457   sw = pool_elt_at_index (im->sw_interfaces, args->slave);
458   sif->port_enabled = sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
459   sif->sw_if_index = sw->sw_if_index;
460   sif->hw_if_index = sw->hw_if_index;
461   sif->packet_template_index = (u8) ~ 0;
462   sif->is_passive = args->is_passive;
463   sif->group = args->group;
464   sif->bif_dev_instance = bif->dev_instance;
465   sif->mode = bif->mode;
466
467   sif->is_long_timeout = args->is_long_timeout;
468   if (args->is_long_timeout)
469     sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
470   else
471     sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
472
473   vec_validate_aligned (bm->slave_by_sw_if_index, sif->sw_if_index,
474                         CLIB_CACHE_LINE_BYTES);
475   /*
476    * sif - bm->neighbors may be 0
477    * Left shift it by 1 bit to distinguish the valid entry that we actually
478    * store from the null entries
479    */
480   bm->slave_by_sw_if_index[sif->sw_if_index] =
481     (uword) (((sif - bm->neighbors) << 1) | 1);
482   vec_add1 (bif->slaves, sif->sw_if_index);
483
484   sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
485
486   /* Save the old mac */
487   memcpy (sif->persistent_hw_address, sif_hw->hw_address, 6);
488   bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
489   if (bif->use_custom_mac)
490     {
491       vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
492                                             bif->hw_address);
493     }
494   else
495     {
496       // bond interface gets the mac address from the first slave
497       if (vec_len (bif->slaves) == 1)
498         {
499           memcpy (bif->hw_address, sif_hw->hw_address, 6);
500           vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index,
501                                                 sif_hw->hw_address);
502         }
503       else
504         {
505           // subsequent slaves gets the mac address of the bond interface
506           vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
507                                                 bif->hw_address);
508         }
509     }
510
511   if (bif_hw->l2_if_count)
512     {
513       ethernet_set_flags (vnm, sif_hw->hw_if_index,
514                           ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
515       /* ensure all packets go to ethernet-input */
516       ethernet_set_rx_redirect (vnm, sif_hw, 1);
517     }
518
519   if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
520     {
521       (*bm->lacp_enable_disable) (vm, bif, sif, 1);
522     }
523   else
524     {
525       bond_enable_collecting_distributing (vm, sif);
526     }
527
528   args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
529                                           sif_hw->hw_if_index, 1, 0, 0);
530
531   if (args->rv)
532     {
533       args->error =
534         clib_error_return (0,
535                            "Error encountered on input feature arc enable");
536     }
537 }
538
539 static clib_error_t *
540 enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
541                               vlib_cli_command_t * cmd)
542 {
543   bond_enslave_args_t args = { 0 };
544   unformat_input_t _line_input, *line_input = &_line_input;
545   vnet_main_t *vnm = vnet_get_main ();
546
547   /* Get a line of input. */
548   if (!unformat_user (input, unformat_line_input, line_input))
549     return clib_error_return (0, "Missing required arguments.");
550
551   args.slave = ~0;
552   args.group = ~0;
553   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
554     {
555       if (unformat (line_input, "%U %U",
556                     unformat_vnet_sw_interface, vnm, &args.group,
557                     unformat_vnet_sw_interface, vnm, &args.slave))
558         ;
559       else if (unformat (line_input, "passive"))
560         args.is_passive = 1;
561       else if (unformat (line_input, "long-timeout"))
562         args.is_long_timeout = 1;
563       else
564         {
565           args.error = clib_error_return (0, "unknown input `%U'",
566                                           format_unformat_error, input);
567           break;
568         }
569     }
570   unformat_free (line_input);
571
572   if (args.error)
573     return args.error;
574   if (args.group == ~0)
575     return clib_error_return (0, "Missing bond interface");
576   if (args.slave == ~0)
577     return clib_error_return (0, "please specify valid slave interface name");
578
579   bond_enslave (vm, &args);
580
581   return args.error;
582 }
583
584 /* *INDENT-OFF* */
585 VLIB_CLI_COMMAND (enslave_interface_command, static) = {
586   .path = "bond add",
587   .short_help = "bond add <BondEthernetx> <slave-interface> "
588                 "[passive] [long-timeout]",
589   .function = enslave_interface_command_fn,
590 };
591 /* *INDENT-ON* */
592
593 void
594 bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args)
595 {
596   bond_if_t *bif;
597   slave_if_t *sif;
598
599   sif = bond_get_slave_by_sw_if_index (args->slave);
600   if (!sif)
601     {
602       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
603       args->error = clib_error_return (0, "interface was not enslaved");
604       return;
605     }
606   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
607   bond_delete_neighbor (vm, bif, sif);
608 }
609
610 static clib_error_t *
611 detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
612                              vlib_cli_command_t * cmd)
613 {
614   bond_detach_slave_args_t args = { 0 };
615   unformat_input_t _line_input, *line_input = &_line_input;
616   vnet_main_t *vnm = vnet_get_main ();
617
618   /* Get a line of input. */
619   if (!unformat_user (input, unformat_line_input, line_input))
620     return clib_error_return (0, "Missing required arguments.");
621
622   args.slave = ~0;
623   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
624     {
625       if (unformat (line_input, "%U",
626                     unformat_vnet_sw_interface, vnm, &args.slave))
627         ;
628       else
629         {
630           args.error = clib_error_return (0, "unknown input `%U'",
631                                           format_unformat_error, input);
632           break;
633         }
634     }
635   unformat_free (line_input);
636
637   if (args.error)
638     return args.error;
639   if (args.slave == ~0)
640     return clib_error_return (0, "please specify valid slave interface name");
641
642   bond_detach_slave (vm, &args);
643
644   return args.error;
645 }
646
647 /* *INDENT-OFF* */
648 VLIB_CLI_COMMAND (detach_interface_command, static) = {
649   .path = "bond del",
650   .short_help = "bond del <slave-interface>",
651   .function = detach_interface_command_fn,
652 };
653 /* *INDENT-ON* */
654
655 static void
656 show_bond (vlib_main_t * vm)
657 {
658   bond_main_t *bm = &bond_main;
659   bond_if_t *bif;
660
661   vlib_cli_output (vm, "%-16s %-12s %-12s %-13s %-14s %s",
662                    "interface name", "sw_if_index", "mode",
663                    "load balance", "active slaves", "slaves");
664
665   /* *INDENT-OFF* */
666   pool_foreach (bif, bm->interfaces,
667   ({
668     vlib_cli_output (vm, "%-16U %-12d %-12U %-13U %-14u %u",
669                      format_bond_interface_name, bif->dev_instance,
670                      bif->sw_if_index, format_bond_mode, bif->mode,
671                      format_bond_load_balance, bif->lb,
672                      vec_len (bif->active_slaves), vec_len (bif->slaves));
673   }));
674   /* *INDENT-ON* */
675 }
676
677 static void
678 show_bond_details (vlib_main_t * vm)
679 {
680   bond_main_t *bm = &bond_main;
681   bond_if_t *bif;
682   u32 *sw_if_index;
683
684   /* *INDENT-OFF* */
685   pool_foreach (bif, bm->interfaces,
686   ({
687     vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
688     vlib_cli_output (vm, "  mode: %U",
689                      format_bond_mode, bif->mode);
690     vlib_cli_output (vm, "  load balance: %U",
691                      format_bond_load_balance, bif->lb);
692     if (bif->mode == BOND_MODE_ROUND_ROBIN)
693       vlib_cli_output (vm, "  last xmit slave index: %u",
694                        bif->lb_rr_last_index);
695     vlib_cli_output (vm, "  number of active slaves: %d",
696                      vec_len (bif->active_slaves));
697     vec_foreach (sw_if_index, bif->active_slaves)
698       {
699         vlib_cli_output (vm, "    %U", format_vnet_sw_if_index_name,
700                          vnet_get_main (), *sw_if_index);
701       }
702     vlib_cli_output (vm, "  number of slaves: %d", vec_len (bif->slaves));
703     vec_foreach (sw_if_index, bif->slaves)
704       {
705         vlib_cli_output (vm, "    %U", format_vnet_sw_if_index_name,
706                          vnet_get_main (), *sw_if_index);
707       }
708     vlib_cli_output (vm, "  device instance: %d", bif->dev_instance);
709     vlib_cli_output (vm, "  sw_if_index: %d", bif->sw_if_index);
710     vlib_cli_output (vm, "  hw_if_index: %d", bif->hw_if_index);
711   }));
712   /* *INDENT-ON* */
713 }
714
715 static clib_error_t *
716 show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
717               vlib_cli_command_t * cmd)
718 {
719   u8 details = 0;
720
721   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
722     {
723       if (unformat (input, "details"))
724         details = 1;
725       else
726         {
727           return clib_error_return (0, "unknown input `%U'",
728                                     format_unformat_error, input);
729         }
730     }
731
732   if (details)
733     show_bond_details (vm);
734   else
735     show_bond (vm);
736
737   return 0;
738 }
739
740 /* *INDENT-OFF* */
741 VLIB_CLI_COMMAND (show_bond_command, static) = {
742   .path = "show bond",
743   .short_help = "show bond [details]",
744   .function = show_bond_fn,
745 };
746 /* *INDENT-ON* */
747
748 clib_error_t *
749 bond_cli_init (vlib_main_t * vm)
750 {
751   bond_main_t *bm = &bond_main;
752
753   bm->vlib_main = vm;
754   bm->vnet_main = vnet_get_main ();
755   vec_validate_aligned (bm->slave_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES);
756
757   return 0;
758 }
759
760 VLIB_INIT_FUNCTION (bond_cli_init);
761
762 /*
763  * fd.io coding-style-patch-verification: ON
764  *
765  * Local Variables:
766  * eval: (c-set-style "gnu")
767  * End:
768  */