Line data Source code
1 : /*
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:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
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.
14 : */
15 :
16 : #include <vlib/vlib.h>
17 : #include <vnet/vnet.h>
18 : #include <vppinfra/error.h>
19 :
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>
24 :
25 : #include <vppinfra/error.h>
26 : #include <vppinfra/elog.h>
27 :
28 : /* packet trace format function */
29 : static u8 *
30 3084 : format_span_trace (u8 * s, va_list * args)
31 : {
32 3084 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
33 3084 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
34 3084 : span_trace_t *t = va_arg (*args, span_trace_t *);
35 :
36 3084 : vnet_main_t *vnm = vnet_get_main ();
37 3084 : s = format (s, "SPAN: mirrored %U -> %U",
38 : format_vnet_sw_if_index_name, vnm, t->src_sw_if_index,
39 : format_vnet_sw_if_index_name, vnm, t->mirror_sw_if_index);
40 :
41 3084 : return s;
42 : }
43 :
44 : #define foreach_span_error \
45 : _(HITS, "SPAN incoming packets processed")
46 :
47 : typedef enum
48 : {
49 : #define _(sym,str) SPAN_ERROR_##sym,
50 : foreach_span_error
51 : #undef _
52 : SPAN_N_ERROR,
53 : } span_error_t;
54 :
55 : static char *span_error_strings[] = {
56 : #define _(sym,string) string,
57 : foreach_span_error
58 : #undef _
59 : };
60 :
61 : static_always_inline void
62 3084 : span_mirror (vlib_main_t * vm, vlib_node_runtime_t * node, u32 sw_if_index0,
63 : vlib_buffer_t * b0, vlib_frame_t ** mirror_frames,
64 : vlib_rx_or_tx_t rxtx, span_feat_t sf)
65 : {
66 : vlib_buffer_t *c0;
67 3084 : span_main_t *sm = &span_main;
68 3084 : vnet_main_t *vnm = vnet_get_main ();
69 3084 : u32 *to_mirror_next = 0;
70 : u32 i;
71 : span_interface_t *si0;
72 : span_mirror_t *sm0;
73 :
74 3084 : if (sw_if_index0 >= vec_len (sm->interfaces))
75 0 : return;
76 :
77 3084 : si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
78 3084 : sm0 = &si0->mirror_rxtx[sf][rxtx];
79 :
80 3084 : if (sm0->num_mirror_ports == 0)
81 0 : return;
82 :
83 : /* Don't do it again */
84 3084 : if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_SPAN_CLONE))
85 0 : return;
86 :
87 : /* *INDENT-OFF* */
88 6168 : clib_bitmap_foreach (i, sm0->mirror_ports)
89 : {
90 3084 : if (mirror_frames[i] == 0)
91 : {
92 24 : if (sf == SPAN_FEAT_L2)
93 22 : mirror_frames[i] = vlib_get_frame_to_node (vm, l2output_node.index);
94 : else
95 2 : mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
96 : }
97 3084 : to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
98 3084 : to_mirror_next += mirror_frames[i]->n_vectors;
99 : /* This can fail */
100 3084 : c0 = vlib_buffer_copy (vm, b0);
101 3084 : if (PREDICT_TRUE(c0 != 0))
102 : {
103 3084 : vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
104 3084 : c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
105 3084 : if (sf == SPAN_FEAT_L2)
106 2827 : vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
107 3084 : to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
108 3084 : mirror_frames[i]->n_vectors++;
109 3084 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
110 : {
111 3084 : span_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
112 3084 : t->src_sw_if_index = sw_if_index0;
113 3084 : t->mirror_sw_if_index = i;
114 : #if 0
115 : /* Enable this path to allow packet trace of SPAN packets.
116 : Note that all SPAN packets will show up on the trace output
117 : with the first SPAN packet (since they are in the same frame)
118 : thus making trace output of the original packet confusing */
119 : mirror_frames[i]->flags |= VLIB_FRAME_TRACE;
120 : c0->flags |= VLIB_BUFFER_IS_TRACED;
121 : #endif
122 : }
123 : }
124 : }
125 : /* *INDENT-ON* */
126 : }
127 :
128 : static_always_inline uword
129 24 : span_node_inline_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
130 : vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
131 : span_feat_t sf)
132 : {
133 24 : span_main_t *sm = &span_main;
134 24 : vnet_main_t *vnm = vnet_get_main ();
135 : u32 n_left_from, *from, *to_next;
136 : u32 next_index;
137 : u32 sw_if_index;
138 : static __thread vlib_frame_t **mirror_frames = 0;
139 :
140 24 : from = vlib_frame_vector_args (frame);
141 24 : n_left_from = frame->n_vectors;
142 24 : next_index = node->cached_next_index;
143 :
144 24 : vec_validate_aligned (mirror_frames, sm->max_sw_if_index,
145 : CLIB_CACHE_LINE_BYTES);
146 :
147 48 : while (n_left_from > 0)
148 : {
149 : u32 n_left_to_next;
150 :
151 24 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
152 :
153 1548 : while (n_left_from >= 4 && n_left_to_next >= 2)
154 : {
155 : u32 bi0;
156 : u32 bi1;
157 : vlib_buffer_t *b0;
158 : vlib_buffer_t *b1;
159 : u32 sw_if_index0;
160 1524 : u32 next0 = 0;
161 : u32 sw_if_index1;
162 1524 : u32 next1 = 0;
163 :
164 : /* speculatively enqueue b0, b1 to the current next frame */
165 1524 : to_next[0] = bi0 = from[0];
166 1524 : to_next[1] = bi1 = from[1];
167 1524 : to_next += 2;
168 1524 : n_left_to_next -= 2;
169 1524 : from += 2;
170 1524 : n_left_from -= 2;
171 :
172 1524 : b0 = vlib_get_buffer (vm, bi0);
173 1524 : b1 = vlib_get_buffer (vm, bi1);
174 1524 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
175 1524 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
176 :
177 1524 : span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
178 1524 : span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
179 :
180 1524 : switch (sf)
181 : {
182 1397 : case SPAN_FEAT_L2:
183 1397 : if (rxtx == VLIB_RX)
184 : {
185 1016 : next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
186 : L2INPUT_FEAT_SPAN);
187 1016 : next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
188 : L2INPUT_FEAT_SPAN);
189 : }
190 : else
191 : {
192 381 : next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
193 : L2OUTPUT_FEAT_SPAN);
194 381 : next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
195 : L2OUTPUT_FEAT_SPAN);
196 : }
197 1397 : break;
198 127 : case SPAN_FEAT_DEVICE:
199 : default:
200 127 : vnet_feature_next (&next0, b0);
201 127 : vnet_feature_next (&next1, b1);
202 127 : break;
203 : }
204 :
205 : /* verify speculative enqueue, maybe switch current next frame */
206 1524 : vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
207 : to_next, n_left_to_next,
208 : bi0, bi1, next0, next1);
209 : }
210 60 : while (n_left_from > 0 && n_left_to_next > 0)
211 : {
212 : u32 bi0;
213 : vlib_buffer_t *b0;
214 : u32 sw_if_index0;
215 36 : u32 next0 = 0;
216 :
217 : /* speculatively enqueue b0 to the current next frame */
218 36 : to_next[0] = bi0 = from[0];
219 36 : to_next += 1;
220 36 : n_left_to_next -= 1;
221 36 : from += 1;
222 36 : n_left_from -= 1;
223 :
224 36 : b0 = vlib_get_buffer (vm, bi0);
225 36 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
226 :
227 36 : span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
228 :
229 36 : switch (sf)
230 : {
231 33 : case SPAN_FEAT_L2:
232 33 : if (rxtx == VLIB_RX)
233 24 : next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
234 : L2INPUT_FEAT_SPAN);
235 : else
236 9 : next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
237 : L2OUTPUT_FEAT_SPAN);
238 33 : break;
239 3 : case SPAN_FEAT_DEVICE:
240 : default:
241 3 : vnet_feature_next (&next0, b0);
242 3 : break;
243 : }
244 :
245 : /* verify speculative enqueue, maybe switch current next frame */
246 36 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
247 : n_left_to_next, bi0, next0);
248 : }
249 :
250 24 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
251 : }
252 :
253 :
254 166 : for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
255 : {
256 142 : vlib_frame_t *f = mirror_frames[sw_if_index];
257 142 : if (f == 0)
258 118 : continue;
259 :
260 24 : if (sf == SPAN_FEAT_L2)
261 22 : vlib_put_frame_to_node (vm, l2output_node.index, f);
262 : else
263 2 : vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
264 24 : mirror_frames[sw_if_index] = 0;
265 : }
266 :
267 24 : return frame->n_vectors;
268 : }
269 :
270 2238 : VLIB_NODE_FN (span_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
271 : vlib_frame_t * frame)
272 : {
273 2 : return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
274 : }
275 :
276 2236 : VLIB_NODE_FN (span_output_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
277 : vlib_frame_t * frame)
278 : {
279 0 : return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
280 : }
281 :
282 2252 : VLIB_NODE_FN (span_l2_input_node) (vlib_main_t * vm,
283 : vlib_node_runtime_t * node,
284 : vlib_frame_t * frame)
285 : {
286 16 : return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
287 : }
288 :
289 2242 : VLIB_NODE_FN (span_l2_output_node) (vlib_main_t * vm,
290 : vlib_node_runtime_t * node,
291 : vlib_frame_t * frame)
292 : {
293 6 : return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
294 : }
295 :
296 : #define span_node_defs \
297 : .vector_size = sizeof (u32), \
298 : .format_trace = format_span_trace, \
299 : .type = VLIB_NODE_TYPE_INTERNAL, \
300 : .n_errors = ARRAY_LEN(span_error_strings), \
301 : .error_strings = span_error_strings, \
302 : .n_next_nodes = 0, \
303 : .next_nodes = { \
304 : [0] = "error-drop" \
305 : }
306 :
307 : /* *INDENT-OFF* */
308 178120 : VLIB_REGISTER_NODE (span_input_node) = {
309 : span_node_defs,
310 : .name = "span-input",
311 : };
312 :
313 178120 : VLIB_REGISTER_NODE (span_output_node) = {
314 : span_node_defs,
315 : .name = "span-output",
316 : };
317 :
318 178120 : VLIB_REGISTER_NODE (span_l2_input_node) = {
319 : span_node_defs,
320 : .name = "span-l2-input",
321 : };
322 :
323 178120 : VLIB_REGISTER_NODE (span_l2_output_node) = {
324 : span_node_defs,
325 : .name = "span-l2-output",
326 : };
327 :
328 : #ifndef CLIB_MARCH_VARIANT
329 559 : clib_error_t *span_init (vlib_main_t * vm)
330 : {
331 559 : span_main_t *sm = &span_main;
332 :
333 559 : sm->vlib_main = vm;
334 559 : sm->vnet_main = vnet_get_main ();
335 :
336 : /* Initialize the feature next-node indexes */
337 559 : feat_bitmap_init_next_nodes (vm,
338 : span_l2_input_node.index,
339 : L2INPUT_N_FEAT,
340 : l2input_get_feat_names (),
341 559 : sm->l2_input_next);
342 :
343 559 : feat_bitmap_init_next_nodes (vm,
344 : span_l2_output_node.index,
345 : L2OUTPUT_N_FEAT,
346 : l2output_get_feat_names (),
347 559 : sm->l2_output_next);
348 559 : return 0;
349 : }
350 :
351 72239 : VLIB_INIT_FUNCTION (span_init);
352 : /* *INDENT-ON* */
353 : #endif /* CLIB_MARCH_VARIANT */
354 :
355 : #undef span_node_defs
356 : /*
357 : * fd.io coding-style-patch-verification: ON
358 : *
359 : * Local Variables:
360 : * eval: (c-set-style "gnu")
361 : * End:
362 : */
|