diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/vat/api_format.c | 6 | ||||
-rw-r--r-- | src/vnet/l2/l2_input.h | 5 | ||||
-rw-r--r-- | src/vnet/l2/l2_output.c | 13 | ||||
-rw-r--r-- | src/vnet/l2/l2_output.h | 8 | ||||
-rw-r--r-- | src/vnet/span/node.c | 198 | ||||
-rw-r--r-- | src/vnet/span/span.api | 1 | ||||
-rw-r--r-- | src/vnet/span/span.c | 148 | ||||
-rw-r--r-- | src/vnet/span/span.h | 25 | ||||
-rw-r--r-- | src/vnet/span/span_api.c | 15 | ||||
-rw-r--r-- | src/vpp/api/custom_dump.c | 3 |
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: |