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