#include <vnet/snap/snap.h>
#include <vnet/bonding/node.h>
+#ifndef CLIB_MARCH_VARIANT
bond_main_t bond_main;
+#endif /* CLIB_MARCH_VARIANT */
#define foreach_bond_input_error \
_(NONE, "no error") \
_(IF_DOWN, "interface down") \
+ _(PASSIVE_IF, "traffic received on passive interface") \
_(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
typedef enum
BOND_INPUT_N_ERROR,
} bond_input_error_t;
-#ifndef CLIB_MARCH_VARIANT
static char *bond_input_error_strings[] = {
#define _(n,s) s,
foreach_bond_input_error
return s;
}
-#endif
-
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)
(snap->oui[2] == 0x0C)));
}
-static inline u32
+static inline void
bond_sw_if_idx_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_buffer_t * b, u32 bond_sw_if_index)
+ vlib_buffer_t * b, u32 bond_sw_if_index,
+ u32 * n_rx_packets, u32 * n_rx_bytes)
{
u16 *ethertype_p, ethertype;
ethernet_vlan_header_t *vlan;
ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
+ (*n_rx_packets)++;
+ *n_rx_bytes += b->current_length;
ethertype = clib_mem_unaligned (ð->type, u16);
if (!ethernet_frame_is_tagged (ntohs (ethertype)))
{
{
/* Change the physical interface to bond interface */
vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
- return 1;
+ return;
}
}
else
{
/* Change the physical interface to bond interface */
vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
- return 1;
+ return;
}
}
vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
- return 0;
+ return;
}
static inline void
bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
- u32 packet_count,
u32 * bond_sw_if_index, vlib_buffer_t * b,
u32 * next_index, vlib_error_t * error)
{
- u16 thread_index = vlib_get_thread_index ();
slave_if_t *sif;
bond_if_t *bif;
- if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
- return;
+ *next_index = BOND_INPUT_NEXT_DROP;
+ *error = 0;
- if (packet_count)
- vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
- VNET_INTERFACE_COUNTER_RX, thread_index,
- *last_slave_sw_if_index, packet_count);
+ if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
+ goto next;
*last_slave_sw_if_index = slave_sw_if_index;
- *next_index = BOND_INPUT_NEXT_DROP;
sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
- ASSERT (sif);
+ ALWAYS_ASSERT (sif);
bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
- ASSERT (bif);
+ ALWAYS_ASSERT (bif);
ASSERT (vec_len (bif->slaves));
- if (PREDICT_TRUE (bif->admin_up == 0))
+ if (PREDICT_FALSE (bif->admin_up == 0))
{
*bond_sw_if_index = slave_sw_if_index;
*error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
}
+ if (PREDICT_FALSE ((bif->mode == BOND_MODE_ACTIVE_BACKUP) &&
+ vec_len (bif->active_slaves) &&
+ (slave_sw_if_index != bif->active_slaves[0])))
+ {
+ *bond_sw_if_index = slave_sw_if_index;
+ *error = node->errors[BOND_INPUT_ERROR_PASSIVE_IF];
+ return;
+ }
+
*bond_sw_if_index = bif->sw_if_index;
- *error = 0;
- vnet_feature_next ( /* not used */ 0, next_index, b);
+
+next:
+ vnet_feature_next (next_index, b);
+}
+
+static_always_inline void
+bond_update_next_x4 (vlib_buffer_t * b0, vlib_buffer_t * b1,
+ vlib_buffer_t * b2, vlib_buffer_t * b3)
+{
+ u32 tmp0, tmp1, tmp2, tmp3;
+
+ tmp0 = tmp1 = tmp2 = tmp3 = BOND_INPUT_NEXT_DROP;
+ vnet_feature_next (&tmp0, b0);
+ vnet_feature_next (&tmp1, b1);
+ vnet_feature_next (&tmp2, b2);
+ vnet_feature_next (&tmp3, b3);
}
VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * frame)
{
- u16 thread_index = vlib_get_thread_index ();
+ u16 thread_index = vm->thread_index;
u32 *from, n_left;
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
u32 bond_sw_if_index = 0;
vlib_error_t error = 0;
u32 next_index = 0;
- u32 cnt = 0;
+ u32 n_rx_bytes = 0, n_rx_packets = 0;
/* Vector of buffer / pkt indices we're supposed to process */
from = vlib_frame_vector_args (frame);
/* Prefetch next iteration */
if (PREDICT_TRUE (n_left >= 16))
{
- CLIB_PREFETCH (vlib_buffer_get_current (b[8]),
- CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (vlib_buffer_get_current (b[9]),
- CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (vlib_buffer_get_current (b[10]),
- CLIB_CACHE_LINE_BYTES, LOAD);
- CLIB_PREFETCH (vlib_buffer_get_current (b[11]),
- CLIB_CACHE_LINE_BYTES, LOAD);
+ vlib_prefetch_buffer_data (b[8], LOAD);
+ vlib_prefetch_buffer_data (b[9], LOAD);
+ vlib_prefetch_buffer_data (b[10], LOAD);
+ vlib_prefetch_buffer_data (b[11], LOAD);
vlib_prefetch_buffer_header (b[12], LOAD);
vlib_prefetch_buffer_header (b[13], LOAD);
if (PREDICT_TRUE (x == 0))
{
+ /*
+ * Optimize to call update_next only if there is a feature arc
+ * after bond-input. Test feature count greater than 1 because
+ * bond-input itself is a feature arc for this slave interface.
+ */
+ ASSERT ((vnet_buffer (b[0])->feature_arc_index ==
+ vnet_buffer (b[1])->feature_arc_index) &&
+ (vnet_buffer (b[0])->feature_arc_index ==
+ vnet_buffer (b[2])->feature_arc_index) &&
+ (vnet_buffer (b[0])->feature_arc_index ==
+ vnet_buffer (b[3])->feature_arc_index));
+ if (PREDICT_FALSE (vnet_get_feature_count
+ (vnet_buffer (b[0])->feature_arc_index,
+ last_slave_sw_if_index) > 1))
+ bond_update_next_x4 (b[0], b[1], b[2], b[3]);
+
next[0] = next[1] = next[2] = next[3] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
{
}
else
{
- cnt +=
- bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
- cnt +=
- bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
- cnt +=
- bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
- cnt +=
- bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
+ bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
+ bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
+ bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
}
}
else
{
-
bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
- cnt, &bond_sw_if_index, b[0], &next_index,
- &error);
+ &bond_sw_if_index, b[0], &next_index, &error);
next[0] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
b[0]->error = error;
else
- cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
- cnt, &bond_sw_if_index, b[1], &next_index,
- &error);
+ &bond_sw_if_index, b[1], &next_index, &error);
next[1] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
b[1]->error = error;
else
- cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
- cnt, &bond_sw_if_index, b[2], &next_index,
- &error);
+ &bond_sw_if_index, b[2], &next_index, &error);
next[2] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
b[2]->error = error;
else
- cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
- cnt, &bond_sw_if_index, b[3], &next_index,
- &error);
+ &bond_sw_if_index, b[3], &next_index, &error);
next[3] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
b[3]->error = error;
else
- cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
}
VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
{
sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
- cnt, &bond_sw_if_index, b[0], &next_index, &error);
+ &bond_sw_if_index, b[0], &next_index, &error);
next[0] = next_index;
if (next_index == BOND_INPUT_NEXT_DROP)
b[0]->error = error;
else
- bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
+ bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
+ &n_rx_packets, &n_rx_bytes);
VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
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;
- uword n_trace = vlib_get_trace_count (vm, node);
- while (n_left && n_trace)
+ while (n_left)
{
if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
{
- vlib_trace_buffer (vm, node, next[0], b[0],
- 0 /* follow_chain */ );
- vlib_set_trace_count (vm, node, --n_trace);
t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
t0->sw_if_index = sw_if_index[0];
- clib_memcpy (&t0->ethernet, vlib_buffer_get_current (b[0]),
- sizeof (ethernet_header_t));
+ clib_memcpy_fast (&t0->ethernet, vlib_buffer_get_current (b[0]),
+ sizeof (ethernet_header_t));
t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
}
/* next */
n_left--;
b++;
sw_if_index++;
- next++;
}
}
/* increase rx counters */
- vlib_increment_simple_counter
- (vnet_main.interface_main.sw_if_counters +
- VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
+ vlib_increment_combined_counter
+ (vnet_main.interface_main.combined_sw_if_counters +
+ VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, n_rx_packets,
+ n_rx_bytes);
vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
vlib_node_increment_counter (vm, bond_input_node.index,
return frame->n_vectors;
}
-#ifndef CLIB_MARCH_VARIANT
static clib_error_t *
bond_input_init (vlib_main_t * vm)
{
sif = bond_get_slave_by_sw_if_index (sw_if_index);
if (sif)
{
- sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+ if (sif->lacp_enabled)
+ return 0;
+
+ /* port_enabled is both admin up and hw link up */
+ sif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
+ vnet_sw_interface_is_link_up (vnm, sw_if_index));
if (sif->port_enabled == 0)
- {
- if (sif->lacp_enabled == 0)
- {
- bond_disable_collecting_distributing (vm, sif);
- }
- }
+ bond_disable_collecting_distributing (vm, sif);
else
- {
- if (sif->lacp_enabled == 0)
- {
- bond_enable_collecting_distributing (vm, sif);
- }
- }
+ bond_enable_collecting_distributing (vm, sif);
}
return 0;
sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
if (sif)
{
- if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
- {
- if (sif->lacp_enabled == 0)
- {
- bond_disable_collecting_distributing (vm, sif);
- }
- }
+ if (sif->lacp_enabled)
+ return 0;
+
+ /* port_enabled is both admin up and hw link up */
+ sif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
+ vnet_sw_interface_is_admin_up (vnm,
+ sw->sw_if_index));
+ if (sif->port_enabled == 0)
+ bond_disable_collecting_distributing (vm, sif);
else
- {
- if (sif->lacp_enabled == 0)
- {
- bond_enable_collecting_distributing (vm, sif);
- }
- }
+ bond_enable_collecting_distributing (vm, sif);
}
return 0;
}
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
-#endif
/*
* fd.io coding-style-patch-verification: ON