summaryrefslogtreecommitdiffstats
path: root/src/vnet/bonding
diff options
context:
space:
mode:
authorSteven <sluong@cisco.com>2018-06-05 11:09:32 -0700
committerSteven <sluong@cisco.com>2018-06-05 11:09:32 -0700
commit9f781d84b0943b03af2a9fd0b7c4cef721d1d4c6 (patch)
treea78172c460d265c89d3717a5cb8cb45775fe523b /src/vnet/bonding
parent439a122f3acd745dcb70e9b32bb518e43967afe4 (diff)
bond: send gratuitous arp when the active slave went down in active-backup mode
- Modify the API send_ip6_na and send_ip4_garp to take sw_if_index instead of vnet_hw_interface_t and add call to build_ethernet_rewrite to support subinterface/vlan - Add code to bonding driver to send an event to bond_process when the first interface becomes active or when the active interface is down - Create a bond_process to walk the interface and the corresponding subinterfaces to send garp/ip6_na when an event is received. - Minor cleanup in bonding/node.c Note: dpdk bonding driver does not send garp/ip6_na for subinterfaces. There is no attempt to fix it here. But the infra is now done and should be easy to add the support. Change-Id: If3ecc4cd0fb3051330f7fa11ca0dab3e18557ce1 Signed-off-by: Steven <sluong@cisco.com>
Diffstat (limited to 'src/vnet/bonding')
-rw-r--r--src/vnet/bonding/cli.c19
-rw-r--r--src/vnet/bonding/device.c48
-rw-r--r--src/vnet/bonding/node.c4
-rw-r--r--src/vnet/bonding/node.h6
4 files changed, 74 insertions, 3 deletions
diff --git a/src/vnet/bonding/cli.c b/src/vnet/bonding/cli.c
index 2799bb88b99..91c6e2cdb7d 100644
--- a/src/vnet/bonding/cli.c
+++ b/src/vnet/bonding/cli.c
@@ -24,9 +24,11 @@
void
bond_disable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
{
+ bond_main_t *bm = &bond_main;
bond_if_t *bif;
int i;
uword p;
+ u8 switching_active = 0;
bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
clib_spinlock_lock_if_init (&bif->lockp);
@@ -35,8 +37,18 @@ 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)
{
+ /* Are we disabling the very 1st slave? */
+ if (sif->sw_if_index == *vec_elt_at_index (bif->active_slaves, 0))
+ switching_active = 1;
+
vec_del1 (bif->active_slaves, i);
hash_unset (bif->active_slave_by_sw_if_index, sif->sw_if_index);
+
+ /* We got a new slave just becoming active? */
+ if ((vec_len (bif->active_slaves) >= 1) &&
+ (bif->mode == BOND_MODE_ACTIVE_BACKUP) && switching_active)
+ vlib_process_signal_event (bm->vlib_main, bond_process_node.index,
+ BOND_SEND_GARP_NA, bif->hw_if_index);
break;
}
}
@@ -47,6 +59,7 @@ void
bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
{
bond_if_t *bif;
+ bond_main_t *bm = &bond_main;
bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
clib_spinlock_lock_if_init (&bif->lockp);
@@ -55,6 +68,12 @@ bond_enable_collecting_distributing (vlib_main_t * vm, slave_if_t * sif)
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);
+
+ /* First slave becomes active? */
+ if ((vec_len (bif->active_slaves) == 1) &&
+ (bif->mode == BOND_MODE_ACTIVE_BACKUP))
+ 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);
}
diff --git a/src/vnet/bonding/device.c b/src/vnet/bonding/device.c
index 8ddec80850a..1ade1c290a1 100644
--- a/src/vnet/bonding/device.c
+++ b/src/vnet/bonding/device.c
@@ -23,6 +23,8 @@
#include <vnet/ip/ip6_hop_by_hop_packet.h>
#include <vnet/bonding/node.h>
#include <vppinfra/lb_hash_hash.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/arp_packet.h>
#define foreach_bond_tx_error \
_(NONE, "no error") \
@@ -700,6 +702,52 @@ bond_tx_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
return frame->n_vectors;
}
+static walk_rc_t
+bond_active_interface_switch_cb (vnet_main_t * vnm, u32 sw_if_index,
+ void *arg)
+{
+ bond_main_t *bm = &bond_main;
+
+ send_ip4_garp (bm->vlib_main, sw_if_index);
+ send_ip6_na (bm->vlib_main, sw_if_index);
+
+ return (WALK_CONTINUE);
+}
+
+static uword
+bond_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ uword event_type, *event_data = 0;
+
+ while (1)
+ {
+ u32 i;
+ u32 hw_if_index;
+
+ vlib_process_wait_for_event (vm);
+ event_type = vlib_process_get_events (vm, &event_data);
+ ASSERT (event_type == BOND_SEND_GARP_NA);
+ for (i = 0; i < vec_len (event_data); i++)
+ {
+ hw_if_index = event_data[i];
+ /* walk hw interface to process all subinterfaces */
+ vnet_hw_interface_walk_sw (vnm, hw_if_index,
+ bond_active_interface_switch_cb, 0);
+ }
+ vec_reset_length (event_data);
+ }
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (bond_process_node) = {
+ .function = bond_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "bond-process",
+};
+/* *INDENT-ON* */
+
/* *INDENT-OFF* */
VNET_DEVICE_CLASS (bond_dev_class) = {
.name = "bond",
diff --git a/src/vnet/bonding/node.c b/src/vnet/bonding/node.c
index 9479fe98dd0..5842da3f5ec 100644
--- a/src/vnet/bonding/node.c
+++ b/src/vnet/bonding/node.c
@@ -67,7 +67,7 @@ typedef enum
{
BOND_INPUT_NEXT_DROP,
BOND_INPUT_N_NEXT,
-} l2output_next_t;
+} bond_output_next_t;
static_always_inline u8
packet_is_cdp (ethernet_header_t * eth)
@@ -329,7 +329,6 @@ VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
n_left = frame->n_vectors; /* number of packets to process */
b = bufs;
sw_if_index = sw_if_indices;
- next = nexts;
bond_packet_trace_t *t0;
while (n_left)
@@ -346,7 +345,6 @@ VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
n_left--;
b++;
sw_if_index++;
- next++;
}
}
diff --git a/src/vnet/bonding/node.h b/src/vnet/bonding/node.h
index 5c6ff32ac4a..7b8e1ad7cb2 100644
--- a/src/vnet/bonding/node.h
+++ b/src/vnet/bonding/node.h
@@ -70,6 +70,11 @@ typedef enum
#undef _
} bond_load_balance_t;
+enum
+{
+ BOND_SEND_GARP_NA = 1,
+} bond_send_garp_na_process_event_t;
+
typedef struct
{
u8 hw_addr_set;
@@ -325,6 +330,7 @@ typedef struct
} bond_load_balance_func_t;
extern vlib_node_registration_t bond_input_node;
+extern vlib_node_registration_t bond_process_node;
extern vnet_device_class_t bond_dev_class;
extern bond_main_t bond_main;