summaryrefslogtreecommitdiffstats
path: root/src/vnet/bonding/cli.c
diff options
context:
space:
mode:
authorSteven <sluong@cisco.com>2017-12-20 12:43:01 -0800
committerDamjan Marion <dmarion.lists@gmail.com>2018-03-21 21:02:15 +0000
commit9cd2d7a5a4fafadb65d772c48109d55d1e19d425 (patch)
tree4a9e0665be0096ee6bfc2235388f90b276b23814 /src/vnet/bonding/cli.c
parent43ebe29b6ea1107c30311cfb3dbd8190282903d0 (diff)
bond: Add bonding driver and LACP protocol
Add bonding driver to support creation of bond interface which composes of multiple slave interfaces. The slave interfaces could be physical interfaces, or just any virtual interfaces. For example, memif interfaces. The syntax to create a bond interface is create bond mode <lacp | xor | acitve-backup | broadcast | round-robin> To enslave an interface to the bond interface, enslave interface TenGigabitEthernet6/0/0 to BondEthernet0 Please see src/plugins/lacp/lacp_doc.md for more examples and additional options. LACP is a control plane protocol which manages and monitors the status of the slave interfaces. The protocol is part of 802.3ad standard. This patch implements LACPv1. LACPv2 is not supported. To enable LACP on the bond interface, specify "mode lacp" when the bond interface is created. The syntax to enslave a slave interface is the same as other bonding modes. Change-Id: I06581d3b87635972f9f0e1ec50b67560fc13e26c Signed-off-by: Steven <sluong@cisco.com>
Diffstat (limited to 'src/vnet/bonding/cli.c')
-rw-r--r--src/vnet/bonding/cli.c706
1 files changed, 706 insertions, 0 deletions
diff --git a/src/vnet/bonding/cli.c b/src/vnet/bonding/cli.c
new file mode 100644
index 00000000000..b2d66f9f1c8
--- /dev/null
+++ b/src/vnet/bonding/cli.c
@@ -0,0 +1,706 @@
+/*
+ *------------------------------------------------------------------
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <stdint.h>
+#include <vlib/vlib.h>
+#include <vlib/unix/unix.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/bonding/node.h>
+
+void
+bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
+{
+ bond_if_t *bif;
+ int i;
+ uword p;
+
+ bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
+ vec_foreach_index (i, bif->active_slaves)
+ {
+ p = *vec_elt_at_index (bif->active_slaves, i);
+ if (p == sif->sw_if_index)
+ {
+ vec_del1 (bif->active_slaves, i);
+ hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index);
+ break;
+ }
+ }
+}
+
+void
+bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
+{
+ bond_if_t *bif;
+
+ bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
+ if (!hash_get (bif->active_slave_by_sw_if_index, sif->sw_if_index))
+ {
+ hash_set (bif->active_slave_by_sw_if_index, sif->sw_if_index,
+ sif->sw_if_index);
+ vec_add1 (bif->active_slaves, sif->sw_if_index);
+ }
+}
+
+int
+bond_dump_ifs (bond_interface_details_t ** out_bondifs)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ bond_main_t *bm = &bond_main;
+ bond_if_t *bif;
+ vnet_hw_interface_t *hi;
+ bond_interface_details_t *r_bondifs = NULL;
+ bond_interface_details_t *bondif = NULL;
+
+ /* *INDENT-OFF* */
+ pool_foreach (bif, bm->interfaces,
+ vec_add2(r_bondifs, bondif, 1);
+ memset (bondif, 0, sizeof (*bondif));
+ bondif->sw_if_index = bif->sw_if_index;
+ 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)));
+ bondif->mode = bif->mode;
+ bondif->lb = bif->lb;
+ bondif->active_slaves = vec_len (bif->active_slaves);
+ bondif->slaves = vec_len (bif->slaves);
+ );
+ /* *INDENT-ON* */
+
+ *out_bondifs = r_bondifs;
+
+ return 0;
+}
+
+int
+bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
+ 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;
+ u32 *sw_if_index = NULL;
+ slave_if_t *sif;
+
+ bif = bond_get_master_by_sw_if_index (bond_sw_if_index);
+ if (!bif)
+ return 1;
+
+ vec_foreach (sw_if_index, bif->slaves)
+ {
+ vec_add2 (r_slaveifs, slaveif, 1);
+ memset (slaveif, 0, sizeof (*slaveif));
+ sif = bond_get_slave_by_sw_if_index (*sw_if_index);
+ if (sif)
+ {
+ sw = vnet_get_sw_interface (vnm, sif->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;
+ }
+ }
+ *out_slaveifs = r_slaveifs;
+
+ return 0;
+}
+
+static void
+bond_delete_neighbor (vlib_main_t * vm, bond_if_t * bif, slave_if_t * sif)
+{
+ bond_main_t *bm = &bond_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ int i;
+ vnet_hw_interface_t *hw;
+
+ bif->port_number_bitmap =
+ clib_bitmap_set (bif->port_number_bitmap,
+ ntohs (sif->actor_admin.port_number) - 1, 0);
+ hash_unset (bm->neighbor_by_sw_if_index, sif->sw_if_index);
+ vec_free (sif->last_marker_pkt);
+ vec_free (sif->last_rx_pkt);
+ vec_foreach_index (i, bif->slaves)
+ {
+ uword p = *vec_elt_at_index (bif->slaves, i);
+ if (p == sif->sw_if_index)
+ {
+ vec_del1 (bif->slaves, i);
+ break;
+ }
+ }
+
+ bond_disable_collecting_distributing (vm, sif);
+
+ /* Put back the old mac */
+ hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
+ vnet_hw_interface_change_mac_address (vnm, hw->hw_if_index,
+ sif->persistent_hw_address);
+
+ pool_put (bm->neighbors, sif);
+
+ if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
+ (*bm->lacp_enable_disable) (vm, bif, sif, 0);
+}
+
+int
+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;
+ vnet_hw_interface_t *hw;
+ u32 *sif_sw_if_index;
+
+ 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);
+
+ vec_foreach (sif_sw_if_index, bif->slaves)
+ {
+ sif = bond_get_slave_by_sw_if_index (*sif_sw_if_index);
+ if (sif)
+ bond_delete_neighbor (vm, bif, sif);
+ }
+
+ /* bring down the interface */
+ vnet_hw_interface_set_flags (vnm, bif->hw_if_index, 0);
+ vnet_sw_interface_set_flags (vnm, bif->sw_if_index, 0);
+
+ ethernet_delete_interface (vnm, bif->hw_if_index);
+
+ clib_bitmap_free (bif->port_number_bitmap);
+ hash_unset (bm->bond_by_sw_if_index, bif->sw_if_index);
+ memset (bif, 0, sizeof (*bif));
+ pool_put (bm->interfaces, bif);
+
+ return 0;
+}
+
+void
+bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args)
+{
+ bond_main_t *bm = &bond_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_sw_interface_t *sw;
+ bond_if_t *bif;
+
+ if ((args->mode == BOND_MODE_LACP) && bm->lacp_plugin_loaded == 0)
+ {
+ args->rv = VNET_API_ERROR_FEATURE_DISABLED;
+ args->error = clib_error_return (0, "LACP plugin is not loaded");
+ return;
+ }
+ if (args->mode > BOND_MODE_LACP || args->mode < BOND_MODE_ROUND_ROBIN)
+ {
+ args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
+ args->error = clib_error_return (0, "Invalid mode");
+ return;
+ }
+ if (args->lb > BOND_LB_L23)
+ {
+ args->rv = VNET_API_ERROR_INVALID_ARGUMENT;
+ args->error = clib_error_return (0, "Invalid load-balance");
+ return;
+ }
+ pool_get (bm->interfaces, bif);
+ memset (bif, 0, sizeof (*bif));
+ bif->dev_instance = bif - bm->interfaces;
+ bif->lb = args->lb;
+ bif->mode = args->mode;
+
+ // Special load-balance mode used for rr and bc
+ if (bif->mode == BOND_MODE_ROUND_ROBIN)
+ bif->lb = BOND_LB_RR;
+ else if (bif->mode == BOND_MODE_BROADCAST)
+ bif->lb = BOND_LB_BC;
+
+ bif->use_custom_mac = args->hw_addr_set;
+ if (!args->hw_addr_set)
+ {
+ f64 now = vlib_time_now (vm);
+ u32 rnd;
+ rnd = (u32) (now * 1e6);
+ rnd = random_u32 (&rnd);
+
+ memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
+ args->hw_addr[0] = 2;
+ args->hw_addr[1] = 0xfe;
+ }
+ memcpy (bif->hw_address, args->hw_addr, 6);
+ args->error = ethernet_register_interface
+ (vnm, bond_dev_class.index, bif - bm->interfaces /* device instance */ ,
+ bif->hw_address /* ethernet address */ ,
+ &bif->hw_if_index, 0 /* flag change */ );
+
+ if (args->error)
+ {
+ args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ pool_put (bm->interfaces, bif);
+ return;
+ }
+
+ sw = vnet_get_hw_sw_interface (vnm, bif->hw_if_index);
+ bif->sw_if_index = sw->sw_if_index;
+ bif->group = bif->sw_if_index;
+
+ vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+
+ hash_set (bm->bond_by_sw_if_index, bif->sw_if_index, bif->dev_instance);
+
+ // for return
+ args->sw_if_index = bif->sw_if_index;
+}
+
+static clib_error_t *
+bond_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ bond_create_if_args_t args = { 0 };
+ u8 mode_is_set = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "Missing required arguments.");
+
+ args.mode = -1;
+ args.lb = BOND_LB_L2;
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "mode %U", unformat_bond_mode, &args.mode))
+ mode_is_set = 1;
+ else if (((args.mode == BOND_MODE_LACP) || (args.mode == BOND_MODE_XOR))
+ && unformat (line_input, "load-balance %U",
+ unformat_bond_load_balance, &args.lb))
+ ;
+ else if (unformat (line_input, "hw-addr %U",
+ unformat_ethernet_address, args.hw_addr))
+ args.hw_addr_set = 1;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ unformat_free (line_input);
+
+ if (mode_is_set == 0)
+ return clib_error_return (0, "Missing bond mode");
+
+ bond_create_if (vm, &args);
+
+ return args.error;
+}
+
+/* *INDENT-OFF* */
+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 }]} [hw-addr <mac-address>]",
+ .function = bond_create_command_fn,
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+bond_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 sw_if_index = ~0;
+ vnet_main_t *vnm = vnet_get_main ();
+ int rv;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "Missing <interface>");
+
+ 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
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ unformat_free (line_input);
+
+ if (sw_if_index == ~0)
+ return clib_error_return (0,
+ "please specify interface name or sw_if_index");
+
+ rv = bond_delete_if (vm, sw_if_index);
+ if (rv == VNET_API_ERROR_INVALID_SW_IF_INDEX)
+ return clib_error_return (0, "not a bond interface");
+ else if (rv != 0)
+ return clib_error_return (0, "error on deleting bond interface");
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (bond_delete__command, static) =
+{
+ .path = "delete bond",
+ .short_help = "delete bond {<interface> | sw_if_index <sw_idx>}",
+ .function = bond_delete_command_fn,
+};
+/* *INDENT-ON* */
+
+void
+bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args)
+{
+ bond_main_t *bm = &bond_main;
+ vnet_main_t *vnm = vnet_get_main ();
+ bond_if_t *bif;
+ slave_if_t *sif;
+ vnet_interface_main_t *im = &vnm->interface_main;
+ vnet_hw_interface_t *hw, *hw2;
+ vnet_sw_interface_t *sw;
+
+ bif = bond_get_master_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))
+ {
+ args->rv = VNET_API_ERROR_VALUE_EXIST;
+ args->error = clib_error_return (0, "interface was already enslaved");
+ return;
+ }
+ hw = vnet_get_sup_hw_interface (vnm, args->slave);
+ if (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 enslaved");
+ return;
+ }
+ pool_get (bm->neighbors, sif);
+ memset (sif, 0, sizeof (*sif));
+ clib_spinlock_init (&sif->lockp);
+ 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 (args->is_long_timeout)
+ sif->ttl_in_seconds = LACP_LONG_TIMOUT_TIME;
+ else
+ sif->ttl_in_seconds = LACP_SHORT_TIMOUT_TIME;
+
+ hash_set (bm->neighbor_by_sw_if_index, sif->sw_if_index,
+ sif - bm->neighbors);
+ vec_add1 (bif->slaves, sif->sw_if_index);
+
+ hw = vnet_get_sup_hw_interface (vnm, sif->sw_if_index);
+ /* Save the old mac */
+ memcpy (sif->persistent_hw_address, hw->hw_address, 6);
+ if (bif->use_custom_mac)
+ {
+ vnet_hw_interface_change_mac_address (vnm, hw->hw_if_index,
+ bif->hw_address);
+ }
+ else
+ {
+ // bond interface gets the mac address from the first slave
+ if (vec_len (bif->slaves) == 1)
+ {
+ memcpy (bif->hw_address, hw->hw_address, 6);
+ hw2 = vnet_get_sup_hw_interface (vnm, bif->sw_if_index);
+ vnet_hw_interface_change_mac_address (vnm, hw2->hw_if_index,
+ hw->hw_address);
+ }
+ else
+ {
+ // subsequent slaves gets the mac address of the bond interface
+ vnet_hw_interface_change_mac_address (vnm, hw->hw_if_index,
+ bif->hw_address);
+ }
+ }
+
+ if ((bif->mode == BOND_MODE_LACP) && bm->lacp_enable_disable)
+ {
+ (*bm->lacp_enable_disable) (vm, bif, sif, 1);
+ }
+ else
+ {
+ bond_enable_collecting_distributing (vm, sif);
+ }
+
+ args->rv = vnet_feature_enable_disable ("device-input", "bond-input",
+ hw->hw_if_index, 1, 0, 0);
+
+ if (args->rv)
+ {
+ args->error =
+ clib_error_return (0,
+ "Error encountered on input feature arc enable");
+ }
+}
+
+static clib_error_t *
+enslave_interface_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ bond_enslave_args_t args = { 0 };
+ unformat_input_t _line_input, *line_input = &_line_input;
+ vnet_main_t *vnm = vnet_get_main ();
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "Missing required arguments.");
+
+ args.slave = ~0;
+ args.group = ~0;
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "interface %U",
+ unformat_vnet_sw_interface, vnm, &args.slave))
+ ;
+ else if (unformat (line_input, "to %U", unformat_vnet_sw_interface, vnm,
+ &args.group))
+ ;
+ else if (unformat (line_input, "passive"))
+ args.is_passive = 1;
+ else if (unformat (line_input, "long-timeout"))
+ args.is_long_timeout = 1;
+ else
+ {
+ args.error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ break;
+ }
+ }
+ unformat_free (line_input);
+
+ if (args.error)
+ 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 interface name");
+
+ bond_enslave (vm, &args);
+
+ return args.error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (enslave_interface_command, static) = {
+ .path = "enslave",
+ .short_help = "enslave interface <interface> to <BondEthernetx> [passive] [long-timeout]",
+ .function = enslave_interface_command_fn,
+};
+/* *INDENT-ON* */
+
+void
+bond_detach_slave (vlib_main_t * vm, bond_detach_slave_args_t * args)
+{
+ bond_if_t *bif;
+ slave_if_t *sif;
+
+ sif = bond_get_slave_by_sw_if_index (args->slave);
+ if (!sif)
+ {
+ args->rv = VNET_API_ERROR_INVALID_INTERFACE;
+ args->error = clib_error_return (0, "interface was not enslaved");
+ return;
+ }
+ bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
+ bond_delete_neighbor (vm, bif, sif);
+}
+
+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 };
+ unformat_input_t _line_input, *line_input = &_line_input;
+ vnet_main_t *vnm = vnet_get_main ();
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "Missing required arguments.");
+
+ args.slave = ~0;
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "interface %U",
+ unformat_vnet_sw_interface, vnm, &args.slave))
+ ;
+ else
+ {
+ args.error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ break;
+ }
+ }
+ unformat_free (line_input);
+
+ if (args.error)
+ return args.error;
+ if (args.slave == ~0)
+ return clib_error_return (0, "please specify valid interface name");
+
+ bond_detach_slave (vm, &args);
+
+ return args.error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (detach_interface_command, static) = {
+ .path = "detach",
+ .short_help = "detach interface <interface>",
+ .function = detach_interface_command_fn,
+};
+/* *INDENT-ON* */
+
+static void
+show_bond (vlib_main_t * vm)
+{
+ bond_main_t *bm = &bond_main;
+ bond_if_t *bif;
+
+ vlib_cli_output (vm, "%-16s %-12s %-12s %-13s %-14s %s",
+ "interface name", "sw_if_index", "mode",
+ "load balance", "active slaves", "slaves");
+
+ /* *INDENT-OFF* */
+ pool_foreach (bif, bm->interfaces,
+ ({
+ vlib_cli_output (vm, "%-16U %-12d %-12U %-13U %-14u %u",
+ 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));
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+show_bond_details (vlib_main_t * vm)
+{
+ bond_main_t *bm = &bond_main;
+ bond_if_t *bif;
+ u32 *sw_if_index;
+
+ /* *INDENT-OFF* */
+ pool_foreach (bif, bm->interfaces,
+ ({
+ vlib_cli_output (vm, "%U", format_bond_interface_name, bif->dev_instance);
+ vlib_cli_output (vm, " mode: %U",
+ format_bond_mode, bif->mode);
+ vlib_cli_output (vm, " load balance: %U",
+ format_bond_load_balance, bif->lb);
+ if (bif->mode == BOND_MODE_ROUND_ROBIN)
+ vlib_cli_output (vm, " last xmit slave 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, " %U", format_vnet_sw_if_index_name,
+ vnet_get_main (), *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, " %U", format_vnet_sw_if_index_name,
+ vnet_get_main (), *sw_if_index);
+ }
+ vlib_cli_output (vm, " device instance: %d", bif->dev_instance);
+ vlib_cli_output (vm, " sw_if_index: %d", bif->sw_if_index);
+ vlib_cli_output (vm, " hw_if_index: %d", bif->hw_if_index);
+ }));
+ /* *INDENT-ON* */
+}
+
+static clib_error_t *
+show_bond_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ u8 details = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "details"))
+ details = 1;
+ else
+ {
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ }
+
+ if (details)
+ show_bond_details (vm);
+ else
+ show_bond (vm);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (show_bond_command, static) = {
+ .path = "show bond",
+ .short_help = "show bond [details]",
+ .function = show_bond_fn,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+bond_cli_init (vlib_main_t * vm)
+{
+ bond_main_t *bm = &bond_main;
+
+ bm->vlib_main = vm;
+ bm->vnet_main = vnet_get_main ();
+ bm->neighbor_by_sw_if_index = hash_create (0, sizeof (uword));
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (bond_cli_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */