bonding: add weight support for active-backup mode 25/21425/14
authorSteven Luong <sluong@cisco.com>
Tue, 20 Aug 2019 23:58:00 +0000 (16:58 -0700)
committerDamjan Marion <dmarion@me.com>
Fri, 6 Sep 2019 16:07:59 +0000 (16:07 +0000)
Not all interfaces have the same characteristics within the bonding group.
For active-backup mode, we should do our best to select the slave that
performs the best as the primary slave. We already did that by preferring
the slave that is local numa. Sometimes, this is not enough. For example,
when all are local numas, the selection is arbitrary. Some slave interfaces
may have higher speed or better qos than the others. But this is hard to
infer.

One rule does not fit all. So we let the operator to optionally specify the
weight for each slave interface. Our primary slave selection rule is now
1. biggest weight
2. is local numa
3. current primary slave (to avoid churn)
4. lowest sw_if_index (for deterministic behavior)

This selection rule only applies to active-backup mode which only one slave
is used for forwarding traffic until it becomes unreachable. At that time,
the next "best" slave candidate is automatically promoted. The slaves are
sorted according to the preference rule when they are up. So there is no need
to find the next best candidate when the primary slave goes down.

Another good thing about this rule is when the down slave comes back up, it
is selected as the primary slave again unless there is indeed a "better"
slave than this down slave that were added during that period.

To set the weight for the slave interface, do this after the interface is
enslaved

set interface bond <interface-name> weight <value>

Type: feature

Signed-off-by: Steven Luong <sluong@cisco.com>
Change-Id: I59ced6d20ce1dec532e667dbe1afd1b4243e04f9

src/vat/api_format.c
src/vnet/bonding/bond.api
src/vnet/bonding/bond_api.c
src/vnet/bonding/cli.c
src/vnet/bonding/node.h
src/vpp/api/custom_dump.c
test/test_bond.py
test/vpp_bond_interface.py

index 4603937..4161106 100644 (file)
@@ -1999,6 +1999,49 @@ static void vl_api_bond_detach_slave_reply_t_handler_json
   vam->result_ready = 1;
 }
 
+static int
+api_sw_interface_set_bond_weight (vat_main_t * vam)
+{
+  unformat_input_t *i = vam->input;
+  vl_api_sw_interface_set_bond_weight_t *mp;
+  u32 sw_if_index = ~0;
+  u32 weight = 0;
+  u8 weight_enter = 0;
+  int ret;
+
+  while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
+       ;
+      else if (unformat (i, "sw_if_index %d", &sw_if_index))
+       ;
+      else if (unformat (i, "weight %u", &weight))
+       weight_enter = 1;
+      else
+       break;
+    }
+
+  if (sw_if_index == ~0)
+    {
+      errmsg ("missing interface name or sw_if_index");
+      return -99;
+    }
+  if (weight_enter == 0)
+    {
+      errmsg ("missing valid weight");
+      return -99;
+    }
+
+  /* Construct the API message */
+  M (SW_INTERFACE_SET_BOND_WEIGHT, mp);
+  mp->sw_if_index = ntohl (sw_if_index);
+  mp->weight = ntohl (weight);
+
+  S (mp);
+  W (ret);
+  return ret;
+}
+
 static void vl_api_sw_interface_bond_details_t_handler
   (vl_api_sw_interface_bond_details_t * mp)
 {
@@ -2064,8 +2107,9 @@ static void vl_api_sw_interface_slave_details_t_handler
   vat_main_t *vam = &vat_main;
 
   print (vam->ofp,
-        "%-25s %-12d %-12d %d", mp->interface_name,
-        ntohl (mp->sw_if_index), mp->is_passive, mp->is_long_timeout);
+        "%-25s %-12d %-7d %-12d %-10d %-10d", mp->interface_name,
+        ntohl (mp->sw_if_index), mp->is_passive, mp->is_long_timeout,
+        ntohl (mp->weight), mp->is_local_numa);
 }
 
 static void vl_api_sw_interface_slave_details_t_handler_json
@@ -2087,6 +2131,8 @@ static void vl_api_sw_interface_slave_details_t_handler_json
                                   mp->interface_name);
   vat_json_object_add_uint (node, "passive", mp->is_passive);
   vat_json_object_add_uint (node, "long_timeout", mp->is_long_timeout);
+  vat_json_object_add_uint (node, "weight", ntohl (mp->weight));
+  vat_json_object_add_uint (node, "is_local_numa", mp->is_local_numa);
 }
 
 static int
@@ -2117,8 +2163,9 @@ api_sw_interface_slave_dump (vat_main_t * vam)
     }
 
   print (vam->ofp,
-        "\n%-25s %-12s %-12s %s",
-        "slave interface name", "sw_if_index", "passive", "long_timeout");
+        "\n%-25s %-12s %-7s %-12s %-10s %-10s",
+        "slave interface name", "sw_if_index", "passive", "long_timeout",
+        "weight", "local numa");
 
   /* Get list of bond interfaces */
   M (SW_INTERFACE_SLAVE_DUMP, mp);
@@ -5040,6 +5087,7 @@ _(sw_interface_set_vxlan_bypass_reply)                  \
 _(sw_interface_set_geneve_bypass_reply)                 \
 _(sw_interface_set_vxlan_gpe_bypass_reply)              \
 _(sw_interface_set_l2_bridge_reply)                     \
+_(sw_interface_set_bond_weight_reply)                   \
 _(bridge_domain_add_del_reply)                          \
 _(sw_interface_set_l2_xconnect_reply)                   \
 _(l2fib_add_del_reply)                                  \
@@ -5242,6 +5290,7 @@ _(BOND_CREATE_REPLY, bond_create_reply)                                   \
 _(BOND_DELETE_REPLY, bond_delete_reply)                                        \
 _(BOND_ENSLAVE_REPLY, bond_enslave_reply)                              \
 _(BOND_DETACH_SLAVE_REPLY, bond_detach_slave_reply)                    \
+_(SW_INTERFACE_SET_BOND_WEIGHT_REPLY, sw_interface_set_bond_weight_reply) \
 _(SW_INTERFACE_BOND_DETAILS, sw_interface_bond_details)                 \
 _(SW_INTERFACE_SLAVE_DETAILS, sw_interface_slave_details)               \
 _(IP_ROUTE_ADD_DEL_REPLY, ip_route_add_del_reply)                      \
@@ -21724,13 +21773,14 @@ _(sw_interface_virtio_pci_dump, "")                                     \
 _(bond_create,                                                          \
   "[hw-addr <mac-addr>] {round-robin | active-backup | "                \
   "broadcast | {lacp | xor} [load-balance { l2 | l23 | l34 }]} "        \
-  "[id <if-id>]")                                                       \
+  "[id <if-id>]")                                                      \
 _(bond_delete,                                                          \
   "<vpp-if-name> | sw_if_index <id>")                                   \
 _(bond_enslave,                                                         \
-  "sw_if_index <n> bond <sw_if_index> [is_passive] [is_long_timeout]") \
+  "sw_if_index <n> bond <sw_if_index> [is_passive] [is_long_timeout]")  \
 _(bond_detach_slave,                                                    \
   "sw_if_index <n>")                                                   \
+ _(sw_interface_set_bond_weight, "<intfc> | sw_if_index <nn> weight <value>") \
 _(sw_interface_bond_dump, "")                                           \
 _(sw_interface_slave_dump,                                              \
   "<vpp-if-name> | sw_if_index <id>")                                   \
index e699267..5d9a056 100644 (file)
@@ -19,7 +19,7 @@
     the bonding device driver
 */
 
-option version = "1.0.1";
+option version = "1.0.2";
 
 /** \brief Initialize a new bond interface with the given paramters
     @param client_index - opaque cookie to identify the sender
@@ -154,6 +154,8 @@ define sw_interface_slave_dump
     @param interface_name - name of interface
     @param is_passve - interface does not initiate the lacp protocol, remote must be active speaker
     @param is_long_timeout - 90 seconds vs default 3 seconds neighbor timeout
+    @param is_local_numa - the slave interface is local numa
+    @param weight - the weight for the slave interface (active-backup mode only)
 */
 define sw_interface_slave_details
 {
@@ -162,6 +164,22 @@ define sw_interface_slave_details
   u8 interface_name[64];
   u8 is_passive;
   u8 is_long_timeout;
+  u8 is_local_numa;
+  u32 weight;
+};
+
+/** \brief Interface set bond weight
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param sw_if_index - slave interface for which to set the weight
+    @param weight - weight value to be set for the slave interface
+*/
+autoreply define sw_interface_set_bond_weight
+{
+  u32 client_index;
+  u32 context;
+  u32 sw_if_index;
+  u32 weight;
 };
 
 /*
index 8e18423..74334b5 100644 (file)
@@ -47,6 +47,7 @@
 _(BOND_CREATE, bond_create)                      \
 _(BOND_DELETE, bond_delete)                      \
 _(BOND_ENSLAVE, bond_enslave)                    \
+_(SW_INTERFACE_SET_BOND_WEIGHT, sw_interface_set_bond_weight) \
 _(BOND_DETACH_SLAVE, bond_detach_slave)          \
 _(SW_INTERFACE_BOND_DUMP, sw_interface_bond_dump)\
 _(SW_INTERFACE_SLAVE_DUMP, sw_interface_slave_dump)
@@ -116,6 +117,25 @@ vl_api_bond_enslave_t_handler (vl_api_bond_enslave_t * mp)
   REPLY_MACRO (VL_API_BOND_ENSLAVE_REPLY);
 }
 
+static void
+  vl_api_sw_interface_set_bond_weight_t_handler
+  (vl_api_sw_interface_set_bond_weight_t * mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  bond_set_intf_weight_args_t _a, *ap = &_a;
+  vl_api_sw_interface_set_bond_weight_reply_t *rmp;
+  int rv = 0;
+
+  clib_memset (ap, 0, sizeof (*ap));
+
+  ap->sw_if_index = ntohl (mp->sw_if_index);
+  ap->weight = ntohl (mp->weight);
+
+  bond_set_intf_weight (vm, ap);
+
+  REPLY_MACRO (VL_API_SW_INTERFACE_SET_BOND_WEIGHT_REPLY);
+}
+
 static void
 vl_api_bond_detach_slave_t_handler (vl_api_bond_detach_slave_t * mp)
 {
@@ -200,6 +220,8 @@ bond_send_sw_interface_slave_details (vpe_api_main_t * am,
                    strlen ((const char *) slave_if->interface_name)));
   mp->is_passive = slave_if->is_passive;
   mp->is_long_timeout = slave_if->is_long_timeout;
+  mp->is_local_numa = slave_if->is_local_numa;
+  mp->weight = htonl (slave_if->weight);
 
   mp->context = context;
   vl_api_send_msg (reg, (u8 *) mp);
index 4e0d30a..2acc670 100644 (file)
@@ -29,8 +29,6 @@ bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
   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);
@@ -40,12 +38,10 @@ bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
     p = *vec_elt_at_index (bif->active_slaves, i);
     if (p == sif->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;
-         }
+       if ((bif->mode == BOND_MODE_ACTIVE_BACKUP) && (i == 0) &&
+           (vec_len (bif->active_slaves) > 1))
+         /* deleting the active slave for active-backup */
+         switching_active = 1;
        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)
@@ -64,37 +60,9 @@ bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
   }
 
   /* 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;
-             }
-         }
-       }
-
-      /* 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))
-       {
-         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);
-       }
-    }
+  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);
 
   if (bif->mode == BOND_MODE_LACP)
@@ -102,6 +70,71 @@ bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
                                    [sif->sw_if_index], sif->actor.state);
 }
 
+/*
+ * return 1 if s2 is preferred.
+ * return -1 if s1 is preferred.
+ */
+static int
+bond_slave_sort (void *a1, void *a2)
+{
+  u32 *s1 = a1;
+  u32 *s2 = a2;
+  slave_if_t *sif1 = bond_get_slave_by_sw_if_index (*s1);
+  slave_if_t *sif2 = bond_get_slave_by_sw_if_index (*s2);
+  bond_if_t *bif;
+
+  ASSERT (sif1);
+  ASSERT (sif2);
+  /*
+   * sort entries according to preference rules:
+   * 1. biggest weight
+   * 2. numa-node
+   * 3. current active slave (to prevent churning)
+   * 4. lowest sw_if_index (for deterministic behavior)
+   *
+   */
+  if (sif2->weight > sif1->weight)
+    return 1;
+  if (sif2->weight < sif1->weight)
+    return -1;
+  else
+    {
+      if (sif2->is_local_numa > sif1->is_local_numa)
+       return 1;
+      if (sif2->is_local_numa < sif1->is_local_numa)
+       return -1;
+      else
+       {
+         bif = bond_get_master_by_dev_instance (sif1->bif_dev_instance);
+         /* Favor the current active slave to avoid churning */
+         if (bif->active_slaves[0] == sif2->sw_if_index)
+           return 1;
+         if (bif->active_slaves[0] == sif1->sw_if_index)
+           return -1;
+         /* go for the tiebreaker as the last resort */
+         if (sif1->sw_if_index > sif2->sw_if_index)
+           return 1;
+         if (sif1->sw_if_index < sif2->sw_if_index)
+           return -1;
+         else
+           ASSERT (0);
+       }
+    }
+  return 0;
+}
+
+static void
+bond_sort_slaves (bond_if_t * bif)
+{
+  bond_main_t *bm = &bond_main;
+  u32 old_active = bif->active_slaves[0];
+
+  vec_sort_with_function (bif->active_slaves, bond_slave_sort);
+  if (old_active != bif->active_slaves[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)
 {
@@ -109,8 +142,6 @@ bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
   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);
-  int i;
-  uword p;
 
   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
   clib_spinlock_lock_if_init (&bif->lockp);
@@ -127,43 +158,17 @@ bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
          bif->n_numa_slaves++;
        }
       else
-       {
-         vec_add1 (bif->active_slaves, sif->sw_if_index);
-       }
+       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))
+      sif->is_local_numa = (vm->numa_node == hw->numa_node) ? 1 : 0;
+      if (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);
-
-           }
+         if (vec_len (bif->active_slaves) == 1)
+           /* First slave becomes active? */
+           vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
+                                      BOND_SEND_GARP_NA, bif->hw_if_index);
+         else
+           bond_sort_slaves (bif);
        }
     }
   clib_spinlock_unlock_if_init (&bif->lockp);
@@ -238,6 +243,8 @@ bond_dump_slave_ifs (slave_interface_details_t ** out_slaveifs,
        slaveif->sw_if_index = sif->sw_if_index;
        slaveif->is_passive = sif->is_passive;
        slaveif->is_long_timeout = sif->is_long_timeout;
+       slaveif->is_local_numa = sif->is_local_numa;
+       slaveif->weight = sif->weight;
       }
   }
   *out_slaveifs = r_slaveifs;
@@ -862,6 +869,14 @@ show_bond_details (vlib_main_t * vm)
       {
         vlib_cli_output (vm, "    %U", format_vnet_sw_if_index_name,
                         vnet_get_main (), *sw_if_index);
+       if (bif->mode == BOND_MODE_ACTIVE_BACKUP)
+         {
+           slave_if_t *sif = bond_get_slave_by_sw_if_index (*sw_if_index);
+           if (sif)
+             vlib_cli_output (vm, "      weight: %u, is_local_numa: %u, "
+                              "sw_if_index: %u", sif->weight,
+                              sif->is_local_numa, sif->sw_if_index);
+         }
       }
     vlib_cli_output (vm, "  number of slaves: %d", vec_len (bif->slaves));
     vec_foreach (sw_if_index, bif->slaves)
@@ -910,6 +925,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)
+{
+  slave_if_t *sif;
+  bond_if_t *bif;
+  vnet_main_t *vnm;
+  u32 old_weight;
+
+  sif = bond_get_slave_by_sw_if_index (args->sw_if_index);
+  if (!sif)
+    {
+      args->rv = VNET_API_ERROR_INVALID_INTERFACE;
+      args->error = clib_error_return (0, "Interface not enslaved");
+      return;
+    }
+  bif = bond_get_master_by_dev_instance (sif->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 = sif->weight;
+  sif->weight = args->weight;
+  vnm = vnet_get_main ();
+  /*
+   * No need to sort the list if the affected slave is not up (not in active
+   * slave set), active slave count is 1, or the current slave is already the
+   * primary slave and new weight > old weight.
+   */
+  if (!vnet_sw_interface_is_up (vnm, sif->sw_if_index) ||
+      (vec_len (bif->active_slaves) == 1) ||
+      ((bif->active_slaves[0] == sif->sw_if_index) &&
+       (sif->weight >= old_weight)))
+    return;
+
+  bond_sort_slaves (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 <interface> | sw_if_index <idx>"
+                " weight <value>",
+  .function = bond_set_intf_cmd,
+};
+/* *INDENT-ON* */
+
 clib_error_t *
 bond_cli_init (vlib_main_t * vm)
 {
index 1ad19de..1479209 100644 (file)
@@ -110,6 +110,15 @@ typedef struct
   clib_error_t *error;
 } bond_detach_slave_args_t;
 
+typedef struct
+{
+  u32 sw_if_index;
+  u32 weight;
+  /* return */
+  int rv;
+  clib_error_t *error;
+} bond_set_intf_weight_args_t;
+
 /** BOND interface details struct */
 typedef struct
 {
@@ -130,6 +139,8 @@ typedef struct
   u8 interface_name[64];
   u8 is_passive;
   u8 is_long_timeout;
+  u8 is_local_numa;
+  u32 weight;
   u32 active_slaves;
 } slave_interface_details_t;
 
@@ -159,11 +170,6 @@ typedef struct
   u8 mode;
   u8 lb;
 
-  /* This flag works for active-backup mode only
-     and marks if the working port is local numa. */
-  u8 is_local_numa;
-  /* current working sw_if_index in active-bakeup mode. */
-  u32 sw_if_index_working;
   /* the last slave index for the rr lb */
   u32 lb_rr_last_index;
 
@@ -239,6 +245,9 @@ typedef struct
   /* neighbor vlib hw_if_index */
   u32 hw_if_index;
 
+  /* weight -- valid only for active backup */
+  u32 weight;
+
   /* actor does not initiate the protocol exchange */
   u8 is_passive;
 
@@ -336,6 +345,9 @@ typedef struct
 
   /* pdu sent */
   u64 marker_pdu_sent;
+
+  /* slave is numa node */
+  u8 is_local_numa;
 } slave_if_t;
 
 typedef void (*lacp_enable_disable_func) (vlib_main_t * vm, bond_if_t * bif,
@@ -398,6 +410,8 @@ void bond_disable_collecting_distributing (vlib_main_t * vm,
 void bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif);
 u8 *format_bond_interface_name (u8 * s, va_list * args);
 
+void bond_set_intf_weight (vlib_main_t * vm,
+                          bond_set_intf_weight_args_t * args);
 void bond_create_if (vlib_main_t * vm, bond_create_if_args_t * args);
 int bond_delete_if (vlib_main_t * vm, u32 sw_if_index);
 void bond_enslave (vlib_main_t * vm, bond_enslave_args_t * args);
index 24c37a6..8ef78cb 100644 (file)
@@ -700,6 +700,18 @@ static void *vl_api_bond_enslave_t_print
   FINISH;
 }
 
+static void *vl_api_sw_interface_set_bond_weight_t_print
+  (vl_api_sw_interface_set_bond_weight_t * mp, void *handle)
+{
+  u8 *s;
+
+  s = format (0, "SCRIPT: sw_interface_set_bond_weight ");
+  s = format (s, "sw_if_index %u ", ntohl (mp->sw_if_index));
+  s = format (s, "weight %u ", ntohl (mp->weight));
+
+  FINISH;
+}
+
 static void *vl_api_bond_detach_slave_t_print
   (vl_api_bond_detach_slave_t * mp, void *handle)
 {
@@ -3774,6 +3786,7 @@ _(BOND_CREATE, bond_create)                                             \
 _(BOND_DELETE, bond_delete)                                             \
 _(BOND_ENSLAVE, bond_enslave)                                           \
 _(BOND_DETACH_SLAVE, bond_detach_slave)                                 \
+_(SW_INTERFACE_SET_BOND_WEIGHT, sw_interface_set_bond_weight)           \
 _(SW_INTERFACE_SLAVE_DUMP, sw_interface_slave_dump)                     \
 _(SW_INTERFACE_BOND_DUMP, sw_interface_bond_dump)                       \
 _(SW_INTERFACE_RX_PLACEMENT_DUMP, sw_interface_rx_placement_dump)       \
index 60ee33c..27da15c 100644 (file)
@@ -86,13 +86,9 @@ class TestBondInterface(VppTestCase):
 
         # enslave pg0 and pg1 to BondEthernet0
         self.logger.info("bond enslave interface pg0 to BondEthernet0")
-        bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
-                                         is_passive=0,
-                                         is_long_timeout=0)
+        bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
         self.logger.info("bond enslave interface pg1 to BondEthernet0")
-        bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
-                                         is_passive=0,
-                                         is_long_timeout=0)
+        bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
 
         # verify both slaves in BondEthernet0
         if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
@@ -276,5 +272,6 @@ class TestBondInterface(VppTestCase):
         if_dump = self.vapi.sw_interface_bond_dump()
         self.assertFalse(bond0.is_interface_config_in_dump(if_dump))
 
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)
index f05a07b..0db04e1 100644 (file)
@@ -29,8 +29,8 @@ class VppBondInterface(VppInterface):
 
     def enslave_vpp_bond_interface(self,
                                    sw_if_index,
-                                   is_passive,
-                                   is_long_timeout):
+                                   is_passive=0,
+                                   is_long_timeout=0):
         self.test.vapi.bond_enslave(sw_if_index,
                                     self.sw_if_index,
                                     is_passive,