4e0d30aa598a55fa2be6bea77464a7b82e91aab9
[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 #include <vpp/stats/stat_segment.h>
24
25 void
26 bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
27 {
28   bond_main_t *bm = &bond_main;
29   bond_if_t *bif;
30   int i;
31   uword p;
32   vnet_main_t *vnm = vnet_get_main ();
33   vnet_hw_interface_t *hw;
34   u8 switching_active = 0;
35
36   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
37   clib_spinlock_lock_if_init (&bif->lockp);
38   vec_foreach_index (i, bif->active_slaves)
39   {
40     p = *vec_elt_at_index (bif->active_slaves, i);
41     if (p == sif->sw_if_index)
42       {
43         if (sif->sw_if_index == bif->sw_if_index_working)
44           {
45             switching_active = 1;
46             if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
47               bif->is_local_numa = 0;
48           }
49         vec_del1 (bif->active_slaves, i);
50         hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index);
51         if (sif->lacp_enabled && bif->numa_only)
52           {
53             /* For lacp mode, if we check it is a slave on local numa node,
54                bif->n_numa_slaves should be decreased by 1 becasue the first
55                bif->n_numa_slaves are all slaves on local numa node */
56             if (i < bif->n_numa_slaves)
57               {
58                 bif->n_numa_slaves--;
59                 ASSERT (bif->n_numa_slaves >= 0);
60               }
61           }
62         break;
63       }
64   }
65
66   /* We get a new slave just becoming active */
67   if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && switching_active)
68     {
69       if ((vec_len (bif->active_slaves) >= 1))
70         {
71           /* scan all slaves and try to find the first slave with local numa node. */
72           vec_foreach_index (i, bif->active_slaves)
73           {
74             p = *vec_elt_at_index (bif->active_slaves, i);
75             hw = vnet_get_sup_hw_interface (vnm, p);
76             if (vm->numa_node == hw->numa_node)
77               {
78                 bif->sw_if_index_working = p;
79                 bif->is_local_numa = 1;
80                 vlib_process_signal_event (bm->vlib_main,
81                                            bond_process_node.index,
82                                            BOND_SEND_GARP_NA,
83                                            bif->hw_if_index);
84                 break;
85               }
86           }
87         }
88
89       /* No local numa node is found in the active slave set. Use the first slave */
90       if ((bif->is_local_numa == 0) && (vec_len (bif->active_slaves) >= 1))
91         {
92           p = *vec_elt_at_index (bif->active_slaves, 0);
93           bif->sw_if_index_working = p;
94           vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
95                                      BOND_SEND_GARP_NA, bif->hw_if_index);
96         }
97     }
98   clib_spinlock_unlock_if_init (&bif->lockp);
99
100   if (bif->mode == BOND_MODE_LACP)
101     stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
102                                     [sif->sw_if_index], sif->actor.state);
103 }
104
105 void
106 bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
107 {
108   bond_if_t *bif;
109   bond_main_t *bm = &bond_main;
110   vnet_main_t *vnm = vnet_get_main ();
111   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
112   int i;
113   uword p;
114
115   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
116   clib_spinlock_lock_if_init (&bif->lockp);
117   if (!hash_get (bif->active_slave_by_sw_if_index, sif->sw_if_index))
118     {
119       hash_set (bif->active_slave_by_sw_if_index, sif->sw_if_index,
120                 sif->sw_if_index);
121
122       if ((sif->lacp_enabled && bif->numa_only)
123           && (vm->numa_node == hw->numa_node))
124         {
125           vec_insert_elts (bif->active_slaves, &sif->sw_if_index, 1,
126                            bif->n_numa_slaves);
127           bif->n_numa_slaves++;
128         }
129       else
130         {
131           vec_add1 (bif->active_slaves, sif->sw_if_index);
132         }
133
134       /* First slave becomes active? */
135       if ((vec_len (bif->active_slaves) == 1) &&
136           (bif->mode == BOND_MODE_ACTIVE_BACKUP))
137         {
138           bif->sw_if_index_working = sif->sw_if_index;
139           bif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0;
140           vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
141                                      BOND_SEND_GARP_NA, bif->hw_if_index);
142         }
143       else if ((vec_len (bif->active_slaves) > 1)
144                && (bif->mode == BOND_MODE_ACTIVE_BACKUP)
145                && bif->is_local_numa == 0)
146         {
147           if (vm->numa_node == hw->numa_node)
148             {
149               vec_foreach_index (i, bif->active_slaves)
150               {
151                 p = *vec_elt_at_index (bif->active_slaves, 0);
152                 if (p == sif->sw_if_index)
153                   break;
154
155                 vec_del1 (bif->active_slaves, 0);
156                 hash_unset (bif->active_slave_by_sw_if_index, p);
157                 vec_add1 (bif->active_slaves, p);
158                 hash_set (bif->active_slave_by_sw_if_index, p, p);
159               }
160               bif->sw_if_index_working = sif->sw_if_index;
161               bif->is_local_numa = 1;
162               vlib_process_signal_event (bm->vlib_main,
163                                          bond_process_node.index,
164                                          BOND_SEND_GARP_NA, bif->hw_if_index);
165
166             }
167         }
168     }
169   clib_spinlock_unlock_if_init (&bif->lockp);
170
171   if (bif->mode == BOND_MODE_LACP)
172     stat_segment_set_state_counter (bm->stats[bif->sw_if_index]
173                                     [sif->sw_if_index], sif->actor.state);
174 }
175
176 int
177 bond_dump_ifs (bond_interface_details_t ** out_bondifs)
178 {
179   vnet_main_t *vnm = vnet_get_main ();
180   bond_main_t *bm = &bond_main;
181   bond_if_t *bif;
182   vnet_hw_interface_t *hi;
183   bond_interface_details_t *r_bondifs = NULL;
184   bond_interface_details_t *bondif = NULL;
185
186   /* *INDENT-OFF* */
187   pool_foreach (bif, bm->interfaces,
188     vec_add2(r_bondifs, bondif, 1);
189     clib_memset (bondif, 0, sizeof (*bondif));
190     bondif->id = bif->id;
191     bondif->sw_if_index = bif->sw_if_index;
192     hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
193     clib_memcpy(bondif->interface_name, hi->name,
194                 MIN (ARRAY_LEN (bondif->interface_name) - 1,
195                      strlen ((const char *) hi->name)));
196     bondif->mode = bif->mode;
197     bondif->lb = bif->lb;
198     bondif->numa_only = bif->numa_only;
199     bondif->active_slaves = vec_len (bif->active_slaves);
200     bondif->slaves = vec_len (bif->slaves);
201   );
202   /* *INDENT-ON* */
203
204   *out_bondifs = r_bondifs;
205
206   return 0;
207 }
208
209 int
210 bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
211                      u32 bond_sw_if_index)
212 {
213   vnet_main_t *vnm = vnet_get_main ();
214   bond_if_t *bif;
215   vnet_hw_interface_t *hi;
216   vnet_sw_interface_t *sw;
217   slave_interface_details_t *r_slaveifs = NULL;
218   slave_interface_details_t *slaveif = NULL;
219   u32 *sw_if_index = NULL;
220   slave_if_t *sif;
221
222   bif = bond_get_master_by_sw_if_index (bond_sw_if_index);
223   if (!bif)
224     return 1;
225
226   vec_foreach (sw_if_index, bif->slaves)
227   {
228     vec_add2 (r_slaveifs, slaveif, 1);
229     clib_memset (slaveif, 0, sizeof (*slaveif));
230     sif = bond_get_slave_by_sw_if_index (*sw_if_index);
231     if (sif)
232       {
233         sw = vnet_get_sw_interface (vnm, sif->sw_if_index);
234         hi = vnet_get_hw_interface (vnm, sw->hw_if_index);
235         clib_memcpy (slaveif->interface_name, hi->name,
236                      MIN (ARRAY_LEN (slaveif->interface_name) - 1,
237                           strlen ((const char *) hi->name)));
238         slaveif->sw_if_index = sif->sw_if_index;
239         slaveif->is_passive = sif->is_passive;
240         slaveif->is_long_timeout = sif->is_long_timeout;
241       }
242   }
243   *out_slaveifs = r_slaveifs;
244
245   return 0;
246 }
247
248 static void
249 bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif)
250 {
251   bond_main_t *bm = &bond_main;
252   vnet_main_t *vnm = vnet_get_main ();
253   int i;
254   vnet_hw_interface_t *sif_hw;
255
256   sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
257
258   bif->port_number_bitmap =
259     clib_bitmap_set (bif->port_number_bitmap,
260                      ntohs (sif->actor_admin.port_number) - 1, 0);
261   bm->slave_by_sw_if_index[sif->sw_if_index] = 0;
262   vec_free (sif->last_marker_pkt);
263   vec_free (sif->last_rx_pkt);
264   vec_foreach_index (i, bif->slaves)
265   {
266     uword p = *vec_elt_at_index (bif->slaves, i);
267     if (p == sif->sw_if_index)
268       {
269         vec_del1 (bif->slaves, i);
270         break;
271       }
272   }
273
274   bond_disable_collecting_distributing (vm, sif);
275
276   vnet_feature_enable_disable ("device-input", "bond-input",
277                                sif_hw->hw_if_index, 0, 0, 0);
278
279   /* Put back the old mac */
280   vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
281                                         sif->persistent_hw_address);
282
283   if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
284     (*bm->lacp_enable_disable) (vm, bif, sif, 0);
285
286   if (bif->mode == BOND_MODE_LACP)
287     stat_segment_deregister_state_counter
288       (bm->stats[bif->sw_if_index][sif->sw_if_index]);
289
290   pool_put (bm->neighbors, sif);
291 }
292
293 int
294 bond_delete_if (vlib_main_t * vm, u32 sw_if_index)
295 {
296   bond_main_t *bm = &bond_main;
297   vnet_main_t *vnm = vnet_get_main ();
298   bond_if_t *bif;
299   slave_if_t *sif;
300   vnet_hw_interface_t *hw;
301   u32 *sif_sw_if_index;
302   u32 **s_list = 0;
303   u32 i;
304
305   hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
306   if (hw == NULL || bond_dev_class.index != hw->dev_class_index)
307     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
308
309   bif = bond_get_master_by_dev_instance (hw->dev_instance);
310
311   vec_foreach (sif_sw_if_index, bif->slaves)
312   {
313     vec_add1 (s_list, sif_sw_if_index);
314   }
315
316   for (i = 0; i < vec_len (s_list); i++)
317     {
318       sif_sw_if_index = s_list[i];
319       sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index);
320       if (sif)
321         bond_delete_neighbor (vm, bif, sif);
322     }
323
324   if (s_list)
325     vec_free (s_list);
326
327   /* bring down the interface */
328   vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
329   vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
330
331   ethernet_delete_interface (vnm, bif->hw_if_index);
332
333   clib_bitmap_free (bif->port_number_bitmap);
334   hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
335   hash_unset (bm->id_used, bif->id);
336   clib_memset (bif, 0, sizeof (*bif));
337   pool_put (bm->interfaces, bif);
338
339   return 0;
340 }
341
342 void
343 bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
344 {
345   bond_main_t *bm = &bond_main;
346   vnet_main_t *vnm = vnet_get_main ();
347   vnet_sw_interface_t *sw;
348   bond_if_t *bif;
349
350   if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
351     {
352       args->rv = VNET_API_ERROR_FEATURE_DISABLED;
353       args->error = clib_error_return (0, "LACP plugin is not loaded");
354       return;
355     }
356   if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
357     {
358       args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
359       args->error = clib_error_return (0, "Invalid mode");
360       return;
361     }
362   if (args->lb > BOND_LB_L23)
363     {
364       args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
365       args->error = clib_error_return (0, "Invalid load-balance");
366       return;
367     }
368   pool_get (bm->interfaces, bif);
369   clib_memset (bif, 0, sizeof (*bif));
370   bif->dev_instance = bif - bm->interfaces;
371   bif->id = args->id;
372   bif->lb = args->lb;
373   bif->mode = args->mode;
374
375   // Adjust requested interface id
376   if (bif->id == ~0)
377     bif->id = bif->dev_instance;
378   if (hash_get (bm->id_used, bif->id))
379     {
380       args->rv = VNET_API_ERROR_INSTANCE_IN_USE;
381       pool_put (bm->interfaces, bif);
382       return;
383     }
384   hash_set (bm->id_used, bif->id, 1);
385
386   // Special load-balance mode used for rr and bc
387   if (bif->mode == BOND_MODE_ROUND_ROBIN)
388     bif->lb = BOND_LB_RR;
389   else if (bif->mode == BOND_MODE_BROADCAST)
390     bif->lb = BOND_LB_BC;
391   else if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
392     bif->lb = BOND_LB_AB;
393
394   bif->use_custom_mac = args->hw_addr_set;
395   if (!args->hw_addr_set)
396     {
397       f64 now = vlib_time_now (vm);
398       u32 rnd;
399       rnd = (u32) (now * 1e6);
400       rnd = random_u32 (&rnd);
401
402       memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
403       args->hw_addr[0] = 2;
404       args->hw_addr[1] = 0xfe;
405     }
406   memcpy (bif->hw_address, args->hw_addr, 6);
407   args->error = ethernet_register_interface
408     (vnm, bond_dev_class.index, bif->dev_instance /* device instance */ ,
409      bif->hw_address /* ethernet address */ ,
410      &bif->hw_if_index, 0 /* flag change */ );
411
412   if (args->error)
413     {
414       args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
415       hash_unset (bm->id_used, bif->id);
416       pool_put (bm->interfaces, bif);
417       return;
418     }
419
420   sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
421   bif->sw_if_index = sw->sw_if_index;
422   bif->group = bif->sw_if_index;
423   bif->numa_only = args->numa_only;
424   if (vlib_get_thread_main ()->n_vlib_mains > 1)
425     clib_spinlock_init (&bif->lockp);
426
427   vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
428                                VNET_HW_INTERFACE_FLAG_LINK_UP);
429
430   hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
431
432   // for return
433   args->sw_if_index = bif->sw_if_index;
434   args->rv = 0;
435 }
436
437 static clib_error_t *
438 bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
439                         vlib_cli_command_t * cmd)
440 {
441   unformat_input_t _line_input, *line_input = &_line_input;
442   bond_create_if_args_t args = { 0 };
443   u8 mode_is_set = 0;
444
445   /* Get a line of input. */
446   if (!unformat_user (input, unformat_line_input, line_input))
447     return clib_error_return (0, "Missing required arguments.");
448
449   args.id = ~0;
450   args.mode = -1;
451   args.lb = BOND_LB_L2;
452   args.rv = -1;
453   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
454     {
455       if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
456         mode_is_set = 1;
457       else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
458                && unformat (line_input, "load-balance %U",
459                             unformat_bond_load_balance, &args.lb))
460         ;
461       else if (unformat (line_input, "hw-addr %U",
462                          unformat_ethernet_address, args.hw_addr))
463         args.hw_addr_set = 1;
464       else if (unformat (line_input, "id %u", &args.id))
465         ;
466       else if (unformat (line_input, "numa-only"))
467         {
468           if (args.mode == BOND_MODE_LACP)
469             args.numa_only = 1;
470           else
471             return clib_error_return (0,
472                                       "Only lacp mode supports numa-only so far!");
473         }
474       else
475         return clib_error_return (0, "unknown input `%U'",
476                                   format_unformat_error, input);
477     }
478   unformat_free (line_input);
479
480   if (mode_is_set == 0)
481     return clib_error_return (0, "Missing bond mode");
482
483   bond_create_if (vm, &args);
484
485   if (!args.rv)
486     vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
487                      vnet_get_main (), args.sw_if_index);
488
489   return args.error;
490 }
491
492 /* *INDENT-OFF* */
493 VLIB_CLI_COMMAND (bond_create_command, static) = {
494   .path = "create bond",
495   .short_help = "create bond mode {round-robin | active-backup | broadcast | "
496     "{lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} [hw-addr <mac-address>] "
497     "[id <if-id>]",
498   .function = bond_create_command_fn,
499 };
500 /* *INDENT-ON* */
501
502 static clib_error_t *
503 bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
504                         vlib_cli_command_t * cmd)
505 {
506   unformat_input_t _line_input, *line_input = &_line_input;
507   u32 sw_if_index = ~0;
508   vnet_main_t *vnm = vnet_get_main ();
509   int rv;
510
511   /* Get a line of input. */
512   if (!unformat_user (input, unformat_line_input, line_input))
513     return clib_error_return (0, "Missing <interface>");
514
515   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
516     {
517       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
518         ;
519       else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
520                          vnm, &sw_if_index))
521         ;
522       else
523         return clib_error_return (0, "unknown input `%U'",
524                                   format_unformat_error, input);
525     }
526   unformat_free (line_input);
527
528   if (sw_if_index == ~0)
529     return clib_error_return (0,
530                               "please specify interface name or sw_if_index");
531
532   rv = bond_delete_if (vm, sw_if_index);
533   if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
534     return clib_error_return (0, "not a bond interface");
535   else if (rv != 0)
536     return clib_error_return (0, "error on deleting bond interface");
537
538   return 0;
539 }
540
541 /* *INDENT-OFF* */
542 VLIB_CLI_COMMAND (bond_delete__command, static) =
543 {
544   .path = "delete bond",
545   .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
546   .function = bond_delete_command_fn,
547 };
548 /* *INDENT-ON* */
549
550 void
551 bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args)
552 {
553   bond_main_t *bm = &bond_main;
554   vnet_main_t *vnm = vnet_get_main ();
555   bond_if_t *bif;
556   slave_if_t *sif;
557   vnet_interface_main_t *im = &vnm->interface_main;
558   vnet_hw_interface_t *bif_hw, *sif_hw;
559   vnet_sw_interface_t *sw;
560   u32 thread_index;
561   u32 sif_if_index;
562
563   bif = bond_get_master_by_sw_if_index (args->group);
564   if (!bif)
565     {
566       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
567       args->error = clib_error_return (0, "bond interface not found");
568       return;
569     }
570   // make sure the interface is not already enslaved
571   if (bond_get_slave_by_sw_if_index (args->slave))
572     {
573       args->rv = VNET_API_ERROR_VALUE_EXIST;
574       args->error = clib_error_return (0, "interface was already enslaved");
575       return;
576     }
577   sif_hw = vnet_get_sup_hw_interface (vnm, args->slave);
578   if (sif_hw->dev_class_index == bond_dev_class.index)
579     {
580       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
581       args->error =
582         clib_error_return (0, "bond interface cannot be enslaved");
583       return;
584     }
585   if (bif->mode == BOND_MODE_LACP)
586     {
587       u8 *name = format (0, "/if/lacp/%u/%u/state", bif->sw_if_index,
588                          args->slave);
589
590       vec_validate (bm->stats, bif->sw_if_index);
591       vec_validate (bm->stats[bif->sw_if_index], args->slave);
592
593       args->error = stat_segment_register_state_counter
594         (name, &bm->stats[bif->sw_if_index][args->slave]);
595       vec_free (name);
596       if (args->error != 0)
597         {
598           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
599           return;
600         }
601     }
602
603   pool_get (bm->neighbors, sif);
604   clib_memset (sif, 0, sizeof (*sif));
605   sw = pool_elt_at_index (im->sw_interfaces, args->slave);
606   /* port_enabled is both admin up and hw link up */
607   sif->port_enabled = vnet_sw_interface_is_up (vnm, sw->sw_if_index);
608   sif->sw_if_index = sw->sw_if_index;
609   sif->hw_if_index = sw->hw_if_index;
610   sif->packet_template_index = (u8) ~ 0;
611   sif->is_passive = args->is_passive;
612   sif->group = args->group;
613   sif->bif_dev_instance = bif->dev_instance;
614   sif->mode = bif->mode;
615
616   sif->is_long_timeout = args->is_long_timeout;
617   if (args->is_long_timeout)
618     sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
619   else
620     sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
621
622   vec_validate_aligned (bm->slave_by_sw_if_index, sif->sw_if_index,
623                         CLIB_CACHE_LINE_BYTES);
624   /*
625    * sif - bm->neighbors may be 0
626    * Left shift it by 1 bit to distinguish the valid entry that we actually
627    * store from the null entries
628    */
629   bm->slave_by_sw_if_index[sif->sw_if_index] =
630     (uword) (((sif - bm->neighbors) << 1) | 1);
631   vec_add1 (bif->slaves, sif->sw_if_index);
632
633   sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
634
635   /* Save the old mac */
636   memcpy (sif->persistent_hw_address, sif_hw->hw_address, 6);
637   bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
638   if (bif->use_custom_mac)
639     {
640       vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
641                                             bif->hw_address);
642     }
643   else
644     {
645       // bond interface gets the mac address from the first slave
646       if (vec_len (bif->slaves) == 1)
647         {
648           memcpy (bif->hw_address, sif_hw->hw_address, 6);
649           vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index,
650                                                 sif_hw->hw_address);
651         }
652       else
653         {
654           // subsequent slaves gets the mac address of the bond interface
655           vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
656                                                 bif->hw_address);
657         }
658     }
659
660   if (bif_hw->l2_if_count)
661     {
662       ethernet_set_flags (vnm, sif_hw->hw_if_index,
663                           ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
664       /* ensure all packets go to ethernet-input */
665       ethernet_set_rx_redirect (vnm, sif_hw, 1);
666     }
667
668   if (bif->mode == BOND_MODE_LACP)
669     {
670       if (bm->lacp_enable_disable)
671         (*bm->lacp_enable_disable) (vm, bif, sif, 1);
672     }
673   else if (sif->port_enabled)
674     {
675       bond_enable_collecting_distributing (vm, sif);
676     }
677
678   vec_foreach_index (thread_index, bm->per_thread_data)
679   {
680     bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
681                                                     thread_index);
682
683     vec_validate_aligned (ptd->per_port_queue, vec_len (bif->slaves) - 1,
684                           CLIB_CACHE_LINE_BYTES);
685
686     vec_foreach_index (sif_if_index, ptd->per_port_queue)
687     {
688       ptd->per_port_queue[sif_if_index].n_buffers = 0;
689     }
690   }
691
692   args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
693                                           sif_hw->hw_if_index, 1, 0, 0);
694
695   if (args->rv)
696     {
697       args->error =
698         clib_error_return (0,
699                            "Error encountered on input feature arc enable");
700     }
701 }
702
703 static clib_error_t *
704 enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
705                               vlib_cli_command_t * cmd)
706 {
707   bond_enslave_args_t args = { 0 };
708   unformat_input_t _line_input, *line_input = &_line_input;
709   vnet_main_t *vnm = vnet_get_main ();
710
711   /* Get a line of input. */
712   if (!unformat_user (input, unformat_line_input, line_input))
713     return clib_error_return (0, "Missing required arguments.");
714
715   args.slave = ~0;
716   args.group = ~0;
717   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
718     {
719       if (unformat (line_input, "%U %U",
720                     unformat_vnet_sw_interface, vnm, &args.group,
721                     unformat_vnet_sw_interface, vnm, &args.slave))
722         ;
723       else if (unformat (line_input, "passive"))
724         args.is_passive = 1;
725       else if (unformat (line_input, "long-timeout"))
726         args.is_long_timeout = 1;
727       else
728         {
729           args.error = clib_error_return (0, "unknown input `%U'",
730                                           format_unformat_error, input);
731           break;
732         }
733     }
734   unformat_free (line_input);
735
736   if (args.error)
737     return args.error;
738   if (args.group == ~0)
739     return clib_error_return (0, "Missing bond interface");
740   if (args.slave == ~0)
741     return clib_error_return (0, "please specify valid slave interface name");
742
743   bond_enslave (vm, &args);
744
745   return args.error;
746 }
747
748 /* *INDENT-OFF* */
749 VLIB_CLI_COMMAND (enslave_interface_command, static) = {
750   .path = "bond add",
751   .short_help = "bond add <BondEthernetx> <slave-interface> "
752                 "[passive] [long-timeout]",
753   .function = enslave_interface_command_fn,
754 };
755 /* *INDENT-ON* */
756
757 void
758 bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args)
759 {
760   bond_if_t *bif;
761   slave_if_t *sif;
762
763   sif = bond_get_slave_by_sw_if_index (args->slave);
764   if (!sif)
765     {
766       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
767       args->error = clib_error_return (0, "interface was not enslaved");
768       return;
769     }
770   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
771   bond_delete_neighbor (vm, bif, sif);
772 }
773
774 static clib_error_t *
775 detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
776                              vlib_cli_command_t * cmd)
777 {
778   bond_detach_slave_args_t args = { 0 };
779   unformat_input_t _line_input, *line_input = &_line_input;
780   vnet_main_t *vnm = vnet_get_main ();
781
782   /* Get a line of input. */
783   if (!unformat_user (input, unformat_line_input, line_input))
784     return clib_error_return (0, "Missing required arguments.");
785
786   args.slave = ~0;
787   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
788     {
789       if (unformat (line_input, "%U",
790                     unformat_vnet_sw_interface, vnm, &args.slave))
791         ;
792       else
793         {
794           args.error = clib_error_return (0, "unknown input `%U'",
795                                           format_unformat_error, input);
796           break;
797         }
798     }
799   unformat_free (line_input);
800
801   if (args.error)
802     return args.error;
803   if (args.slave == ~0)
804     return clib_error_return (0, "please specify valid slave interface name");
805
806   bond_detach_slave (vm, &args);
807
808   return args.error;
809 }
810
811 /* *INDENT-OFF* */
812 VLIB_CLI_COMMAND (detach_interface_command, static) = {
813   .path = "bond del",
814   .short_help = "bond del <slave-interface>",
815   .function = detach_interface_command_fn,
816 };
817 /* *INDENT-ON* */
818
819 static void
820 show_bond (vlib_main_t * vm)
821 {
822   bond_main_t *bm = &bond_main;
823   bond_if_t *bif;
824
825   vlib_cli_output (vm, "%-16s %-12s %-13s %-13s %-14s %s",
826                    "interface name", "sw_if_index", "mode",
827                    "load balance", "active slaves", "slaves");
828
829   /* *INDENT-OFF* */
830   pool_foreach (bif, bm->interfaces,
831   ({
832     vlib_cli_output (vm, "%-16U %-12d %-13U %-13U %-14u %u",
833                      format_bond_interface_name, bif->dev_instance,
834                      bif->sw_if_index, format_bond_mode, bif->mode,
835                      format_bond_load_balance, bif->lb,
836                      vec_len (bif->active_slaves), vec_len (bif->slaves));
837   }));
838   /* *INDENT-ON* */
839 }
840
841 static void
842 show_bond_details (vlib_main_t * vm)
843 {
844   bond_main_t *bm = &bond_main;
845   bond_if_t *bif;
846   u32 *sw_if_index;
847
848   /* *INDENT-OFF* */
849   pool_foreach (bif, bm->interfaces,
850   ({
851     vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
852     vlib_cli_output (vm, "  mode: %U",
853                      format_bond_mode, bif->mode);
854     vlib_cli_output (vm, "  load balance: %U",
855                      format_bond_load_balance, bif->lb);
856     if (bif->mode == BOND_MODE_ROUND_ROBIN)
857       vlib_cli_output (vm, "  last xmit slave index: %u",
858                        bif->lb_rr_last_index);
859     vlib_cli_output (vm, "  number of active slaves: %d",
860                      vec_len (bif->active_slaves));
861     vec_foreach (sw_if_index, bif->active_slaves)
862       {
863         vlib_cli_output (vm, "    %U", format_vnet_sw_if_index_name,
864                          vnet_get_main (), *sw_if_index);
865       }
866     vlib_cli_output (vm, "  number of slaves: %d", vec_len (bif->slaves));
867     vec_foreach (sw_if_index, bif->slaves)
868       {
869         vlib_cli_output (vm, "    %U", format_vnet_sw_if_index_name,
870                          vnet_get_main (), *sw_if_index);
871       }
872     vlib_cli_output (vm, "  device instance: %d", bif->dev_instance);
873     vlib_cli_output (vm, "  interface id: %d", bif->id);
874     vlib_cli_output (vm, "  sw_if_index: %d", bif->sw_if_index);
875     vlib_cli_output (vm, "  hw_if_index: %d", bif->hw_if_index);
876   }));
877   /* *INDENT-ON* */
878 }
879
880 static clib_error_t *
881 show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
882               vlib_cli_command_t * cmd)
883 {
884   u8 details = 0;
885
886   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
887     {
888       if (unformat (input, "details"))
889         details = 1;
890       else
891         {
892           return clib_error_return (0, "unknown input `%U'",
893                                     format_unformat_error, input);
894         }
895     }
896
897   if (details)
898     show_bond_details (vm);
899   else
900     show_bond (vm);
901
902   return 0;
903 }
904
905 /* *INDENT-OFF* */
906 VLIB_CLI_COMMAND (show_bond_command, static) = {
907   .path = "show bond",
908   .short_help = "show bond [details]",
909   .function = show_bond_fn,
910 };
911 /* *INDENT-ON* */
912
913 clib_error_t *
914 bond_cli_init (vlib_main_t * vm)
915 {
916   bond_main_t *bm = &bond_main;
917
918   bm->vlib_main = vm;
919   bm->vnet_main = vnet_get_main ();
920   vec_validate_aligned (bm->slave_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES);
921   vec_validate_aligned (bm->per_thread_data,
922                         vlib_get_thread_main ()->n_vlib_mains - 1,
923                         CLIB_CACHE_LINE_BYTES);
924
925   return 0;
926 }
927
928 VLIB_INIT_FUNCTION (bond_cli_init);
929
930 /*
931  * fd.io coding-style-patch-verification: ON
932  *
933  * Local Variables:
934  * eval: (c-set-style "gnu")
935  * End:
936  */