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;
73 span_interface_t *si0;
76 if (sw_if_index0 >= vec_len (sm->interfaces))
79 si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
80 sm0 = &si0->mirror_rxtx[sf][rxtx];
82 if (sm0->num_mirror_ports == 0)
85 /* Don't do it again */
86 if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_SPAN_CLONE))
90 clib_bitmap_foreach (i, sm0->mirror_ports, (
92 if (mirror_frames[i] == 0)
94 if (sf == SPAN_FEAT_L2)
95 mirror_frames[i] = vlib_get_frame_to_node (vnm->vlib_main,
98 mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
100 to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
101 to_mirror_next += mirror_frames[i]->n_vectors;
103 c0 = vlib_buffer_copy (vm, b0);
104 if (PREDICT_TRUE(c0 != 0))
106 vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
107 c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
108 if (sf == SPAN_FEAT_L2)
109 vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
110 to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
111 mirror_frames[i]->n_vectors++;
112 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
114 span_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
115 t->src_sw_if_index = sw_if_index0;
116 t->mirror_sw_if_index = i;
118 /* Enable this path to allow packet trace of SPAN packets.
119 Note that all SPAN packets will show up on the trace output
120 with the first SPAN packet (since they are in the same frame)
121 thus making trace output of the original packet confusing */
122 mirror_frames[i]->flags |= VLIB_FRAME_TRACE;
123 c0->flags |= VLIB_BUFFER_IS_TRACED;
131 static_always_inline uword
132 span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
133 vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
136 span_main_t *sm = &span_main;
137 vnet_main_t *vnm = &vnet_main;
138 u32 n_left_from, *from, *to_next;
139 u32 n_span_packets = 0;
142 static __thread vlib_frame_t **mirror_frames = 0;
144 from = vlib_frame_vector_args (frame);
145 n_left_from = frame->n_vectors;
146 next_index = node->cached_next_index;
148 vec_validate_aligned (mirror_frames, sm->max_sw_if_index,
149 CLIB_CACHE_LINE_BYTES);
151 while (n_left_from > 0)
155 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
157 while (n_left_from >= 4 && n_left_to_next >= 2)
168 /* speculatively enqueue b0, b1 to the current next frame */
169 to_next[0] = bi0 = from[0];
170 to_next[1] = bi1 = from[1];
176 b0 = vlib_get_buffer (vm, bi0);
177 b1 = vlib_get_buffer (vm, bi1);
178 sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
179 sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
181 span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
182 span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
189 next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
191 next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
196 next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
198 next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
202 case SPAN_FEAT_DEVICE:
204 vnet_feature_next (sw_if_index0, &next0, b0);
205 vnet_feature_next (sw_if_index1, &next1, b1);
209 /* verify speculative enqueue, maybe switch current next frame */
210 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
211 to_next, n_left_to_next,
212 bi0, bi1, next0, next1);
214 while (n_left_from > 0 && n_left_to_next > 0)
221 /* speculatively enqueue b0 to the current next frame */
222 to_next[0] = bi0 = from[0];
228 b0 = vlib_get_buffer (vm, bi0);
229 sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
231 span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
237 next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
240 next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
243 case SPAN_FEAT_DEVICE:
245 vnet_feature_next (sw_if_index0, &next0, b0);
249 /* verify speculative enqueue, maybe switch current next frame */
250 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
251 n_left_to_next, bi0, next0);
254 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
258 for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
260 vlib_frame_t *f = mirror_frames[sw_if_index];
264 if (sf == SPAN_FEAT_L2)
265 vlib_put_frame_to_node (vnm->vlib_main, l2output_node.index, f);
267 vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
268 mirror_frames[sw_if_index] = 0;
270 vlib_node_increment_counter (vm, span_node.index, SPAN_ERROR_HITS,
273 return frame->n_vectors;
277 span_device_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
278 vlib_frame_t * frame)
280 return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
284 span_device_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
285 vlib_frame_t * frame)
287 return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
291 span_l2_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
292 vlib_frame_t * frame)
294 return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
298 span_l2_output_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
299 vlib_frame_t * frame)
301 return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
304 #define span_node_defs \
305 .vector_size = sizeof (u32), \
306 .format_trace = format_span_trace, \
307 .type = VLIB_NODE_TYPE_INTERNAL, \
308 .n_errors = ARRAY_LEN(span_error_strings), \
309 .error_strings = span_error_strings, \
316 VLIB_REGISTER_NODE (span_input_node) = {
318 .function = span_device_input_node_fn,
319 .name = "span-input",
322 VLIB_NODE_FUNCTION_MULTIARCH (span_input_node, span_device_input_node_fn)
324 VLIB_REGISTER_NODE (span_output_node) = {
326 .function = span_device_output_node_fn,
327 .name = "span-output",
330 VLIB_NODE_FUNCTION_MULTIARCH (span_output_node, span_device_output_node_fn)
332 VLIB_REGISTER_NODE (span_l2_input_node) = {
334 .function = span_l2_input_node_fn,
335 .name = "span-l2-input",
338 VLIB_NODE_FUNCTION_MULTIARCH (span_l2_input_node, span_l2_input_node_fn)
340 VLIB_REGISTER_NODE (span_l2_output_node) = {
342 .function = span_l2_output_node_fn,
343 .name = "span-l2-output",
346 VLIB_NODE_FUNCTION_MULTIARCH (span_l2_output_node, span_l2_output_node_fn)
348 clib_error_t *span_init (vlib_main_t * vm)
350 span_main_t *sm = &span_main;
353 sm->vnet_main = vnet_get_main ();
355 /* Initialize the feature next-node indexes */
356 feat_bitmap_init_next_nodes (vm,
357 span_l2_input_node.index,
359 l2input_get_feat_names (),
362 feat_bitmap_init_next_nodes (vm,
363 span_l2_output_node.index,
365 l2output_get_feat_names (),
370 VLIB_INIT_FUNCTION (span_init);
373 #undef span_node_defs
375 * fd.io coding-style-patch-verification: ON
378 * eval: (c-set-style "gnu")