aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEyal Bari <ebari@cisco.com>2017-07-16 09:34:53 +0300
committerEyal Bari <ebari@cisco.com>2017-07-24 08:21:52 +0300
commit001fd406df771f1cf73ca0dea440c8bde309e077 (patch)
treebfa98f32f5cba2d5fe06e2bc39a03b4d6ce98112 /src
parentbeb0b2e346c63e21ffe892ae0e04b67bb10fba5e (diff)
SPAN:add l2 mirror
added span feature nodes for l2-input / l2-output Change-Id: Ib6e0ce60d0811901b6edd70209e6a4c4a35cd8ff Signed-off-by: Eyal Bari <ebari@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/vat/api_format.c6
-rw-r--r--src/vnet/l2/l2_input.h5
-rw-r--r--src/vnet/l2/l2_output.c13
-rw-r--r--src/vnet/l2/l2_output.h8
-rw-r--r--src/vnet/span/node.c198
-rw-r--r--src/vnet/span/span.api1
-rw-r--r--src/vnet/span/span.c148
-rw-r--r--src/vnet/span/span.h25
-rw-r--r--src/vnet/span/span_api.c15
-rw-r--r--src/vpp/api/custom_dump.c3
10 files changed, 284 insertions, 138 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 40eca8c5d57..932e162d7bc 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -18082,6 +18082,7 @@ api_sw_interface_span_enable_disable (vat_main_t * vam)
u32 dst_sw_if_index = ~0;
u8 state = 3;
int ret;
+ u8 is_l2 = 0;
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
{
@@ -18104,6 +18105,8 @@ api_sw_interface_span_enable_disable (vat_main_t * vam)
state = 2;
else if (unformat (i, "both"))
state = 3;
+ else if (unformat (i, "l2"))
+ is_l2 = 1;
else
break;
}
@@ -18113,6 +18116,7 @@ api_sw_interface_span_enable_disable (vat_main_t * vam)
mp->sw_if_index_from = htonl (src_sw_if_index);
mp->sw_if_index_to = htonl (dst_sw_if_index);
mp->state = state;
+ mp->is_l2 = is_l2;
S (mp);
W (ret);
@@ -20044,7 +20048,7 @@ _(set_ipfix_classify_stream, "[domain <domain-id>] [src_port <src-port>]") \
_(ipfix_classify_stream_dump, "") \
_(ipfix_classify_table_add_del, "table <table-index> ip4|ip6 [tcp|udp]") \
_(ipfix_classify_table_dump, "") \
-_(sw_interface_span_enable_disable, "[src <intfc> | src_sw_if_index <id>] [disable | [[dst <intfc> | dst_sw_if_index <id>] [both|rx|tx]]]") \
+_(sw_interface_span_enable_disable, "[l2] [src <intfc> | src_sw_if_index <id>] [disable | [[dst <intfc> | dst_sw_if_index <id>] [both|rx|tx]]]") \
_(sw_interface_span_dump, "") \
_(get_next_index, "node-name <node-name> next-node-name <node-name>") \
_(pg_create_interface, "if_id <nn>") \
diff --git a/src/vnet/l2/l2_input.h b/src/vnet/l2/l2_input.h
index 244ef445ca8..e6b3bc7f9cd 100644
--- a/src/vnet/l2/l2_input.h
+++ b/src/vnet/l2/l2_input.h
@@ -102,7 +102,7 @@ l2input_bd_config (u32 bd_index)
/* L2 input features */
-/* Mappings from feature ID to graph node name */
+/* Mappings from feature ID to graph node name in reverse order */
#define foreach_l2input_feat \
_(DROP, "feature-bitmap-drop") \
_(XCONNECT, "l2-output") \
@@ -116,7 +116,8 @@ l2input_bd_config (u32 bd_index)
_(VPATH, "vpath-input-l2") \
_(ACL, "l2-input-acl") \
_(POLICER_CLAS, "l2-policer-classify") \
- _(INPUT_CLASSIFY, "l2-input-classify")
+ _(INPUT_CLASSIFY, "l2-input-classify") \
+ _(SPAN, "span-l2-input")
/* Feature bitmap positions */
typedef enum
diff --git a/src/vnet/l2/l2_output.c b/src/vnet/l2/l2_output.c
index b3537a355cf..fbee590c944 100644
--- a/src/vnet/l2/l2_output.c
+++ b/src/vnet/l2/l2_output.c
@@ -195,8 +195,6 @@ l2output_vtr (vlib_node_runtime_t * node, l2_output_config_t * config,
}
-static vlib_node_registration_t l2output_node;
-
static_always_inline uword
l2output_node_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * frame, int do_trace)
@@ -477,7 +475,7 @@ l2output_node_fn (vlib_main_t * vm,
}
/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (l2output_node,static) = {
+VLIB_REGISTER_NODE (l2output_node) = {
.function = l2output_node_fn,
.name = "l2-output",
.vector_size = sizeof (u32),
@@ -495,6 +493,8 @@ VLIB_REGISTER_NODE (l2output_node,static) = {
[L2OUTPUT_NEXT_BAD_INTF] = "l2-output-bad-intf",
},
};
+
+VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn);
/* *INDENT-ON* */
@@ -601,11 +601,12 @@ VLIB_REGISTER_NODE (l2output_bad_intf_node,static) = {
[0] = "error-drop",
},
};
-/* *INDENT-ON* */
+VLIB_NODE_FUNCTION_MULTIARCH (l2output_bad_intf_node, l2output_bad_intf_node_fn);
+/* *INDENT-ON* */
-VLIB_NODE_FUNCTION_MULTIARCH (l2output_node, l2output_node_fn)
- clib_error_t *l2output_init (vlib_main_t * vm)
+static clib_error_t *
+l2output_init (vlib_main_t * vm)
{
l2output_main_t *mp = &l2output_main;
diff --git a/src/vnet/l2/l2_output.h b/src/vnet/l2/l2_output.h
index 6da3e303c3b..a54b8d67c93 100644
--- a/src/vnet/l2/l2_output.h
+++ b/src/vnet/l2/l2_output.h
@@ -77,12 +77,14 @@ typedef struct
l2output_main_t l2output_main;
+extern vlib_node_registration_t l2output_node;
+
/* L2 output features */
-/* Mappings from feature ID to graph node name */
+/* Mappings from feature ID to graph node name in reverse order */
#define foreach_l2output_feat \
_(OUTPUT, "interface-output") \
- _(SPAN, "feature-bitmap-drop") \
+ _(SPAN, "span-l2-output") \
_(CFM, "feature-bitmap-drop") \
_(QOS, "feature-bitmap-drop") \
_(ACL, "l2-output-acl") \
@@ -103,6 +105,8 @@ typedef enum
L2OUTPUT_N_FEAT,
} l2output_feat_t;
+STATIC_ASSERT (L2OUTPUT_N_FEAT <= 32, "too many l2 output features");
+
/* Feature bit masks */
typedef enum
{
diff --git a/src/vnet/span/node.c b/src/vnet/span/node.c
index 3a461b0a3d3..9d83d4ef288 100644
--- a/src/vnet/span/node.c
+++ b/src/vnet/span/node.c
@@ -18,6 +18,9 @@
#include <vppinfra/error.h>
#include <vnet/span/span.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/l2/l2_output.h>
+#include <vnet/l2/feat_bitmap.h>
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
@@ -59,21 +62,19 @@ static char *span_error_strings[] = {
static_always_inline void
span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
- vlib_buffer_t * b0, vlib_frame_t ** mirror_frames, int is_rx)
+ vlib_buffer_t * b0, vlib_frame_t ** mirror_frames,
+ vlib_rx_or_tx_t rxtx, span_feat_t sf)
{
vlib_buffer_t *c0;
span_main_t *sm = &span_main;
vnet_main_t *vnm = &vnet_main;
- span_interface_t *si0 = 0;
u32 *to_mirror_next = 0;
u32 i;
- si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
+ span_interface_t *si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
+ span_mirror_t *sm0 = &si0->mirror_rxtx[sf][rxtx];
- if (is_rx != 0 && si0->num_rx_mirror_ports == 0)
- return;
-
- if (is_rx == 0 && si0->num_tx_mirror_ports == 0)
+ if (sm0->num_mirror_ports == 0)
return;
/* Don't do it again */
@@ -81,10 +82,15 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
return;
/* *INDENT-OFF* */
- clib_bitmap_foreach (i, is_rx ? si0->rx_mirror_ports : si0->tx_mirror_ports, (
+ clib_bitmap_foreach (i, sm0->mirror_ports, (
{
if (mirror_frames[i] == 0)
- mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
+ {
+ if (sf == SPAN_FEAT_L2)
+ mirror_frames[i] = vlib_get_frame_to_node (vnm->vlib_main, l2output_node.index);
+ else
+ mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
+ }
to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
to_mirror_next += mirror_frames[i]->n_vectors;
/* This can fail */
@@ -93,6 +99,8 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
{
vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
+ if (sf == SPAN_FEAT_L2)
+ vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
mirror_frames[i]->n_vectors++;
if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
@@ -108,7 +116,8 @@ span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
static_always_inline uword
span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame, int is_rx)
+ vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
+ span_feat_t sf)
{
span_main_t *sm = &span_main;
vnet_main_t *vnm = &vnet_main;
@@ -117,7 +126,6 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
u32 next_index;
u32 sw_if_index;
static __thread vlib_frame_t **mirror_frames = 0;
- vlib_rx_or_tx_t rxtx = is_rx ? VLIB_RX : VLIB_TX;
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
@@ -156,11 +164,33 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
- span_mirror (vm, node, sw_if_index0, b0, mirror_frames, is_rx);
- span_mirror (vm, node, sw_if_index1, b1, mirror_frames, is_rx);
-
- vnet_feature_next (sw_if_index0, &next0, b0);
- vnet_feature_next (sw_if_index1, &next1, b1);
+ span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
+ span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
+
+ switch (sf)
+ {
+ case SPAN_FEAT_L2:
+ if (rxtx == VLIB_RX)
+ {
+ next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
+ L2INPUT_FEAT_SPAN);
+ next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
+ L2INPUT_FEAT_SPAN);
+ }
+ else
+ {
+ next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
+ L2OUTPUT_FEAT_SPAN);
+ next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
+ L2OUTPUT_FEAT_SPAN);
+ }
+ break;
+ case SPAN_FEAT_DEVICE:
+ default:
+ vnet_feature_next (sw_if_index0, &next0, b0);
+ vnet_feature_next (sw_if_index1, &next1, b1);
+ break;
+ }
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
@@ -184,9 +214,23 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
b0 = vlib_get_buffer (vm, bi0);
sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
- span_mirror (vm, node, sw_if_index0, b0, mirror_frames, is_rx);
-
- vnet_feature_next (sw_if_index0, &next0, b0);
+ span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
+
+ switch (sf)
+ {
+ case SPAN_FEAT_L2:
+ if (rxtx == VLIB_RX)
+ next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
+ L2INPUT_FEAT_SPAN);
+ else
+ next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
+ L2OUTPUT_FEAT_SPAN);
+ break;
+ case SPAN_FEAT_DEVICE:
+ default:
+ vnet_feature_next (sw_if_index0, &next0, b0);
+ break;
+ }
/* verify speculative enqueue, maybe switch current next frame */
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
@@ -199,11 +243,14 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
{
- if (mirror_frames[sw_if_index] == 0)
+ vlib_frame_t *f = mirror_frames[sw_if_index];
+ if (f == 0)
continue;
- vnet_put_frame_to_sw_interface (vnm, sw_if_index,
- mirror_frames[sw_if_index]);
+ if (sf == SPAN_FEAT_L2)
+ vlib_put_frame_to_node (vnm->vlib_main, l2output_node.index, f);
+ else
+ vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
mirror_frames[sw_if_index] = 0;
}
vlib_node_increment_counter (vm, span_node.index, SPAN_ERROR_HITS,
@@ -213,62 +260,103 @@ span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
}
static uword
-span_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+span_device_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
- return span_node_inline_fn (vm, node, frame, 1);
+ return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
}
static uword
-span_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+span_device_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
- return span_node_inline_fn (vm, node, frame, 0);
+ return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
}
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (span_input_node) = {
- .function = span_input_node_fn,
- .name = "span-input",
- .vector_size = sizeof (u32),
- .format_trace = format_span_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
+static uword
+span_l2_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
+}
- .n_errors = ARRAY_LEN(span_error_strings),
- .error_strings = span_error_strings,
+static uword
+span_l2_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
+}
- .n_next_nodes = 0,
+#define span_node_defs \
+ .vector_size = sizeof (u32), \
+ .format_trace = format_span_trace, \
+ .type = VLIB_NODE_TYPE_INTERNAL, \
+ .n_errors = ARRAY_LEN(span_error_strings), \
+ .error_strings = span_error_strings, \
+ .n_next_nodes = 0, \
+ .next_nodes = { \
+ [0] = "error-drop" \
+ }
- /* edit / add dispositions here */
- .next_nodes = {
- [0] = "error-drop",
- },
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (span_input_node) = {
+ span_node_defs,
+ .function = span_device_input_node_fn,
+ .name = "span-input",
};
-VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_input_node_fn)
+VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_device_input_node_fn)
VLIB_REGISTER_NODE (span_output_node) = {
- .function = span_output_node_fn,
+ span_node_defs,
+ .function = span_device_output_node_fn,
.name = "span-output",
- .vector_size = sizeof (u32),
- .format_trace = format_span_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
+};
- .n_errors = ARRAY_LEN(span_error_strings),
- .error_strings = span_error_strings,
+VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_device_output_node_fn)
- .n_next_nodes = 0,
+VLIB_REGISTER_NODE (span_l2_input_node) = {
+ span_node_defs,
+ .function = span_l2_input_node_fn,
+ .name = "span-l2-input",
+};
- /* edit / add dispositions here */
- .next_nodes = {
- [0] = "error-drop",
- },
+VLIB_NODE_FUNCTION_MULTIARCH (span_l2_input_node, span_l2_input_node_fn)
+
+VLIB_REGISTER_NODE (span_l2_output_node) = {
+ span_node_defs,
+ .function = span_l2_output_node_fn,
+ .name = "span-l2-output",
};
-VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_output_node_fn)
+VLIB_NODE_FUNCTION_MULTIARCH (span_l2_output_node, span_l2_output_node_fn)
+
+clib_error_t *span_init (vlib_main_t * vm)
+{
+ span_main_t *sm = &span_main;
+
+ sm->vlib_main = vm;
+ sm->vnet_main = vnet_get_main ();
+
+ /* Initialize the feature next-node indexes */
+ feat_bitmap_init_next_nodes (vm,
+ span_l2_input_node.index,
+ L2INPUT_N_FEAT,
+ l2input_get_feat_names (),
+ sm->l2_input_next);
+
+ feat_bitmap_init_next_nodes (vm,
+ span_l2_output_node.index,
+ L2OUTPUT_N_FEAT,
+ l2output_get_feat_names (),
+ sm->l2_output_next);
+ return 0;
+}
+VLIB_INIT_FUNCTION (span_init);
/* *INDENT-ON* */
+#undef span_node_defs
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/span/span.api b/src/vnet/span/span.api
index 914fd8d0b40..2a762ac2582 100644
--- a/src/vnet/span/span.api
+++ b/src/vnet/span/span.api
@@ -27,6 +27,7 @@ autoreply define sw_interface_span_enable_disable {
u32 sw_if_index_from;
u32 sw_if_index_to;
u8 state;
+ u8 is_l2;
};
/** \brief SPAN dump request
diff --git a/src/vnet/span/span.c b/src/vnet/span/span.c
index c5b43e343c4..6ecd17895ef 100644
--- a/src/vnet/span/span.c
+++ b/src/vnet/span/span.c
@@ -16,60 +16,81 @@
#include <vlib/vlib.h>
#include <vppinfra/error.h>
#include <vnet/feature/feature.h>
+#include <vnet/l2/l2_input.h>
+#include <vnet/l2/l2_output.h>
#include <vnet/span/span.h>
+typedef enum
+{
+ SPAN_DISABLE = 0,
+ SPAN_RX = 1,
+ SPAN_TX = 2,
+ SPAN_BOTH = SPAN_RX | SPAN_TX
+} span_state_t;
+
+static_always_inline u32
+span_dst_set (span_mirror_t * sm, u32 dst_sw_if_index, int enable)
+{
+ sm->mirror_ports =
+ clib_bitmap_set (sm->mirror_ports, dst_sw_if_index, enable);
+ u32 last = sm->num_mirror_ports;
+ sm->num_mirror_ports = clib_bitmap_count_set_bits (sm->mirror_ports);
+ return last;
+}
+
int
span_add_delete_entry (vlib_main_t * vm,
- u32 src_sw_if_index, u32 dst_sw_if_index, u8 state)
+ u32 src_sw_if_index, u32 dst_sw_if_index, u8 state,
+ span_feat_t sf)
{
span_main_t *sm = &span_main;
- span_interface_t *si;
- u32 new_num_rx_mirror_ports, new_num_tx_mirror_ports;
- if (state > 3)
+ if (state > SPAN_BOTH)
return VNET_API_ERROR_UNIMPLEMENTED;
if ((src_sw_if_index == ~0) || (dst_sw_if_index == ~0 && state > 0)
|| (src_sw_if_index == dst_sw_if_index))
return VNET_API_ERROR_INVALID_INTERFACE;
- vnet_sw_interface_t *sw_if;
-
- sw_if = vnet_get_sw_interface (vnet_get_main (), src_sw_if_index);
- if (sw_if->type == VNET_SW_INTERFACE_TYPE_SUB)
- return VNET_API_ERROR_UNIMPLEMENTED;
-
vec_validate_aligned (sm->interfaces, src_sw_if_index,
CLIB_CACHE_LINE_BYTES);
- si = vec_elt_at_index (sm->interfaces, src_sw_if_index);
-
- si->rx_mirror_ports = clib_bitmap_set (si->rx_mirror_ports, dst_sw_if_index,
- (state & 1) != 0);
- si->tx_mirror_ports = clib_bitmap_set (si->tx_mirror_ports, dst_sw_if_index,
- (state & 2) != 0);
- new_num_rx_mirror_ports = clib_bitmap_count_set_bits (si->rx_mirror_ports);
- new_num_tx_mirror_ports = clib_bitmap_count_set_bits (si->tx_mirror_ports);
+ span_interface_t *si = vec_elt_at_index (sm->interfaces, src_sw_if_index);
- if (new_num_rx_mirror_ports == 1 && si->num_rx_mirror_ports == 0)
- vnet_feature_enable_disable ("device-input", "span-input",
- src_sw_if_index, 1, 0, 0);
+ int rx = ! !(state & SPAN_RX);
+ int tx = ! !(state & SPAN_TX);
- if (new_num_rx_mirror_ports == 0 && si->num_rx_mirror_ports == 1)
- vnet_feature_enable_disable ("device-input", "span-input",
- src_sw_if_index, 0, 0, 0);
+ span_mirror_t *rxm = &si->mirror_rxtx[sf][VLIB_RX];
+ span_mirror_t *txm = &si->mirror_rxtx[sf][VLIB_TX];
- if (new_num_rx_mirror_ports == 1 && si->num_rx_mirror_ports == 0)
- vnet_feature_enable_disable ("interface-output", "span-output",
- src_sw_if_index, 1, 0, 0);
+ u32 last_rx_ports_count = span_dst_set (rxm, dst_sw_if_index, rx);
+ u32 last_tx_ports_count = span_dst_set (txm, dst_sw_if_index, tx);
- if (new_num_rx_mirror_ports == 0 && si->num_rx_mirror_ports == 1)
- vnet_feature_enable_disable ("interface-output", "span-output",
- src_sw_if_index, 0, 0, 0);
+ int enable_rx = last_rx_ports_count == 0 && rxm->num_mirror_ports == 1;
+ int disable_rx = last_rx_ports_count == 1 && rxm->num_mirror_ports == 0;
+ int enable_tx = last_tx_ports_count == 0 && txm->num_mirror_ports == 1;
+ int disable_tx = last_tx_ports_count == 1 && txm->num_mirror_ports == 0;
- si->num_rx_mirror_ports = new_num_rx_mirror_ports;
- si->num_tx_mirror_ports = new_num_tx_mirror_ports;
+ switch (sf)
+ {
+ case SPAN_FEAT_DEVICE:
+ if (enable_rx || disable_rx)
+ vnet_feature_enable_disable ("device-input", "span-input",
+ src_sw_if_index, rx, 0, 0);
+ if (enable_tx || disable_tx)
+ vnet_feature_enable_disable ("interface-output", "span-output",
+ src_sw_if_index, tx, 0, 0);
+ break;
+ case SPAN_FEAT_L2:
+ if (enable_rx || disable_rx)
+ l2input_intf_bitmap_enable (src_sw_if_index, L2INPUT_FEAT_SPAN, rx);
+ if (enable_tx || disable_tx)
+ l2output_intf_bitmap_enable (src_sw_if_index, L2OUTPUT_FEAT_SPAN, tx);
+ break;
+ default:
+ return VNET_API_ERROR_UNIMPLEMENTED;
+ }
if (dst_sw_if_index > sm->max_sw_if_index)
sm->max_sw_if_index = dst_sw_if_index;
@@ -85,7 +106,8 @@ set_interface_span_command_fn (vlib_main_t * vm,
span_main_t *sm = &span_main;
u32 src_sw_if_index = ~0;
u32 dst_sw_if_index = ~0;
- u8 state = 3;
+ u8 state = SPAN_BOTH;
+ span_feat_t sf = SPAN_FEAT_DEVICE;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
@@ -96,19 +118,21 @@ set_interface_span_command_fn (vlib_main_t * vm,
sm->vnet_main, &dst_sw_if_index))
;
else if (unformat (input, "disable"))
- state = 0;
+ state = SPAN_DISABLE;
else if (unformat (input, "rx"))
- state = 1;
+ state = SPAN_RX;
else if (unformat (input, "tx"))
- state = 2;
+ state = SPAN_TX;
else if (unformat (input, "both"))
- state = 3;
+ state = SPAN_BOTH;
+ else if (unformat (input, "l2"))
+ sf = SPAN_FEAT_L2;
else
break;
}
int rv =
- span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state);
+ span_add_delete_entry (vm, src_sw_if_index, dst_sw_if_index, state, sf);
if (rv == VNET_API_ERROR_INVALID_INTERFACE)
return clib_error_return (0, "Invalid interface");
return 0;
@@ -117,7 +141,7 @@ set_interface_span_command_fn (vlib_main_t * vm,
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (set_interface_span_command, static) = {
.path = "set interface span",
- .short_help = "set interface span <if-name> [disable | destination <if-name> [both|rx|tx]]",
+ .short_help = "set interface span <if-name> [l2] {disable | destination <if-name> [both|rx|tx]}",
.function = set_interface_span_command_fn,
};
/* *INDENT-ON* */
@@ -136,31 +160,44 @@ show_interfaces_span_command_fn (vlib_main_t * vm,
/* *INDENT-OFF* */
vec_foreach (si, sm->interfaces)
- if (si->num_rx_mirror_ports || si->num_tx_mirror_ports)
+ {
+ span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX];
+ span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX];
+
+ span_mirror_t * lrxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_RX];
+ span_mirror_t * ltxm = &si->mirror_rxtx[SPAN_FEAT_L2][VLIB_TX];
+
+ if (drxm->num_mirror_ports || dtxm->num_mirror_ports ||
+ lrxm->num_mirror_ports || ltxm->num_mirror_ports)
{
- clib_bitmap_t *b;
u32 i;
- b = clib_bitmap_dup_or (si->rx_mirror_ports, si->tx_mirror_ports);
+ clib_bitmap_t *d = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports);
+ clib_bitmap_t *l = clib_bitmap_dup_or (lrxm->mirror_ports, ltxm->mirror_ports);
+ clib_bitmap_t *b = clib_bitmap_dup_or (d, l);
if (header)
{
- vlib_cli_output (vm, "%-40s %s", "Source interface",
- "Mirror interface (direction)");
+ vlib_cli_output (vm, "%-20s %-20s %6s %6s", "Source", "Destination",
+ "Device", "L2");
header = 0;
}
s = format (s, "%U", format_vnet_sw_if_index_name, vnm,
si - sm->interfaces);
clib_bitmap_foreach (i, b, (
{
- int state;
- state = (clib_bitmap_get (si->rx_mirror_ports, i) +
- clib_bitmap_get (si->tx_mirror_ports, i) * 2);
+ int device = (clib_bitmap_get (drxm->mirror_ports, i) +
+ clib_bitmap_get (dtxm->mirror_ports, i) * 2);
+ int l2 = (clib_bitmap_get (lrxm->mirror_ports, i) +
+ clib_bitmap_get (ltxm->mirror_ports, i) * 2);
- vlib_cli_output (vm, "%-40v %U (%s)", s,
+ vlib_cli_output (vm, "%-20v %-20U (%6s) (%6s)", s,
format_vnet_sw_if_index_name, vnm, i,
- states[state]);
+ states[device], states[l2]);
vec_reset_length (s);
}));
clib_bitmap_free (b);
+ clib_bitmap_free (l);
+ clib_bitmap_free (d);
+ }
}
/* *INDENT-ON* */
vec_free (s);
@@ -175,19 +212,6 @@ VLIB_CLI_COMMAND (show_interfaces_span_command, static) = {
};
/* *INDENT-ON* */
-static clib_error_t *
-span_init (vlib_main_t * vm)
-{
- span_main_t *sm = &span_main;
-
- sm->vlib_main = vm;
- sm->vnet_main = vnet_get_main ();
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (span_init);
-
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/span/span.h b/src/vnet/span/span.h
index a98b010bf61..10de8272ab0 100644
--- a/src/vnet/span/span.h
+++ b/src/vnet/span/span.h
@@ -18,17 +18,32 @@
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
+#include <vnet/l2/l2_output.h>
+
+typedef enum
+{
+ SPAN_FEAT_DEVICE,
+ SPAN_FEAT_L2,
+ SPAN_FEAT_N
+} span_feat_t;
+
+typedef struct
+{
+ clib_bitmap_t *mirror_ports;
+ u32 num_mirror_ports;
+} span_mirror_t;
typedef struct
{
- clib_bitmap_t *rx_mirror_ports;
- clib_bitmap_t *tx_mirror_ports;
- u32 num_rx_mirror_ports;
- u32 num_tx_mirror_ports;
+ span_mirror_t mirror_rxtx[SPAN_FEAT_N][VLIB_N_RX_TX];
} span_interface_t;
typedef struct
{
+ /* l2 feature Next nodes */
+ u32 l2_input_next[32];
+ u32 l2_output_next[32];
+
/* per-interface vector of span instances */
span_interface_t *interfaces;
@@ -52,7 +67,7 @@ typedef struct
int
span_add_delete_entry (vlib_main_t * vm, u32 src_sw_if_index,
- u32 dst_sw_if_index, u8 is_add);
+ u32 dst_sw_if_index, u8 state, span_feat_t sf);
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/span/span_api.c b/src/vnet/span/span_api.c
index b4565663eb9..69fa8e974fa 100644
--- a/src/vnet/span/span_api.c
+++ b/src/vnet/span/span_api.c
@@ -56,7 +56,8 @@ static void
vlib_main_t *vm = vlib_get_main ();
rv = span_add_delete_entry (vm, ntohl (mp->sw_if_index_from),
- ntohl (mp->sw_if_index_to), mp->state);
+ ntohl (mp->sw_if_index_to), mp->state,
+ mp->is_l2 ? SPAN_FEAT_L2 : SPAN_FEAT_DEVICE);
REPLY_MACRO (VL_API_SW_INTERFACE_SPAN_ENABLE_DISABLE_REPLY);
}
@@ -76,11 +77,14 @@ vl_api_sw_interface_span_dump_t_handler (vl_api_sw_interface_span_dump_t * mp)
/* *INDENT-OFF* */
vec_foreach (si, sm->interfaces)
- if (si->num_rx_mirror_ports || si->num_tx_mirror_ports)
+ {
+ span_mirror_t * drxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_RX];
+ span_mirror_t * dtxm = &si->mirror_rxtx[SPAN_FEAT_DEVICE][VLIB_TX];
+ if (drxm->num_mirror_ports || dtxm->num_mirror_ports)
{
clib_bitmap_t *b;
u32 i;
- b = clib_bitmap_dup_or (si->rx_mirror_ports, si->tx_mirror_ports);
+ b = clib_bitmap_dup_or (drxm->mirror_ports, dtxm->mirror_ports);
clib_bitmap_foreach (i, b, (
{
rmp = vl_msg_api_alloc (sizeof (*rmp));
@@ -90,13 +94,14 @@ vl_api_sw_interface_span_dump_t_handler (vl_api_sw_interface_span_dump_t * mp)
rmp->sw_if_index_from = htonl (si - sm->interfaces);
rmp->sw_if_index_to = htonl (i);
- rmp->state = (u8) (clib_bitmap_get (si->rx_mirror_ports, i) +
- clib_bitmap_get (si->tx_mirror_ports, i) * 2);
+ rmp->state = (u8) (clib_bitmap_get (drxm->mirror_ports, i) +
+ clib_bitmap_get (dtxm->mirror_ports, i) * 2);
vl_msg_api_send_shmem (q, (u8 *) & rmp);
}));
clib_bitmap_free (b);
}
+ }
/* *INDENT-ON* */
}
diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c
index 7f3a58d9523..55a362a386b 100644
--- a/src/vpp/api/custom_dump.c
+++ b/src/vpp/api/custom_dump.c
@@ -2227,6 +2227,9 @@ static void *vl_api_sw_interface_span_enable_disable_t_print
s = format (s, "src_sw_if_index %u ", ntohl (mp->sw_if_index_from));
s = format (s, "dst_sw_if_index %u ", ntohl (mp->sw_if_index_to));
+ if (mp->is_l2)
+ s = format (s, "l2 ");
+
switch (mp->state)
{
case 0: