#include <vnet/l2/feat_bitmap.h>
#include <vnet/l2/l2_bvi.h>
#include <vnet/l2/l2_fib.h>
+#include <vnet/l2/l2_bd.h>
#include <vppinfra/error.h>
#include <vppinfra/hash.h>
static_always_inline void
classify_and_dispatch (vlib_main_t * vm,
vlib_node_runtime_t * node,
- u32 cpu_index,
+ u32 thread_index,
l2input_main_t * msm, vlib_buffer_t * b0, u32 * next0)
{
/*
/* Get config for the bridge domain interface */
bd_config = vec_elt_at_index (msm->bd_configs, bd_index0);
+ /* Save bridge domain and interface seq_num */
+ /* *INDENT-OFF* */
+ l2fib_seq_num_t sn = {
+ .swif = config->seq_num,
+ .bd = bd_config->seq_num,
+ };
+ /* *INDENT-ON* */
+ vnet_buffer (b0)->l2.l2fib_sn = sn.as_u16;;
+
/*
* Process bridge domain feature enables.
* To perform learning/flooding/forwarding, the corresponding bit
feature_bitmap);
}
-
-static uword
-l2input_node_fn (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
+static_always_inline uword
+l2input_node_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame,
+ int do_trace)
{
u32 n_left_from, *from, *to_next;
l2input_next_t next_index;
l2input_main_t *msm = &l2input_main;
- u32 cpu_index = os_get_cpu_number ();
+ u32 thread_index = vlib_get_thread_index ();
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors; /* number of packets to process */
b2 = vlib_get_buffer (vm, bi2);
b3 = vlib_get_buffer (vm, bi3);
- if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+ if (do_trace)
{
/* RX interface handles */
sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
vlib_node_increment_counter (vm, l2input_node.index,
L2INPUT_ERROR_L2INPUT, 4);
- classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0);
- classify_and_dispatch (vm, node, cpu_index, msm, b1, &next1);
- classify_and_dispatch (vm, node, cpu_index, msm, b2, &next2);
- classify_and_dispatch (vm, node, cpu_index, msm, b3, &next3);
+ classify_and_dispatch (vm, node, thread_index, msm, b0, &next0);
+ classify_and_dispatch (vm, node, thread_index, msm, b1, &next1);
+ classify_and_dispatch (vm, node, thread_index, msm, b2, &next2);
+ classify_and_dispatch (vm, node, thread_index, msm, b3, &next3);
/* verify speculative enqueues, maybe switch current next frame */
/* if next0==next1==next_index then nothing special needs to be done */
b0 = vlib_get_buffer (vm, bi0);
- if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
- && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ if (do_trace && PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
{
ethernet_header_t *h0 = vlib_buffer_get_current (b0);
l2input_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
vlib_node_increment_counter (vm, l2input_node.index,
L2INPUT_ERROR_L2INPUT, 1);
- classify_and_dispatch (vm, node, cpu_index, msm, b0, &next0);
+ classify_and_dispatch (vm, node, thread_index, msm, b0, &next0);
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
return frame->n_vectors;
}
+static uword
+l2input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+ return l2input_node_inline (vm, node, frame, 1 /* do_trace */ );
+ return l2input_node_inline (vm, node, frame, 0 /* do_trace */ );
+}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (l2input_node) = {
u32
l2input_intf_bitmap_enable (u32 sw_if_index, u32 feature_bitmap, u32 enable)
{
- l2input_main_t *mp = &l2input_main;
- l2_input_config_t *config;
-
- vec_validate (mp->configs, sw_if_index);
- config = vec_elt_at_index (mp->configs, sw_if_index);
+ l2_input_config_t *config = l2input_intf_config (sw_if_index);
if (enable)
- {
- config->feature_bitmap |= feature_bitmap;
- }
+ config->feature_bitmap |= feature_bitmap;
else
- {
- config->feature_bitmap &= ~feature_bitmap;
- }
+ config->feature_bitmap &= ~feature_bitmap;
return config->feature_bitmap;
}
u32
l2input_set_bridge_features (u32 bd_index, u32 feat_mask, u32 feat_value)
{
- l2_bridge_domain_t *bd_config;
- vec_validate (l2input_main.bd_configs, bd_index);
- bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
+ l2_bridge_domain_t *bd_config = l2input_bd_config (bd_index);;
bd_validate (bd_config);
bd_config->feature_bitmap =
(bd_config->feature_bitmap & ~feat_mask) | feat_value;
*/
u32
-set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, u32 mode, u32 sw_if_index, u32 bd_index, /* for bridged interface */
- u32 bvi, /* the bridged interface is the BVI */
- u32 shg, /* the bridged interface's split horizon group */
- u32 xc_sw_if_index) /* peer interface for xconnect */
+set_int_l2_mode (vlib_main_t * vm, vnet_main_t * vnet_main, /* */
+ u32 mode, /* One of L2 modes or back to L3 mode */
+ u32 sw_if_index, /* sw interface index */
+ u32 bd_index, /* for bridged interface */
+ u32 bvi, /* the bridged interface is the BVI */
+ u32 shg, /* the bridged interface split horizon group */
+ u32 xc_sw_if_index) /* peer interface for xconnect */
{
l2input_main_t *mp = &l2input_main;
l2output_main_t *l2om = &l2output_main;
l2_output_config_t *out_config;
l2_input_config_t *config;
l2_bridge_domain_t *bd_config;
- l2_flood_member_t member;
u64 mac;
i32 l2_if_adjust = 0;
u32 slot;
VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
ASSERT (slot == VNET_SIMULATED_ETHERNET_TX_NEXT_ETHERNET_INPUT);
}
+
+ /* Clear MACs learned on the interface */
+ if ((config->feature_bitmap & L2INPUT_FEAT_LEARN) ||
+ (bd_config->feature_bitmap & L2INPUT_FEAT_LEARN))
+ l2fib_flush_int_mac (vm, sw_if_index);
+
l2_if_adjust--;
}
else if (config->xconnect)
config->bd_index = 0;
config->feature_bitmap = L2INPUT_FEAT_DROP;
+ /* Clear L2 output config */
+ out_config = l2output_intf_config (sw_if_index);
+ memset (out_config, 0, sizeof (l2_output_config_t));
+
/* Make sure any L2-output packet to this interface now in L3 mode is
* dropped. This may happen if L2 FIB MAC entry is stale */
l2om->next_nodes.output_node_index_vec[sw_if_index] =
config->xconnect = 0;
config->bridge = 1;
config->bd_index = bd_index;
+ config->seq_num += 1;
/*
* Enable forwarding, flooding, learning and ARP termination by default
config->feature_bitmap &= ~L2INPUT_FEAT_XCONNECT;
/* Set up bridge domain */
- vec_validate (mp->bd_configs, bd_index);
- bd_config = vec_elt_at_index (mp->bd_configs, bd_index);
+ bd_config = l2input_bd_config (bd_index);
bd_validate (bd_config);
/* TODO: think: add l2fib entry even for non-bvi interface? */
}
/* Add interface to bridge-domain flood vector */
- member.sw_if_index = sw_if_index;
- member.flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL;
- member.shg = shg;
+ l2_flood_member_t member = {
+ .sw_if_index = sw_if_index,
+ .flags = bvi ? L2_FLOOD_MEMBER_BVI : L2_FLOOD_MEMBER_NORMAL,
+ .shg = shg,
+ };
bd_add_member (bd_config, &member);
}
shg = 0; /* not used in xconnect */
}
- /* set up split-horizon group */
+ /* set up split-horizon group and set output feature bit */
config->shg = shg;
out_config = l2output_intf_config (sw_if_index);
out_config->shg = shg;
+ out_config->feature_bitmap |= L2OUTPUT_FEAT_OUTPUT;
/*
* Test: remove this when non-IP features can be configured.
goto done;
}
+ if (bd_id > L2_BD_ID_MAX)
+ {
+ error = clib_error_return (0, "bridge domain ID exceed 16M limit",
+ format_unformat_error, input);
+ goto done;
+ }
bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
/* optional bvi */
char *mode;
u8 *args;
vnet_interface_main_t *im = &vnm->interface_main;
- vnet_sw_interface_t *si, *sis = 0;
- l2input_main_t *mp = &l2input_main;
- l2_input_config_t *config;
+ vnet_sw_interface_t *si, *sis = 0;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
u32 sw_if_index;
format_unformat_error, input);
goto done;
}
-
}
if (vec_len (sis) == 0) /* Get all interfaces */
vec_foreach (si, sis)
{
- vec_validate (mp->configs, si->sw_if_index);
- config = vec_elt_at_index (mp->configs, si->sw_if_index);
+ l2_input_config_t *config = l2input_intf_config (si->sw_if_index);
if (config->bridge)
{
u32 bd_id;