2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vlib/vlib.h>
17 #include <vnet/vnet.h>
18 #include <vppinfra/error.h>
20 #include <vnet/span/span.h>
21 #include <vnet/l2/l2_input.h>
22 #include <vnet/l2/l2_output.h>
23 #include <vnet/l2/feat_bitmap.h>
25 #include <vppinfra/error.h>
26 #include <vppinfra/elog.h>
28 vlib_node_registration_t span_node;
30 /* packet trace format function */
32 format_span_trace (u8 * s, va_list * args)
34 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
35 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
36 span_trace_t *t = va_arg (*args, span_trace_t *);
38 vnet_main_t *vnm = &vnet_main;
39 s = format (s, "SPAN: mirrored %U -> %U",
40 format_vnet_sw_if_index_name, vnm, t->src_sw_if_index,
41 format_vnet_sw_if_index_name, vnm, t->mirror_sw_if_index);
46 #define foreach_span_error \
47 _(HITS, "SPAN incomming packets processed")
51 #define _(sym,str) SPAN_ERROR_##sym,
57 static char *span_error_strings[] = {
58 #define _(sym,string) string,
63 static_always_inline void
64 span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
65 vlib_buffer_t * b0, vlib_frame_t ** mirror_frames,
66 vlib_rx_or_tx_t rxtx, span_feat_t sf)
69 span_main_t *sm = &span_main;
70 vnet_main_t *vnm = &vnet_main;
71 u32 *to_mirror_next = 0;
74 span_interface_t *si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
75 span_mirror_t *sm0 = &si0->mirror_rxtx[sf][rxtx];
77 if (sm0->num_mirror_ports == 0)
80 /* Don't do it again */
81 if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_SPAN_CLONE))
85 clib_bitmap_foreach (i, sm0->mirror_ports, (
87 if (mirror_frames[i] == 0)
89 if (sf == SPAN_FEAT_L2)
90 mirror_frames[i] = vlib_get_frame_to_node (vnm->vlib_main,
93 mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
95 to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
96 to_mirror_next += mirror_frames[i]->n_vectors;
98 c0 = vlib_buffer_copy (vm, b0);
99 if (PREDICT_TRUE(c0 != 0))
101 vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
102 c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
103 if (sf == SPAN_FEAT_L2)
104 vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
105 to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
106 mirror_frames[i]->n_vectors++;
107 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
109 span_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
110 t->src_sw_if_index = sw_if_index0;
111 t->mirror_sw_if_index = i;
113 /* Enable this path to allow packet trace of SPAN packets.
114 Note that all SPAN packets will show up on the trace output
115 with the first SPAN packet (since they are in the same frame)
116 thus making trace output of the original packet confusing */
117 mirror_frames[i]->flags |= VLIB_FRAME_TRACE;
118 c0->flags |= VLIB_BUFFER_IS_TRACED;
126 static_always_inline uword
127 span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
128 vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
131 span_main_t *sm = &span_main;
132 vnet_main_t *vnm = &vnet_main;
133 u32 n_left_from, *from, *to_next;
134 u32 n_span_packets = 0;
137 static __thread vlib_frame_t **mirror_frames = 0;
139 from = vlib_frame_vector_args (frame);
140 n_left_from = frame->n_vectors;
141 next_index = node->cached_next_index;
143 vec_validate_aligned (mirror_frames, sm->max_sw_if_index,
144 CLIB_CACHE_LINE_BYTES);
146 while (n_left_from > 0)
150 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
152 while (n_left_from >= 4 && n_left_to_next >= 2)
163 /* speculatively enqueue b0, b1 to the current next frame */
164 to_next[0] = bi0 = from[0];
165 to_next[1] = bi1 = from[1];
171 b0 = vlib_get_buffer (vm, bi0);
172 b1 = vlib_get_buffer (vm, bi1);
173 sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
174 sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
176 span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
177 span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
184 next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
186 next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
191 next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
193 next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
197 case SPAN_FEAT_DEVICE:
199 vnet_feature_next (sw_if_index0, &next0, b0);
200 vnet_feature_next (sw_if_index1, &next1, b1);
204 /* verify speculative enqueue, maybe switch current next frame */
205 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
206 to_next, n_left_to_next,
207 bi0, bi1, next0, next1);
209 while (n_left_from > 0 && n_left_to_next > 0)
216 /* speculatively enqueue b0 to the current next frame */
217 to_next[0] = bi0 = from[0];
223 b0 = vlib_get_buffer (vm, bi0);
224 sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
226 span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
232 next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
235 next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
238 case SPAN_FEAT_DEVICE:
240 vnet_feature_next (sw_if_index0, &next0, b0);
244 /* verify speculative enqueue, maybe switch current next frame */
245 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
246 n_left_to_next, bi0, next0);
249 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
253 for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
255 vlib_frame_t *f = mirror_frames[sw_if_index];
259 if (sf == SPAN_FEAT_L2)
260 vlib_put_frame_to_node (vnm->vlib_main, l2output_node.index, f);
262 vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
263 mirror_frames[sw_if_index] = 0;
265 vlib_node_increment_counter (vm, span_node.index, SPAN_ERROR_HITS,
268 return frame->n_vectors;
272 span_device_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
273 vlib_frame_t * frame)
275 return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
279 span_device_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
280 vlib_frame_t * frame)
282 return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
286 span_l2_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
287 vlib_frame_t * frame)
289 return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
293 span_l2_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
294 vlib_frame_t * frame)
296 return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
299 #define span_node_defs \
300 .vector_size = sizeof (u32), \
301 .format_trace = format_span_trace, \
302 .type = VLIB_NODE_TYPE_INTERNAL, \
303 .n_errors = ARRAY_LEN(span_error_strings), \
304 .error_strings = span_error_strings, \
311 VLIB_REGISTER_NODE (span_input_node) = {
313 .function = span_device_input_node_fn,
314 .name = "span-input",
317 VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_device_input_node_fn)
319 VLIB_REGISTER_NODE (span_output_node) = {
321 .function = span_device_output_node_fn,
322 .name = "span-output",
325 VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_device_output_node_fn)
327 VLIB_REGISTER_NODE (span_l2_input_node) = {
329 .function = span_l2_input_node_fn,
330 .name = "span-l2-input",
333 VLIB_NODE_FUNCTION_MULTIARCH (span_l2_input_node, span_l2_input_node_fn)
335 VLIB_REGISTER_NODE (span_l2_output_node) = {
337 .function = span_l2_output_node_fn,
338 .name = "span-l2-output",
341 VLIB_NODE_FUNCTION_MULTIARCH (span_l2_output_node, span_l2_output_node_fn)
343 clib_error_t *span_init (vlib_main_t * vm)
345 span_main_t *sm = &span_main;
348 sm->vnet_main = vnet_get_main ();
350 /* Initialize the feature next-node indexes */
351 feat_bitmap_init_next_nodes (vm,
352 span_l2_input_node.index,
354 l2input_get_feat_names (),
357 feat_bitmap_init_next_nodes (vm,
358 span_l2_output_node.index,
360 l2output_get_feat_names (),
365 VLIB_INIT_FUNCTION (span_init);
368 #undef span_node_defs
370 * fd.io coding-style-patch-verification: ON
373 * eval: (c-set-style "gnu")