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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
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>
26 bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
28 bond_main_t *bm = &bond_main;
29 vnet_main_t *vnm = vnet_get_main ();
33 u8 switching_active = 0;
35 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
36 clib_spinlock_lock_if_init (&bif->lockp);
37 vec_foreach_index (i, bif->active_slaves)
39 p = *vec_elt_at_index (bif->active_slaves, i);
40 if (p == sif->sw_if_index)
42 if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && (i == 0) &&
43 (vec_len (bif->active_slaves) > 1))
44 /* deleting the active slave for active-backup */
46 vec_del1 (bif->active_slaves, i);
47 if (sif->lacp_enabled && bif->numa_only)
49 /* For lacp mode, if we check it is a slave on local numa node,
50 bif->n_numa_slaves should be decreased by 1 becasue the first
51 bif->n_numa_slaves are all slaves on local numa node */
52 if (i < bif->n_numa_slaves)
55 ASSERT (bif->n_numa_slaves >= 0);
58 /* If that was the last active slave, set bond link state down */
59 if (!vec_len (bif->active_slaves))
61 vnet_hw_interface_flags_t flags;
63 flags = vnet_hw_interface_get_flags (vnm, bif->hw_if_index);
64 flags &= ~VNET_HW_INTERFACE_FLAG_LINK_UP;
65 vnet_hw_interface_set_flags (vnm, bif->hw_if_index, flags);
71 /* We get a new slave just becoming active */
73 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
74 BOND_SEND_GARP_NA, bif->hw_if_index);
75 clib_spinlock_unlock_if_init (&bif->lockp);
79 * return 1 if s2 is preferred.
80 * return -1 if s1 is preferred.
83 bond_slave_sort (void *a1, void *a2)
87 slave_if_t *sif1 = bond_get_slave_by_sw_if_index (*s1);
88 slave_if_t *sif2 = bond_get_slave_by_sw_if_index (*s2);
94 * sort entries according to preference rules:
97 * 3. current active slave (to prevent churning)
98 * 4. lowest sw_if_index (for deterministic behavior)
101 if (sif2->weight > sif1->weight)
103 if (sif2->weight < sif1->weight)
107 if (sif2->is_local_numa > sif1->is_local_numa)
109 if (sif2->is_local_numa < sif1->is_local_numa)
113 bif = bond_get_master_by_dev_instance (sif1->bif_dev_instance);
114 /* Favor the current active slave to avoid churning */
115 if (bif->active_slaves[0] == sif2->sw_if_index)
117 if (bif->active_slaves[0] == sif1->sw_if_index)
119 /* go for the tiebreaker as the last resort */
120 if (sif1->sw_if_index > sif2->sw_if_index)
122 if (sif1->sw_if_index < sif2->sw_if_index)
132 bond_sort_slaves (bond_if_t * bif)
134 bond_main_t *bm = &bond_main;
135 u32 old_active = bif->active_slaves[0];
137 vec_sort_with_function (bif->active_slaves, bond_slave_sort);
138 if (old_active != bif->active_slaves[0])
139 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
140 BOND_SEND_GARP_NA, bif->hw_if_index);
144 bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
147 bond_main_t *bm = &bond_main;
148 vnet_main_t *vnm = vnet_get_main ();
149 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
153 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
154 clib_spinlock_lock_if_init (&bif->lockp);
155 vec_foreach_index (i, bif->active_slaves)
157 p = *vec_elt_at_index (bif->active_slaves, i);
158 if (p == sif->sw_if_index)
162 if (sif->lacp_enabled && bif->numa_only && (vm->numa_node == hw->numa_node))
164 vec_insert_elts (bif->active_slaves, &sif->sw_if_index, 1,
166 bif->n_numa_slaves++;
169 vec_add1 (bif->active_slaves, sif->sw_if_index);
171 /* If this was the first active slave, set bond link state up */
172 if (vec_len (bif->active_slaves) == 1)
174 vnet_hw_interface_flags_t flags;
176 flags = vnet_hw_interface_get_flags (vnm, bif->hw_if_index);
177 flags |= VNET_HW_INTERFACE_FLAG_LINK_UP;
178 vnet_hw_interface_set_flags (vnm, bif->hw_if_index, flags);
181 sif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0;
182 if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
184 if (vec_len (bif->active_slaves) == 1)
185 /* First slave becomes active? */
186 vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
187 BOND_SEND_GARP_NA, bif->hw_if_index);
189 bond_sort_slaves (bif);
193 clib_spinlock_unlock_if_init (&bif->lockp);
197 bond_dump_ifs (bond_interface_details_t ** out_bondifs)
199 vnet_main_t *vnm = vnet_get_main ();
200 bond_main_t *bm = &bond_main;
202 vnet_hw_interface_t *hi;
203 bond_interface_details_t *r_bondifs = NULL;
204 bond_interface_details_t *bondif = NULL;
207 pool_foreach (bif, bm->interfaces,
208 vec_add2(r_bondifs, bondif, 1);
209 clib_memset (bondif, 0, sizeof (*bondif));
210 bondif->id = bif->id;
211 bondif->sw_if_index = bif->sw_if_index;
212 hi = vnet_get_hw_interface (vnm, bif->hw_if_index);
213 clib_memcpy(bondif->interface_name, hi->name,
214 MIN (ARRAY_LEN (bondif->interface_name) - 1,
215 vec_len ((const char *) hi->name)));
216 /* enforce by memset() above */
217 ASSERT(0 == bondif->interface_name[ARRAY_LEN (bondif->interface_name) - 1]);
218 bondif->mode = bif->mode;
219 bondif->lb = bif->lb;
220 bondif->numa_only = bif->numa_only;
221 bondif->active_slaves = vec_len (bif->active_slaves);
222 bondif->slaves = vec_len (bif->slaves);
226 *out_bondifs = r_bondifs;
232 bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
233 u32 bond_sw_if_index)
235 vnet_main_t *vnm = vnet_get_main ();
237 vnet_hw_interface_t *hi;
238 vnet_sw_interface_t *sw;
239 slave_interface_details_t *r_slaveifs = NULL;
240 slave_interface_details_t *slaveif = NULL;
241 u32 *sw_if_index = NULL;
244 bif = bond_get_master_by_sw_if_index (bond_sw_if_index);
248 vec_foreach (sw_if_index, bif->slaves)
250 vec_add2 (r_slaveifs, slaveif, 1);
251 clib_memset (slaveif, 0, sizeof (*slaveif));
252 sif = bond_get_slave_by_sw_if_index (*sw_if_index);
255 sw = vnet_get_sw_interface (vnm, sif->sw_if_index);
256 hi = vnet_get_hw_interface (vnm, sw->hw_if_index);
257 clib_memcpy (slaveif->interface_name, hi->name,
258 MIN (ARRAY_LEN (slaveif->interface_name) - 1,
259 vec_len ((const char *) hi->name)));
260 /* enforce by memset() above */
262 slaveif->interface_name[ARRAY_LEN (slaveif->interface_name) -
264 slaveif->sw_if_index = sif->sw_if_index;
265 slaveif->is_passive = sif->is_passive;
266 slaveif->is_long_timeout = sif->is_long_timeout;
267 slaveif->is_local_numa = sif->is_local_numa;
268 slaveif->weight = sif->weight;
271 *out_slaveifs = r_slaveifs;
277 * Manage secondary mac addresses when attaching/detaching a slave.
278 * If adding, copies any secondary addresses from master to slave
279 * If deleting, deletes the master's secondary addresses from the slave
283 bond_slave_add_del_mac_addrs (bond_if_t * bif, u32 sif_sw_if_index, u8 is_add)
285 vnet_main_t *vnm = vnet_get_main ();
286 ethernet_interface_t *b_ei;
287 mac_address_t *sec_mac;
288 vnet_hw_interface_t *s_hwif;
290 b_ei = ethernet_get_interface (ðernet_main, bif->hw_if_index);
291 if (!b_ei || !b_ei->secondary_addrs)
294 s_hwif = vnet_get_sup_hw_interface (vnm, sif_sw_if_index);
296 vec_foreach (sec_mac, b_ei->secondary_addrs)
297 vnet_hw_interface_add_del_mac_address (vnm, s_hwif->hw_if_index,
298 sec_mac->bytes, is_add);
302 bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif)
304 bond_main_t *bm = &bond_main;
305 vnet_main_t *vnm = vnet_get_main ();
307 vnet_hw_interface_t *sif_hw;
309 sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
311 bif->port_number_bitmap =
312 clib_bitmap_set (bif->port_number_bitmap,
313 ntohs (sif->actor_admin.port_number) - 1, 0);
314 bm->slave_by_sw_if_index[sif->sw_if_index] = 0;
315 vec_free (sif->last_marker_pkt);
316 vec_free (sif->last_rx_pkt);
317 vec_foreach_index (i, bif->slaves)
319 uword p = *vec_elt_at_index (bif->slaves, i);
320 if (p == sif->sw_if_index)
322 vec_del1 (bif->slaves, i);
327 bond_disable_collecting_distributing (vm, sif);
329 vnet_feature_enable_disable ("device-input", "bond-input",
330 sif->sw_if_index, 0, 0, 0);
332 /* Put back the old mac */
333 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
334 sif->persistent_hw_address);
336 /* delete the bond's secondary/virtual mac addrs from the slave */
337 bond_slave_add_del_mac_addrs (bif, sif->sw_if_index, 0 /* is_add */ );
340 if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
341 (*bm->lacp_enable_disable) (vm, bif, sif, 0);
343 if (bif->mode == BOND_MODE_LACP)
345 stat_segment_deregister_state_counter
346 (bm->stats[bif->sw_if_index][sif->sw_if_index].actor_state);
347 stat_segment_deregister_state_counter
348 (bm->stats[bif->sw_if_index][sif->sw_if_index].partner_state);
351 pool_put (bm->neighbors, sif);
355 bond_delete_if (vlib_main_t * vm, u32 sw_if_index)
357 bond_main_t *bm = &bond_main;
358 vnet_main_t *vnm = vnet_get_main ();
361 vnet_hw_interface_t *hw;
362 u32 *sif_sw_if_index;
365 hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
366 if (hw == NULL || bond_dev_class.index != hw->dev_class_index)
367 return VNET_API_ERROR_INVALID_SW_IF_INDEX;
369 bif = bond_get_master_by_dev_instance (hw->dev_instance);
371 vec_append (s_list, bif->slaves);
372 vec_foreach (sif_sw_if_index, s_list)
374 sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index);
376 bond_delete_neighbor (vm, bif, sif);
380 /* bring down the interface */
381 vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
382 vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
384 ethernet_delete_interface (vnm, bif->hw_if_index);
386 clib_bitmap_free (bif->port_number_bitmap);
387 hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
388 hash_unset (bm->id_used, bif->id);
389 clib_memset (bif, 0, sizeof (*bif));
390 pool_put (bm->interfaces, bif);
396 bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
398 bond_main_t *bm = &bond_main;
399 vnet_main_t *vnm = vnet_get_main ();
400 vnet_sw_interface_t *sw;
402 vnet_hw_interface_t *hw;
404 if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
406 args->rv = VNET_API_ERROR_FEATURE_DISABLED;
407 args->error = clib_error_return (0, "LACP plugin is not loaded");
410 if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
412 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
413 args->error = clib_error_return (0, "Invalid mode");
416 if (args->lb > BOND_LB_L23)
418 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
419 args->error = clib_error_return (0, "Invalid load-balance");
422 pool_get (bm->interfaces, bif);
423 clib_memset (bif, 0, sizeof (*bif));
424 bif->dev_instance = bif - bm->interfaces;
427 bif->mode = args->mode;
428 bif->gso = args->gso;
430 // Adjust requested interface id
432 bif->id = bif->dev_instance;
433 if (hash_get (bm->id_used, bif->id))
435 args->rv = VNET_API_ERROR_INSTANCE_IN_USE;
436 pool_put (bm->interfaces, bif);
439 hash_set (bm->id_used, bif->id, 1);
441 // Special load-balance mode used for rr and bc
442 if (bif->mode == BOND_MODE_ROUND_ROBIN)
443 bif->lb = BOND_LB_RR;
444 else if (bif->mode == BOND_MODE_BROADCAST)
445 bif->lb = BOND_LB_BC;
446 else if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
447 bif->lb = BOND_LB_AB;
449 bif->use_custom_mac = args->hw_addr_set;
450 if (!args->hw_addr_set)
452 f64 now = vlib_time_now (vm);
454 rnd = (u32) (now * 1e6);
455 rnd = random_u32 (&rnd);
457 memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
458 args->hw_addr[0] = 2;
459 args->hw_addr[1] = 0xfe;
461 memcpy (bif->hw_address, args->hw_addr, 6);
462 args->error = ethernet_register_interface
463 (vnm, bond_dev_class.index, bif->dev_instance /* device instance */ ,
464 bif->hw_address /* ethernet address */ ,
465 &bif->hw_if_index, 0 /* flag change */ );
469 args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
470 hash_unset (bm->id_used, bif->id);
471 pool_put (bm->interfaces, bif);
475 sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
476 bif->sw_if_index = sw->sw_if_index;
477 bif->group = bif->sw_if_index;
478 bif->numa_only = args->numa_only;
480 hw = vnet_get_hw_interface (vnm, bif->hw_if_index);
482 * Add GSO and Checksum offload flags if GSO is enabled on Bond
486 hw->flags |= (VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO |
487 VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD);
489 if (vlib_get_thread_main ()->n_vlib_mains > 1)
490 clib_spinlock_init (&bif->lockp);
492 hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
495 args->sw_if_index = bif->sw_if_index;
499 static clib_error_t *
500 bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
501 vlib_cli_command_t * cmd)
503 unformat_input_t _line_input, *line_input = &_line_input;
504 bond_create_if_args_t args = { 0 };
507 /* Get a line of input. */
508 if (!unformat_user (input, unformat_line_input, line_input))
509 return clib_error_return (0, "Missing required arguments.");
513 args.lb = BOND_LB_L2;
515 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
517 if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
519 else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
520 && unformat (line_input, "load-balance %U",
521 unformat_bond_load_balance, &args.lb))
523 else if (unformat (line_input, "hw-addr %U",
524 unformat_ethernet_address, args.hw_addr))
525 args.hw_addr_set = 1;
526 else if (unformat (line_input, "id %u", &args.id))
528 else if (unformat (line_input, "gso"))
530 else if (unformat (line_input, "numa-only"))
532 if (args.mode == BOND_MODE_LACP)
535 return clib_error_return (0,
536 "Only lacp mode supports numa-only so far!");
539 return clib_error_return (0, "unknown input `%U'",
540 format_unformat_error, input);
542 unformat_free (line_input);
544 if (mode_is_set == 0)
545 return clib_error_return (0, "Missing bond mode");
547 bond_create_if (vm, &args);
550 vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
551 vnet_get_main (), args.sw_if_index);
557 VLIB_CLI_COMMAND (bond_create_command, static) = {
558 .path = "create bond",
559 .short_help = "create bond mode {round-robin | active-backup | broadcast | "
560 "{lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} "
561 "[hw-addr <mac-address>] [id <if-id>] [gso]",
562 .function = bond_create_command_fn,
566 static clib_error_t *
567 bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
568 vlib_cli_command_t * cmd)
570 unformat_input_t _line_input, *line_input = &_line_input;
571 u32 sw_if_index = ~0;
572 vnet_main_t *vnm = vnet_get_main ();
575 /* Get a line of input. */
576 if (!unformat_user (input, unformat_line_input, line_input))
577 return clib_error_return (0, "Missing <interface>");
579 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
581 if (unformat (line_input, "sw_if_index %d", &sw_if_index))
583 else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
587 return clib_error_return (0, "unknown input `%U'",
588 format_unformat_error, input);
590 unformat_free (line_input);
592 if (sw_if_index == ~0)
593 return clib_error_return (0,
594 "please specify interface name or sw_if_index");
596 rv = bond_delete_if (vm, sw_if_index);
597 if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
598 return clib_error_return (0, "not a bond interface");
600 return clib_error_return (0, "error on deleting bond interface");
606 VLIB_CLI_COMMAND (bond_delete__command, static) =
608 .path = "delete bond",
609 .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
610 .function = bond_delete_command_fn,
615 bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args)
617 bond_main_t *bm = &bond_main;
618 vnet_main_t *vnm = vnet_get_main ();
621 vnet_interface_main_t *im = &vnm->interface_main;
622 vnet_hw_interface_t *bif_hw, *sif_hw;
623 vnet_sw_interface_t *sw;
627 bif = bond_get_master_by_sw_if_index (args->group);
630 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
631 args->error = clib_error_return (0, "bond interface not found");
634 // make sure the interface is not already enslaved
635 if (bond_get_slave_by_sw_if_index (args->slave))
637 args->rv = VNET_API_ERROR_VALUE_EXIST;
638 args->error = clib_error_return (0, "interface was already enslaved");
641 sif_hw = vnet_get_sup_hw_interface (vnm, args->slave);
642 if (sif_hw->dev_class_index == bond_dev_class.index)
644 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
646 clib_error_return (0, "bond interface cannot be enslaved");
649 if (bif->gso && !(sif_hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO))
651 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
653 clib_error_return (0, "slave interface is not gso capable");
656 if (bif->mode == BOND_MODE_LACP)
658 u8 *name = format (0, "/if/lacp/%u/%u/state%c", bif->sw_if_index,
661 vec_validate (bm->stats, bif->sw_if_index);
662 vec_validate (bm->stats[bif->sw_if_index], args->slave);
664 args->error = stat_segment_register_state_counter
665 (name, &bm->stats[bif->sw_if_index][args->slave].actor_state);
666 if (args->error != 0)
668 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
673 vec_reset_length (name);
674 name = format (0, "/if/lacp/%u/%u/partner-state%c", bif->sw_if_index,
676 args->error = stat_segment_register_state_counter
677 (name, &bm->stats[bif->sw_if_index][args->slave].partner_state);
679 if (args->error != 0)
681 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
686 pool_get (bm->neighbors, sif);
687 clib_memset (sif, 0, sizeof (*sif));
688 sw = pool_elt_at_index (im->sw_interfaces, args->slave);
689 /* port_enabled is both admin up and hw link up */
690 sif->port_enabled = vnet_sw_interface_is_up (vnm, sw->sw_if_index);
691 sif->sw_if_index = sw->sw_if_index;
692 sif->hw_if_index = sw->hw_if_index;
693 sif->packet_template_index = (u8) ~ 0;
694 sif->is_passive = args->is_passive;
695 sif->group = args->group;
696 sif->bif_dev_instance = bif->dev_instance;
697 sif->mode = bif->mode;
699 sif->is_long_timeout = args->is_long_timeout;
700 if (args->is_long_timeout)
701 sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
703 sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
705 vec_validate_aligned (bm->slave_by_sw_if_index, sif->sw_if_index,
706 CLIB_CACHE_LINE_BYTES);
708 * sif - bm->neighbors may be 0
709 * Left shift it by 1 bit to distinguish the valid entry that we actually
710 * store from the null entries
712 bm->slave_by_sw_if_index[sif->sw_if_index] =
713 (uword) (((sif - bm->neighbors) << 1) | 1);
714 vec_add1 (bif->slaves, sif->sw_if_index);
716 sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
718 /* Save the old mac */
719 memcpy (sif->persistent_hw_address, sif_hw->hw_address, 6);
720 bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
721 if (bif->use_custom_mac)
723 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
728 // bond interface gets the mac address from the first slave
729 if (vec_len (bif->slaves) == 1)
731 memcpy (bif->hw_address, sif_hw->hw_address, 6);
732 vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index,
737 // subsequent slaves gets the mac address of the bond interface
738 vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index,
743 /* if there are secondary/virtual mac addrs, propagate to the slave */
744 bond_slave_add_del_mac_addrs (bif, sif->sw_if_index, 1 /* is_add */ );
746 if (bif_hw->l2_if_count)
747 ethernet_set_flags (vnm, sif_hw->hw_if_index,
748 ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
750 ethernet_set_flags (vnm, sif_hw->hw_if_index,
751 /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0);
753 if (bif->mode == BOND_MODE_LACP)
755 if (bm->lacp_enable_disable)
756 (*bm->lacp_enable_disable) (vm, bif, sif, 1);
758 else if (sif->port_enabled)
760 bond_enable_collecting_distributing (vm, sif);
763 vec_foreach_index (thread_index, bm->per_thread_data)
765 bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
768 vec_validate_aligned (ptd->per_port_queue, vec_len (bif->slaves) - 1,
769 CLIB_CACHE_LINE_BYTES);
771 vec_foreach_index (sif_if_index, ptd->per_port_queue)
773 ptd->per_port_queue[sif_if_index].n_buffers = 0;
777 args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
778 sif->sw_if_index, 1, 0, 0);
783 clib_error_return (0,
784 "Error encountered on input feature arc enable");
788 static clib_error_t *
789 enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
790 vlib_cli_command_t * cmd)
792 bond_enslave_args_t args = { 0 };
793 unformat_input_t _line_input, *line_input = &_line_input;
794 vnet_main_t *vnm = vnet_get_main ();
796 /* Get a line of input. */
797 if (!unformat_user (input, unformat_line_input, line_input))
798 return clib_error_return (0, "Missing required arguments.");
802 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
804 if (unformat (line_input, "%U %U",
805 unformat_vnet_sw_interface, vnm, &args.group,
806 unformat_vnet_sw_interface, vnm, &args.slave))
808 else if (unformat (line_input, "passive"))
810 else if (unformat (line_input, "long-timeout"))
811 args.is_long_timeout = 1;
814 args.error = clib_error_return (0, "unknown input `%U'",
815 format_unformat_error, input);
819 unformat_free (line_input);
823 if (args.group == ~0)
824 return clib_error_return (0, "Missing bond interface");
825 if (args.slave == ~0)
826 return clib_error_return (0, "please specify valid slave interface name");
828 bond_enslave (vm, &args);
834 VLIB_CLI_COMMAND (enslave_interface_command, static) = {
836 .short_help = "bond add <BondEthernetx> <slave-interface> "
837 "[passive] [long-timeout]",
838 .function = enslave_interface_command_fn,
843 bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args)
848 sif = bond_get_slave_by_sw_if_index (args->slave);
851 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
852 args->error = clib_error_return (0, "interface was not enslaved");
855 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
856 bond_delete_neighbor (vm, bif, sif);
859 static clib_error_t *
860 detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
861 vlib_cli_command_t * cmd)
863 bond_detach_slave_args_t args = { 0 };
864 unformat_input_t _line_input, *line_input = &_line_input;
865 vnet_main_t *vnm = vnet_get_main ();
867 /* Get a line of input. */
868 if (!unformat_user (input, unformat_line_input, line_input))
869 return clib_error_return (0, "Missing required arguments.");
872 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
874 if (unformat (line_input, "%U",
875 unformat_vnet_sw_interface, vnm, &args.slave))
879 args.error = clib_error_return (0, "unknown input `%U'",
880 format_unformat_error, input);
884 unformat_free (line_input);
888 if (args.slave == ~0)
889 return clib_error_return (0, "please specify valid slave interface name");
891 bond_detach_slave (vm, &args);
897 VLIB_CLI_COMMAND (detach_interface_command, static) = {
899 .short_help = "bond del <slave-interface>",
900 .function = detach_interface_command_fn,
905 show_bond (vlib_main_t * vm)
907 bond_main_t *bm = &bond_main;
910 vlib_cli_output (vm, "%-16s %-12s %-13s %-13s %-14s %s",
911 "interface name", "sw_if_index", "mode",
912 "load balance", "active slaves", "slaves");
915 pool_foreach (bif, bm->interfaces,
917 vlib_cli_output (vm, "%-16U %-12d %-13U %-13U %-14u %u",
918 format_bond_interface_name, bif->dev_instance,
919 bif->sw_if_index, format_bond_mode, bif->mode,
920 format_bond_load_balance, bif->lb,
921 vec_len (bif->active_slaves), vec_len (bif->slaves));
927 show_bond_details (vlib_main_t * vm)
929 bond_main_t *bm = &bond_main;
934 pool_foreach (bif, bm->interfaces,
936 vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
937 vlib_cli_output (vm, " mode: %U",
938 format_bond_mode, bif->mode);
939 vlib_cli_output (vm, " load balance: %U",
940 format_bond_load_balance, bif->lb);
942 vlib_cli_output (vm, " gso enable");
943 if (bif->mode == BOND_MODE_ROUND_ROBIN)
944 vlib_cli_output (vm, " last xmit slave index: %u",
945 bif->lb_rr_last_index);
946 vlib_cli_output (vm, " number of active slaves: %d",
947 vec_len (bif->active_slaves));
948 vec_foreach (sw_if_index, bif->active_slaves)
950 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
951 vnet_get_main (), *sw_if_index);
952 if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
954 slave_if_t *sif = bond_get_slave_by_sw_if_index (*sw_if_index);
956 vlib_cli_output (vm, " weight: %u, is_local_numa: %u, "
957 "sw_if_index: %u", sif->weight,
958 sif->is_local_numa, sif->sw_if_index);
961 vlib_cli_output (vm, " number of slaves: %d", vec_len (bif->slaves));
962 vec_foreach (sw_if_index, bif->slaves)
964 vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name,
965 vnet_get_main (), *sw_if_index);
967 vlib_cli_output (vm, " device instance: %d", bif->dev_instance);
968 vlib_cli_output (vm, " interface id: %d", bif->id);
969 vlib_cli_output (vm, " sw_if_index: %d", bif->sw_if_index);
970 vlib_cli_output (vm, " hw_if_index: %d", bif->hw_if_index);
975 static clib_error_t *
976 show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
977 vlib_cli_command_t * cmd)
981 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
983 if (unformat (input, "details"))
987 return clib_error_return (0, "unknown input `%U'",
988 format_unformat_error, input);
993 show_bond_details (vm);
1001 VLIB_CLI_COMMAND (show_bond_command, static) = {
1002 .path = "show bond",
1003 .short_help = "show bond [details]",
1004 .function = show_bond_fn,
1009 bond_set_intf_weight (vlib_main_t * vm, bond_set_intf_weight_args_t * args)
1016 sif = bond_get_slave_by_sw_if_index (args->sw_if_index);
1019 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1020 args->error = clib_error_return (0, "Interface not enslaved");
1023 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
1026 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1027 args->error = clib_error_return (0, "bond interface not found");
1030 if (bif->mode != BOND_MODE_ACTIVE_BACKUP)
1032 args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
1034 clib_error_return (0, "Weight valid for active-backup only");
1038 old_weight = sif->weight;
1039 sif->weight = args->weight;
1040 vnm = vnet_get_main ();
1042 * No need to sort the list if the affected slave is not up (not in active
1043 * slave set), active slave count is 1, or the current slave is already the
1044 * primary slave and new weight > old weight.
1046 if (!vnet_sw_interface_is_up (vnm, sif->sw_if_index) ||
1047 (vec_len (bif->active_slaves) == 1) ||
1048 ((bif->active_slaves[0] == sif->sw_if_index) &&
1049 (sif->weight >= old_weight)))
1052 bond_sort_slaves (bif);
1055 static clib_error_t *
1056 bond_set_intf_cmd (vlib_main_t * vm, unformat_input_t * input,
1057 vlib_cli_command_t * cmd)
1059 bond_set_intf_weight_args_t args = { 0 };
1060 u32 sw_if_index = (u32) ~ 0;
1061 unformat_input_t _line_input, *line_input = &_line_input;
1062 vnet_main_t *vnm = vnet_get_main ();
1063 u8 weight_enter = 0;
1066 /* Get a line of input. */
1067 if (!unformat_user (input, unformat_line_input, line_input))
1068 return clib_error_return (0, "Missing required arguments.");
1070 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1072 if (unformat (line_input, "sw_if_index %d", &sw_if_index))
1074 else if (unformat (line_input, "%U", unformat_vnet_sw_interface, vnm,
1077 else if (unformat (line_input, "weight %u", &weight))
1081 clib_error_return (0, "unknown input `%U'", format_unformat_error,
1087 unformat_free (line_input);
1088 if (sw_if_index == (u32) ~ 0)
1090 args.rv = VNET_API_ERROR_INVALID_INTERFACE;
1091 clib_error_return (0, "Interface name is invalid!");
1093 if (weight_enter == 0)
1095 args.rv = VNET_API_ERROR_INVALID_ARGUMENT;
1096 clib_error_return (0, "weight missing");
1099 args.sw_if_index = sw_if_index;
1100 args.weight = weight;
1101 bond_set_intf_weight (vm, &args);
1107 VLIB_CLI_COMMAND(set_interface_bond_cmd, static) = {
1108 .path = "set interface bond",
1109 .short_help = "set interface bond <interface> | sw_if_index <idx>"
1111 .function = bond_set_intf_cmd,
1116 bond_cli_init (vlib_main_t * vm)
1118 bond_main_t *bm = &bond_main;
1121 bm->vnet_main = vnet_get_main ();
1122 vec_validate_aligned (bm->slave_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES);
1123 vec_validate_aligned (bm->per_thread_data,
1124 vlib_get_thread_main ()->n_vlib_mains - 1,
1125 CLIB_CACHE_LINE_BYTES);
1130 VLIB_INIT_FUNCTION (bond_cli_init);
1133 * fd.io coding-style-patch-verification: ON
1136 * eval: (c-set-style "gnu")