X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Fbonding%2Fcli.c;h=062e30926408b7161ca12cce08bba541ad0896ca;hb=4c4223edf;hp=371e3c1012c91b6bd699308ed712d5a83a6d3341;hpb=751e3f3824fc1a318f8c71ade664bd13c16b335e;p=vpp.git diff --git a/src/vnet/bonding/cli.c b/src/vnet/bonding/cli.c index 371e3c1012c..062e3092640 100644 --- a/src/vnet/bonding/cli.c +++ b/src/vnet/bonding/cli.c @@ -20,152 +20,157 @@ #include #include #include +#include void -bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif) +bond_disable_collecting_distributing (vlib_main_t * vm, member_if_t * mif) { bond_main_t *bm = &bond_main; bond_if_t *bif; int i; uword p; - vnet_main_t *vnm = vnet_get_main (); - vnet_hw_interface_t *hw; u8 switching_active = 0; - bif = bond_get_master_by_dev_instance (sif->bif_dev_instance); + bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance); clib_spinlock_lock_if_init (&bif->lockp); - vec_foreach_index (i, bif->active_slaves) + vec_foreach_index (i, bif->active_members) { - p = *vec_elt_at_index (bif->active_slaves, i); - if (p == sif->sw_if_index) + p = *vec_elt_at_index (bif->active_members, i); + if (p == mif->sw_if_index) { - if (sif->sw_if_index == bif->sw_if_index_working) - { - switching_active = 1; - if (bif->mode == BOND_MODE_ACTIVE_BACKUP) - bif->is_local_numa = 0; - } - vec_del1 (bif->active_slaves, i); - hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index); - if (sif->lacp_enabled && bif->numa_only) + if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && (i == 0) && + (vec_len (bif->active_members) > 1)) + /* deleting the active member for active-backup */ + switching_active = 1; + vec_del1 (bif->active_members, i); + if (mif->lacp_enabled && bif->numa_only) { - /* For lacp mode, if we check it is a slave on local numa node, - bif->n_numa_slaves should be decreased by 1 becasue the first - bif->n_numa_slaves are all slaves on local numa node */ - if (i < bif->n_numa_slaves) + /* For lacp mode, if we check it is a member on local numa node, + bif->n_numa_members should be decreased by 1 becasue the first + bif->n_numa_members are all members on local numa node */ + if (i < bif->n_numa_members) { - bif->n_numa_slaves--; - ASSERT (bif->n_numa_slaves >= 0); + bif->n_numa_members--; + ASSERT (bif->n_numa_members >= 0); } } break; } } - /* We get a new slave just becoming active */ - if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && switching_active) - { - if ((vec_len (bif->active_slaves) >= 1)) - { - /* scan all slaves and try to find the first slave with local numa node. */ - vec_foreach_index (i, bif->active_slaves) - { - p = *vec_elt_at_index (bif->active_slaves, i); - hw = vnet_get_sup_hw_interface (vnm, p); - if (vm->numa_node == hw->numa_node) - { - bif->sw_if_index_working = p; - bif->is_local_numa = 1; - vlib_process_signal_event (bm->vlib_main, - bond_process_node.index, - BOND_SEND_GARP_NA, - bif->hw_if_index); - break; - } - } - } + /* We get a new member just becoming active */ + if (switching_active) + vlib_process_signal_event (bm->vlib_main, bond_process_node.index, + BOND_SEND_GARP_NA, bif->hw_if_index); + clib_spinlock_unlock_if_init (&bif->lockp); +} + +/* + * return 1 if s2 is preferred. + * return -1 if s1 is preferred. + */ +static int +bond_member_sort (void *a1, void *a2) +{ + u32 *s1 = a1; + u32 *s2 = a2; + member_if_t *mif1 = bond_get_member_by_sw_if_index (*s1); + member_if_t *mif2 = bond_get_member_by_sw_if_index (*s2); + bond_if_t *bif; - /* No local numa node is found in the active slave set. Use the first slave */ - if ((bif->is_local_numa == 0) && (vec_len (bif->active_slaves) >= 1)) + ALWAYS_ASSERT (mif1); + ALWAYS_ASSERT (mif2); + /* + * sort entries according to preference rules: + * 1. biggest weight + * 2. numa-node + * 3. current active member (to prevent churning) + * 4. lowest sw_if_index (for deterministic behavior) + * + */ + if (mif2->weight > mif1->weight) + return 1; + if (mif2->weight < mif1->weight) + return -1; + else + { + if (mif2->is_local_numa > mif1->is_local_numa) + return 1; + if (mif2->is_local_numa < mif1->is_local_numa) + return -1; + else { - p = *vec_elt_at_index (bif->active_slaves, 0); - bif->sw_if_index_working = p; - vlib_process_signal_event (bm->vlib_main, bond_process_node.index, - BOND_SEND_GARP_NA, bif->hw_if_index); + bif = bond_get_bond_if_by_dev_instance (mif1->bif_dev_instance); + /* Favor the current active member to avoid churning */ + if (bif->active_members[0] == mif2->sw_if_index) + return 1; + if (bif->active_members[0] == mif1->sw_if_index) + return -1; + /* go for the tiebreaker as the last resort */ + if (mif1->sw_if_index > mif2->sw_if_index) + return 1; + if (mif1->sw_if_index < mif2->sw_if_index) + return -1; + else + ASSERT (0); } } - clib_spinlock_unlock_if_init (&bif->lockp); + return 0; +} + +static void +bond_sort_members (bond_if_t * bif) +{ + bond_main_t *bm = &bond_main; + u32 old_active = bif->active_members[0]; - return; + vec_sort_with_function (bif->active_members, bond_member_sort); + if (old_active != bif->active_members[0]) + vlib_process_signal_event (bm->vlib_main, bond_process_node.index, + BOND_SEND_GARP_NA, bif->hw_if_index); } void -bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif) +bond_enable_collecting_distributing (vlib_main_t * vm, member_if_t * mif) { bond_if_t *bif; bond_main_t *bm = &bond_main; vnet_main_t *vnm = vnet_get_main (); - vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index); + vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index); int i; uword p; - bif = bond_get_master_by_dev_instance (sif->bif_dev_instance); + bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance); clib_spinlock_lock_if_init (&bif->lockp); - if (!hash_get (bif->active_slave_by_sw_if_index, sif->sw_if_index)) + vec_foreach_index (i, bif->active_members) + { + p = *vec_elt_at_index (bif->active_members, i); + if (p == mif->sw_if_index) + goto done; + } + + if (mif->lacp_enabled && bif->numa_only && (vm->numa_node == hw->numa_node)) { - hash_set (bif->active_slave_by_sw_if_index, sif->sw_if_index, - sif->sw_if_index); + vec_insert_elts (bif->active_members, &mif->sw_if_index, 1, + bif->n_numa_members); + bif->n_numa_members++; + } + else + vec_add1 (bif->active_members, mif->sw_if_index); - if ((sif->lacp_enabled && bif->numa_only) - && (vm->numa_node == hw->numa_node)) - { - vec_insert_elts (bif->active_slaves, &sif->sw_if_index, 1, - bif->n_numa_slaves); - bif->n_numa_slaves++; - } + mif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0; + if (bif->mode == BOND_MODE_ACTIVE_BACKUP) + { + if (vec_len (bif->active_members) == 1) + /* First member becomes active? */ + vlib_process_signal_event (bm->vlib_main, bond_process_node.index, + BOND_SEND_GARP_NA, bif->hw_if_index); else - { - vec_add1 (bif->active_slaves, sif->sw_if_index); - } - - /* First slave becomes active? */ - if ((vec_len (bif->active_slaves) == 1) && - (bif->mode == BOND_MODE_ACTIVE_BACKUP)) - { - bif->sw_if_index_working = sif->sw_if_index; - bif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0; - vlib_process_signal_event (bm->vlib_main, bond_process_node.index, - BOND_SEND_GARP_NA, bif->hw_if_index); - } - else if ((vec_len (bif->active_slaves) > 1) - && (bif->mode == BOND_MODE_ACTIVE_BACKUP) - && bif->is_local_numa == 0) - { - if (vm->numa_node == hw->numa_node) - { - vec_foreach_index (i, bif->active_slaves) - { - p = *vec_elt_at_index (bif->active_slaves, 0); - if (p == sif->sw_if_index) - break; - - vec_del1 (bif->active_slaves, 0); - hash_unset (bif->active_slave_by_sw_if_index, p); - vec_add1 (bif->active_slaves, p); - hash_set (bif->active_slave_by_sw_if_index, p, p); - } - bif->sw_if_index_working = sif->sw_if_index; - bif->is_local_numa = 1; - vlib_process_signal_event (bm->vlib_main, - bond_process_node.index, - BOND_SEND_GARP_NA, bif->hw_if_index); - - } - } + bond_sort_members (bif); } - clib_spinlock_unlock_if_init (&bif->lockp); - return; +done: + clib_spinlock_unlock_if_init (&bif->lockp); } int @@ -187,12 +192,14 @@ bond_dump_ifs (bond_interface_details_t ** out_bondifs) hi = vnet_get_hw_interface (vnm, bif->hw_if_index); clib_memcpy(bondif->interface_name, hi->name, MIN (ARRAY_LEN (bondif->interface_name) - 1, - strlen ((const char *) hi->name))); + vec_len ((const char *) hi->name))); + /* enforce by memset() above */ + ASSERT(0 == bondif->interface_name[ARRAY_LEN (bondif->interface_name) - 1]); bondif->mode = bif->mode; bondif->lb = bif->lb; bondif->numa_only = bif->numa_only; - bondif->active_slaves = vec_len (bif->active_slaves); - bondif->slaves = vec_len (bif->slaves); + bondif->active_members = vec_len (bif->active_members); + bondif->members = vec_len (bif->members); ); /* *INDENT-ON* */ @@ -202,83 +209,127 @@ bond_dump_ifs (bond_interface_details_t ** out_bondifs) } int -bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs, - u32 bond_sw_if_index) +bond_dump_member_ifs (member_interface_details_t ** out_memberifs, + u32 bond_sw_if_index) { vnet_main_t *vnm = vnet_get_main (); bond_if_t *bif; vnet_hw_interface_t *hi; vnet_sw_interface_t *sw; - slave_interface_details_t *r_slaveifs = NULL; - slave_interface_details_t *slaveif = NULL; + member_interface_details_t *r_memberifs = NULL; + member_interface_details_t *memberif = NULL; u32 *sw_if_index = NULL; - slave_if_t *sif; + member_if_t *mif; - bif = bond_get_master_by_sw_if_index (bond_sw_if_index); + bif = bond_get_bond_if_by_sw_if_index (bond_sw_if_index); if (!bif) return 1; - vec_foreach (sw_if_index, bif->slaves) + vec_foreach (sw_if_index, bif->members) { - vec_add2 (r_slaveifs, slaveif, 1); - clib_memset (slaveif, 0, sizeof (*slaveif)); - sif = bond_get_slave_by_sw_if_index (*sw_if_index); - if (sif) + vec_add2 (r_memberifs, memberif, 1); + clib_memset (memberif, 0, sizeof (*memberif)); + mif = bond_get_member_by_sw_if_index (*sw_if_index); + if (mif) { - sw = vnet_get_sw_interface (vnm, sif->sw_if_index); + sw = vnet_get_sw_interface (vnm, mif->sw_if_index); hi = vnet_get_hw_interface (vnm, sw->hw_if_index); - clib_memcpy (slaveif->interface_name, hi->name, - MIN (ARRAY_LEN (slaveif->interface_name) - 1, - strlen ((const char *) hi->name))); - slaveif->sw_if_index = sif->sw_if_index; - slaveif->is_passive = sif->is_passive; - slaveif->is_long_timeout = sif->is_long_timeout; + clib_memcpy (memberif->interface_name, hi->name, + MIN (ARRAY_LEN (memberif->interface_name) - 1, + vec_len ((const char *) hi->name))); + /* enforce by memset() above */ + ASSERT (0 == + memberif->interface_name[ARRAY_LEN (memberif->interface_name) + - 1]); + memberif->sw_if_index = mif->sw_if_index; + memberif->is_passive = mif->is_passive; + memberif->is_long_timeout = mif->is_long_timeout; + memberif->is_local_numa = mif->is_local_numa; + memberif->weight = mif->weight; } } - *out_slaveifs = r_slaveifs; + *out_memberifs = r_memberifs; return 0; } +/* + * Manage secondary mac addresses when attaching/detaching a member. + * If adding, copy any secondary addresses from bond interface to member. + * If deleting, delete the bond interface's secondary addresses from the + * member. + */ +static void +bond_member_add_del_mac_addrs (bond_if_t * bif, u32 mif_sw_if_index, + u8 is_add) +{ + vnet_main_t *vnm = vnet_get_main (); + ethernet_interface_t *b_ei; + mac_address_t *sec_mac; + vnet_hw_interface_t *s_hwif; + + b_ei = ethernet_get_interface (ðernet_main, bif->hw_if_index); + if (!b_ei || !b_ei->secondary_addrs) + return; + + s_hwif = vnet_get_sup_hw_interface (vnm, mif_sw_if_index); + + vec_foreach (sec_mac, b_ei->secondary_addrs) + vnet_hw_interface_add_del_mac_address (vnm, s_hwif->hw_if_index, + sec_mac->bytes, is_add); +} + static void -bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif) +bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, member_if_t * mif) { bond_main_t *bm = &bond_main; vnet_main_t *vnm = vnet_get_main (); int i; - vnet_hw_interface_t *sif_hw; + vnet_hw_interface_t *mif_hw; - sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index); + mif_hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index); bif->port_number_bitmap = clib_bitmap_set (bif->port_number_bitmap, - ntohs (sif->actor_admin.port_number) - 1, 0); - bm->slave_by_sw_if_index[sif->sw_if_index] = 0; - vec_free (sif->last_marker_pkt); - vec_free (sif->last_rx_pkt); - vec_foreach_index (i, bif->slaves) + ntohs (mif->actor_admin.port_number) - 1, 0); + bm->member_by_sw_if_index[mif->sw_if_index] = 0; + vec_free (mif->last_marker_pkt); + vec_free (mif->last_rx_pkt); + vec_foreach_index (i, bif->members) { - uword p = *vec_elt_at_index (bif->slaves, i); - if (p == sif->sw_if_index) + uword p = *vec_elt_at_index (bif->members, i); + if (p == mif->sw_if_index) { - vec_del1 (bif->slaves, i); + vec_del1 (bif->members, i); break; } } - bond_disable_collecting_distributing (vm, sif); + bond_disable_collecting_distributing (vm, mif); vnet_feature_enable_disable ("device-input", "bond-input", - sif_hw->hw_if_index, 0, 0, 0); + mif->sw_if_index, 0, 0, 0); /* Put back the old mac */ - vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index, - sif->persistent_hw_address); + vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index, + mif->persistent_hw_address); + + /* delete the bond's secondary/virtual mac addrs from the member */ + bond_member_add_del_mac_addrs (bif, mif->sw_if_index, 0 /* is_add */ ); + if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable) - (*bm->lacp_enable_disable) (vm, bif, sif, 0); + (*bm->lacp_enable_disable) (vm, bif, mif, 0); + + if (bif->mode == BOND_MODE_LACP) + { + stat_segment_deregister_state_counter + (bm->stats[bif->sw_if_index][mif->sw_if_index].actor_state); + stat_segment_deregister_state_counter + (bm->stats[bif->sw_if_index][mif->sw_if_index].partner_state); + } - pool_put (bm->neighbors, sif); + pool_put (bm->neighbors, mif); } int @@ -287,33 +338,25 @@ bond_delete_if (vlib_main_t * vm, u32 sw_if_index) bond_main_t *bm = &bond_main; vnet_main_t *vnm = vnet_get_main (); bond_if_t *bif; - slave_if_t *sif; + member_if_t *mif; vnet_hw_interface_t *hw; - u32 *sif_sw_if_index; - u32 **s_list = 0; - u32 i; + u32 *mif_sw_if_index; + u32 *s_list = 0; hw = vnet_get_sup_hw_interface (vnm, sw_if_index); if (hw == NULL || bond_dev_class.index != hw->dev_class_index) return VNET_API_ERROR_INVALID_SW_IF_INDEX; - bif = bond_get_master_by_dev_instance (hw->dev_instance); + bif = bond_get_bond_if_by_dev_instance (hw->dev_instance); - vec_foreach (sif_sw_if_index, bif->slaves) + vec_append (s_list, bif->members); + vec_foreach (mif_sw_if_index, s_list) { - vec_add1 (s_list, sif_sw_if_index); + mif = bond_get_member_by_sw_if_index (*mif_sw_if_index); + if (mif) + bond_delete_neighbor (vm, bif, mif); } - - for (i = 0; i < vec_len (s_list); i++) - { - sif_sw_if_index = s_list[i]; - sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index); - if (sif) - bond_delete_neighbor (vm, bif, sif); - } - - if (s_list) - vec_free (s_list); + vec_free (s_list); /* bring down the interface */ vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0); @@ -337,6 +380,7 @@ bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args) vnet_main_t *vnm = vnet_get_main (); vnet_sw_interface_t *sw; bond_if_t *bif; + vnet_hw_interface_t *hw; if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0) { @@ -362,6 +406,7 @@ bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args) bif->id = args->id; bif->lb = args->lb; bif->mode = args->mode; + bif->gso = args->gso; // Adjust requested interface id if (bif->id == ~0) @@ -412,6 +457,16 @@ bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args) bif->sw_if_index = sw->sw_if_index; bif->group = bif->sw_if_index; bif->numa_only = args->numa_only; + + hw = vnet_get_hw_interface (vnm, bif->hw_if_index); + /* + * Add GSO and Checksum offload flags if GSO is enabled on Bond + */ + if (args->gso) + { + hw->flags |= (VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO | + VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD); + } if (vlib_get_thread_main ()->n_vlib_mains > 1) clib_spinlock_init (&bif->lockp); @@ -422,6 +477,7 @@ bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args) // for return args->sw_if_index = bif->sw_if_index; + args->rv = 0; } static clib_error_t * @@ -439,6 +495,7 @@ bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input, args.id = ~0; args.mode = -1; args.lb = BOND_LB_L2; + args.rv = -1; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode)) @@ -452,6 +509,8 @@ bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input, args.hw_addr_set = 1; else if (unformat (line_input, "id %u", &args.id)) ; + else if (unformat (line_input, "gso")) + args.gso = 1; else if (unformat (line_input, "numa-only")) { if (args.mode == BOND_MODE_LACP) @@ -471,6 +530,10 @@ bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input, bond_create_if (vm, &args); + if (!args.rv) + vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, + vnet_get_main (), args.sw_if_index); + return args.error; } @@ -478,8 +541,8 @@ bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input, VLIB_CLI_COMMAND (bond_create_command, static) = { .path = "create bond", .short_help = "create bond mode {round-robin | active-backup | broadcast | " - "{lacp | xor} [load-balance { l2 | l23 | l34 } {numa-only}]} [hw-addr ] " - "[id ]", + "{lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} " + "[hw-addr ] [id ] [gso]", .function = bond_create_command_fn, }; /* *INDENT-ON* */ @@ -533,113 +596,153 @@ VLIB_CLI_COMMAND (bond_delete__command, static) = /* *INDENT-ON* */ void -bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args) +bond_add_member (vlib_main_t * vm, bond_add_member_args_t * args) { bond_main_t *bm = &bond_main; vnet_main_t *vnm = vnet_get_main (); bond_if_t *bif; - slave_if_t *sif; + member_if_t *mif; vnet_interface_main_t *im = &vnm->interface_main; - vnet_hw_interface_t *bif_hw, *sif_hw; + vnet_hw_interface_t *bif_hw, *mif_hw; vnet_sw_interface_t *sw; u32 thread_index; - u32 sif_if_index; + u32 mif_if_index; - bif = bond_get_master_by_sw_if_index (args->group); + bif = bond_get_bond_if_by_sw_if_index (args->group); if (!bif) { args->rv = VNET_API_ERROR_INVALID_INTERFACE; args->error = clib_error_return (0, "bond interface not found"); return; } - // make sure the interface is not already enslaved - if (bond_get_slave_by_sw_if_index (args->slave)) + // make sure the interface is not already added as member + if (bond_get_member_by_sw_if_index (args->member)) { args->rv = VNET_API_ERROR_VALUE_EXIST; - args->error = clib_error_return (0, "interface was already enslaved"); + args->error = clib_error_return + (0, "interface was already added as member"); + return; + } + mif_hw = vnet_get_sup_hw_interface (vnm, args->member); + if (mif_hw->dev_class_index == bond_dev_class.index) + { + args->rv = VNET_API_ERROR_INVALID_INTERFACE; + args->error = + clib_error_return (0, "bond interface cannot be added as member"); return; } - sif_hw = vnet_get_sup_hw_interface (vnm, args->slave); - if (sif_hw->dev_class_index == bond_dev_class.index) + if (bif->gso && !(mif_hw->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)) { args->rv = VNET_API_ERROR_INVALID_INTERFACE; args->error = - clib_error_return (0, "bond interface cannot be enslaved"); + clib_error_return (0, "member interface is not gso capable"); return; } - pool_get (bm->neighbors, sif); - clib_memset (sif, 0, sizeof (*sif)); - sw = pool_elt_at_index (im->sw_interfaces, args->slave); - sif->port_enabled = sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP; - sif->sw_if_index = sw->sw_if_index; - sif->hw_if_index = sw->hw_if_index; - sif->packet_template_index = (u8) ~ 0; - sif->is_passive = args->is_passive; - sif->group = args->group; - sif->bif_dev_instance = bif->dev_instance; - sif->mode = bif->mode; - - sif->is_long_timeout = args->is_long_timeout; + if (bif->mode == BOND_MODE_LACP) + { + u8 *name = format (0, "/if/lacp/%u/%u/state%c", bif->sw_if_index, + args->member, 0); + + vec_validate (bm->stats, bif->sw_if_index); + vec_validate (bm->stats[bif->sw_if_index], args->member); + + args->error = stat_segment_register_state_counter + (name, &bm->stats[bif->sw_if_index][args->member].actor_state); + if (args->error != 0) + { + args->rv = VNET_API_ERROR_INVALID_INTERFACE; + vec_free (name); + return; + } + + vec_reset_length (name); + name = format (0, "/if/lacp/%u/%u/partner-state%c", bif->sw_if_index, + args->member, 0); + args->error = stat_segment_register_state_counter + (name, &bm->stats[bif->sw_if_index][args->member].partner_state); + vec_free (name); + if (args->error != 0) + { + args->rv = VNET_API_ERROR_INVALID_INTERFACE; + return; + } + } + + pool_get (bm->neighbors, mif); + clib_memset (mif, 0, sizeof (*mif)); + sw = pool_elt_at_index (im->sw_interfaces, args->member); + /* port_enabled is both admin up and hw link up */ + mif->port_enabled = vnet_sw_interface_is_up (vnm, sw->sw_if_index); + mif->sw_if_index = sw->sw_if_index; + mif->hw_if_index = sw->hw_if_index; + mif->packet_template_index = (u8) ~ 0; + mif->is_passive = args->is_passive; + mif->group = args->group; + mif->bif_dev_instance = bif->dev_instance; + mif->mode = bif->mode; + + mif->is_long_timeout = args->is_long_timeout; if (args->is_long_timeout) - sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME; + mif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME; else - sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME; + mif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME; - vec_validate_aligned (bm->slave_by_sw_if_index, sif->sw_if_index, + vec_validate_aligned (bm->member_by_sw_if_index, mif->sw_if_index, CLIB_CACHE_LINE_BYTES); /* - * sif - bm->neighbors may be 0 + * mif - bm->neighbors may be 0 * Left shift it by 1 bit to distinguish the valid entry that we actually * store from the null entries */ - bm->slave_by_sw_if_index[sif->sw_if_index] = - (uword) (((sif - bm->neighbors) << 1) | 1); - vec_add1 (bif->slaves, sif->sw_if_index); + bm->member_by_sw_if_index[mif->sw_if_index] = + (uword) (((mif - bm->neighbors) << 1) | 1); + vec_add1 (bif->members, mif->sw_if_index); - sif_hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index); + mif_hw = vnet_get_sup_hw_interface (vnm, mif->sw_if_index); /* Save the old mac */ - memcpy (sif->persistent_hw_address, sif_hw->hw_address, 6); + memcpy (mif->persistent_hw_address, mif_hw->hw_address, 6); bif_hw = vnet_get_sup_hw_interface (vnm, bif->sw_if_index); if (bif->use_custom_mac) { - vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index, + vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index, bif->hw_address); } else { - // bond interface gets the mac address from the first slave - if (vec_len (bif->slaves) == 1) + // bond interface gets the mac address from the first member + if (vec_len (bif->members) == 1) { - memcpy (bif->hw_address, sif_hw->hw_address, 6); + memcpy (bif->hw_address, mif_hw->hw_address, 6); vnet_hw_interface_change_mac_address (vnm, bif_hw->hw_if_index, - sif_hw->hw_address); + mif_hw->hw_address); } else { - // subsequent slaves gets the mac address of the bond interface - vnet_hw_interface_change_mac_address (vnm, sif_hw->hw_if_index, + // subsequent members gets the mac address of the bond interface + vnet_hw_interface_change_mac_address (vnm, mif_hw->hw_if_index, bif->hw_address); } } + /* if there are secondary/virtual mac addrs, propagate to the member */ + bond_member_add_del_mac_addrs (bif, mif->sw_if_index, 1 /* is_add */ ); + if (bif_hw->l2_if_count) - { - ethernet_set_flags (vnm, sif_hw->hw_if_index, - ETHERNET_INTERFACE_FLAG_ACCEPT_ALL); - /* ensure all packets go to ethernet-input */ - ethernet_set_rx_redirect (vnm, sif_hw, 1); - } + ethernet_set_flags (vnm, mif_hw->hw_if_index, + ETHERNET_INTERFACE_FLAG_ACCEPT_ALL); + else + ethernet_set_flags (vnm, mif_hw->hw_if_index, + /*ETHERNET_INTERFACE_FLAG_DEFAULT_L3 */ 0); if (bif->mode == BOND_MODE_LACP) { if (bm->lacp_enable_disable) - (*bm->lacp_enable_disable) (vm, bif, sif, 1); + (*bm->lacp_enable_disable) (vm, bif, mif, 1); } - else if (sif->port_enabled && - (sif_hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)) + else if (mif->port_enabled) { - bond_enable_collecting_distributing (vm, sif); + bond_enable_collecting_distributing (vm, mif); } vec_foreach_index (thread_index, bm->per_thread_data) @@ -647,17 +750,17 @@ bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args) bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data, thread_index); - vec_validate_aligned (ptd->per_port_queue, vec_len (bif->slaves) - 1, + vec_validate_aligned (ptd->per_port_queue, vec_len (bif->members) - 1, CLIB_CACHE_LINE_BYTES); - vec_foreach_index (sif_if_index, ptd->per_port_queue) + vec_foreach_index (mif_if_index, ptd->per_port_queue) { - ptd->per_port_queue[sif_if_index].n_buffers = 0; + ptd->per_port_queue[mif_if_index].n_buffers = 0; } } args->rv = vnet_feature_enable_disable ("device-input", "bond-input", - sif_hw->hw_if_index, 1, 0, 0); + mif->sw_if_index, 1, 0, 0); if (args->rv) { @@ -668,10 +771,10 @@ bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args) } static clib_error_t * -enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, - vlib_cli_command_t * cmd) +add_member_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) { - bond_enslave_args_t args = { 0 }; + bond_add_member_args_t args = { 0 }; unformat_input_t _line_input, *line_input = &_line_input; vnet_main_t *vnm = vnet_get_main (); @@ -679,13 +782,13 @@ enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, "Missing required arguments."); - args.slave = ~0; + args.member = ~0; args.group = ~0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "%U %U", unformat_vnet_sw_interface, vnm, &args.group, - unformat_vnet_sw_interface, vnm, &args.slave)) + unformat_vnet_sw_interface, vnm, &args.member)) ; else if (unformat (line_input, "passive")) args.is_passive = 1; @@ -704,45 +807,46 @@ enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, return args.error; if (args.group == ~0) return clib_error_return (0, "Missing bond interface"); - if (args.slave == ~0) - return clib_error_return (0, "please specify valid slave interface name"); + if (args.member == ~0) + return clib_error_return (0, + "please specify valid member interface name"); - bond_enslave (vm, &args); + bond_add_member (vm, &args); return args.error; } /* *INDENT-OFF* */ -VLIB_CLI_COMMAND (enslave_interface_command, static) = { +VLIB_CLI_COMMAND (add_member_interface_command, static) = { .path = "bond add", - .short_help = "bond add " + .short_help = "bond add " "[passive] [long-timeout]", - .function = enslave_interface_command_fn, + .function = add_member_interface_command_fn, }; /* *INDENT-ON* */ void -bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args) +bond_detach_member (vlib_main_t * vm, bond_detach_member_args_t * args) { bond_if_t *bif; - slave_if_t *sif; + member_if_t *mif; - sif = bond_get_slave_by_sw_if_index (args->slave); - if (!sif) + mif = bond_get_member_by_sw_if_index (args->member); + if (!mif) { args->rv = VNET_API_ERROR_INVALID_INTERFACE; - args->error = clib_error_return (0, "interface was not enslaved"); + args->error = clib_error_return (0, "interface was not a member"); return; } - bif = bond_get_master_by_dev_instance (sif->bif_dev_instance); - bond_delete_neighbor (vm, bif, sif); + bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance); + bond_delete_neighbor (vm, bif, mif); } static clib_error_t * detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - bond_detach_slave_args_t args = { 0 }; + bond_detach_member_args_t args = { 0 }; unformat_input_t _line_input, *line_input = &_line_input; vnet_main_t *vnm = vnet_get_main (); @@ -750,11 +854,11 @@ detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, "Missing required arguments."); - args.slave = ~0; + args.member = ~0; while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "%U", - unformat_vnet_sw_interface, vnm, &args.slave)) + unformat_vnet_sw_interface, vnm, &args.member)) ; else { @@ -767,10 +871,11 @@ detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, if (args.error) return args.error; - if (args.slave == ~0) - return clib_error_return (0, "please specify valid slave interface name"); + if (args.member == ~0) + return clib_error_return (0, + "please specify valid member interface name"); - bond_detach_slave (vm, &args); + bond_detach_member (vm, &args); return args.error; } @@ -778,7 +883,7 @@ detach_interface_command_fn (vlib_main_t * vm, unformat_input_t * input, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (detach_interface_command, static) = { .path = "bond del", - .short_help = "bond del ", + .short_help = "bond del ", .function = detach_interface_command_fn, }; /* *INDENT-ON* */ @@ -791,7 +896,7 @@ show_bond (vlib_main_t * vm) vlib_cli_output (vm, "%-16s %-12s %-13s %-13s %-14s %s", "interface name", "sw_if_index", "mode", - "load balance", "active slaves", "slaves"); + "load balance", "active members", "members"); /* *INDENT-OFF* */ pool_foreach (bif, bm->interfaces, @@ -800,7 +905,7 @@ show_bond (vlib_main_t * vm) format_bond_interface_name, bif->dev_instance, bif->sw_if_index, format_bond_mode, bif->mode, format_bond_load_balance, bif->lb, - vec_len (bif->active_slaves), vec_len (bif->slaves)); + vec_len (bif->active_members), vec_len (bif->members)); })); /* *INDENT-ON* */ } @@ -820,18 +925,28 @@ show_bond_details (vlib_main_t * vm) format_bond_mode, bif->mode); vlib_cli_output (vm, " load balance: %U", format_bond_load_balance, bif->lb); + if (bif->gso) + vlib_cli_output (vm, " gso enable"); if (bif->mode == BOND_MODE_ROUND_ROBIN) - vlib_cli_output (vm, " last xmit slave index: %u", + vlib_cli_output (vm, " last xmit member index: %u", bif->lb_rr_last_index); - vlib_cli_output (vm, " number of active slaves: %d", - vec_len (bif->active_slaves)); - vec_foreach (sw_if_index, bif->active_slaves) + vlib_cli_output (vm, " number of active members: %d", + vec_len (bif->active_members)); + vec_foreach (sw_if_index, bif->active_members) { vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnet_get_main (), *sw_if_index); + if (bif->mode == BOND_MODE_ACTIVE_BACKUP) + { + member_if_t *mif = bond_get_member_by_sw_if_index (*sw_if_index); + if (mif) + vlib_cli_output (vm, " weight: %u, is_local_numa: %u, " + "sw_if_index: %u", mif->weight, + mif->is_local_numa, mif->sw_if_index); + } } - vlib_cli_output (vm, " number of slaves: %d", vec_len (bif->slaves)); - vec_foreach (sw_if_index, bif->slaves) + vlib_cli_output (vm, " number of members: %d", vec_len (bif->members)); + vec_foreach (sw_if_index, bif->members) { vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnet_get_main (), *sw_if_index); @@ -877,6 +992,113 @@ VLIB_CLI_COMMAND (show_bond_command, static) = { }; /* *INDENT-ON* */ +void +bond_set_intf_weight (vlib_main_t * vm, bond_set_intf_weight_args_t * args) +{ + member_if_t *mif; + bond_if_t *bif; + vnet_main_t *vnm; + u32 old_weight; + + mif = bond_get_member_by_sw_if_index (args->sw_if_index); + if (!mif) + { + args->rv = VNET_API_ERROR_INVALID_INTERFACE; + args->error = clib_error_return (0, "Interface not a member"); + return; + } + bif = bond_get_bond_if_by_dev_instance (mif->bif_dev_instance); + if (!bif) + { + args->rv = VNET_API_ERROR_INVALID_INTERFACE; + args->error = clib_error_return (0, "bond interface not found"); + return; + } + if (bif->mode != BOND_MODE_ACTIVE_BACKUP) + { + args->rv = VNET_API_ERROR_INVALID_ARGUMENT; + args->error = + clib_error_return (0, "Weight valid for active-backup only"); + return; + } + + old_weight = mif->weight; + mif->weight = args->weight; + vnm = vnet_get_main (); + /* + * No need to sort the list if the affected member is not up (not in active + * member set), active member count is 1, or the current member is already the + * primary member and new weight > old weight. + */ + if (!vnet_sw_interface_is_up (vnm, mif->sw_if_index) || + (vec_len (bif->active_members) == 1) || + ((bif->active_members[0] == mif->sw_if_index) && + (mif->weight >= old_weight))) + return; + + bond_sort_members (bif); +} + +static clib_error_t * +bond_set_intf_cmd (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + bond_set_intf_weight_args_t args = { 0 }; + u32 sw_if_index = (u32) ~ 0; + unformat_input_t _line_input, *line_input = &_line_input; + vnet_main_t *vnm = vnet_get_main (); + u8 weight_enter = 0; + u32 weight = 0; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, "Missing required arguments."); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "sw_if_index %d", &sw_if_index)) + ; + else if (unformat (line_input, "%U", unformat_vnet_sw_interface, vnm, + &sw_if_index)) + ; + else if (unformat (line_input, "weight %u", &weight)) + weight_enter = 1; + else + { + clib_error_return (0, "unknown input `%U'", format_unformat_error, + input); + break; + } + } + + unformat_free (line_input); + if (sw_if_index == (u32) ~ 0) + { + args.rv = VNET_API_ERROR_INVALID_INTERFACE; + clib_error_return (0, "Interface name is invalid!"); + } + if (weight_enter == 0) + { + args.rv = VNET_API_ERROR_INVALID_ARGUMENT; + clib_error_return (0, "weight missing"); + } + + args.sw_if_index = sw_if_index; + args.weight = weight; + bond_set_intf_weight (vm, &args); + + return args.error; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND(set_interface_bond_cmd, static) = { + .path = "set interface bond", + .short_help = "set interface bond | sw_if_index " + " weight ", + .function = bond_set_intf_cmd, +}; +/* *INDENT-ON* */ + clib_error_t * bond_cli_init (vlib_main_t * vm) { @@ -884,7 +1106,7 @@ bond_cli_init (vlib_main_t * vm) bm->vlib_main = vm; bm->vnet_main = vnet_get_main (); - vec_validate_aligned (bm->slave_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned (bm->member_by_sw_if_index, 1, CLIB_CACHE_LINE_BYTES); vec_validate_aligned (bm->per_thread_data, vlib_get_thread_main ()->n_vlib_mains - 1, CLIB_CACHE_LINE_BYTES);