FD.io VPP  v19.01.3-6-g70449b9b9
Vector Packet Processing
node.c
Go to the documentation of this file.
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 
29 
30 /* packet trace format function */
31 u8 *
32 format_span_trace (u8 * s, va_list * args)
33 {
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 *);
37 
38  vnet_main_t *vnm = vnet_get_main ();
39  s = format (s, "SPAN: mirrored %U -> %U",
42 
43  return s;
44 }
45 
46 #define foreach_span_error \
47 _(HITS, "SPAN incoming packets processed")
48 
49 typedef enum
50 {
51 #define _(sym,str) SPAN_ERROR_##sym,
53 #undef _
55 } span_error_t;
56 
57 static char *span_error_strings[] = {
58 #define _(sym,string) string,
60 #undef _
61 };
62 
65  vlib_buffer_t * b0, vlib_frame_t ** mirror_frames,
67 {
68  vlib_buffer_t *c0;
69  span_main_t *sm = &span_main;
70  vnet_main_t *vnm = vnet_get_main ();
71  u32 *to_mirror_next = 0;
72  u32 i;
73  span_interface_t *si0;
74  span_mirror_t *sm0;
75 
76  if (sw_if_index0 >= vec_len (sm->interfaces))
77  return;
78 
79  si0 = vec_elt_at_index (sm->interfaces, sw_if_index0);
80  sm0 = &si0->mirror_rxtx[sf][rxtx];
81 
82  if (sm0->num_mirror_ports == 0)
83  return;
84 
85  /* Don't do it again */
86  if (PREDICT_FALSE (b0->flags & VNET_BUFFER_F_SPAN_CLONE))
87  return;
88 
89  /* *INDENT-OFF* */
91  {
92  if (mirror_frames[i] == 0)
93  {
94  if (sf == SPAN_FEAT_L2)
95  mirror_frames[i] = vlib_get_frame_to_node (vm, l2output_node.index);
96  else
97  mirror_frames[i] = vnet_get_frame_to_sw_interface (vnm, i);
98  }
99  to_mirror_next = vlib_frame_vector_args (mirror_frames[i]);
100  to_mirror_next += mirror_frames[i]->n_vectors;
101  /* This can fail */
102  c0 = vlib_buffer_copy (vm, b0);
103  if (PREDICT_TRUE(c0 != 0))
104  {
105  vnet_buffer (c0)->sw_if_index[VLIB_TX] = i;
106  c0->flags |= VNET_BUFFER_F_SPAN_CLONE;
107  if (sf == SPAN_FEAT_L2)
108  vnet_buffer (c0)->l2.feature_bitmap = L2OUTPUT_FEAT_OUTPUT;
109  to_mirror_next[0] = vlib_get_buffer_index (vm, c0);
110  mirror_frames[i]->n_vectors++;
111  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
112  {
113  span_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
114  t->src_sw_if_index = sw_if_index0;
115  t->mirror_sw_if_index = i;
116 #if 0
117  /* Enable this path to allow packet trace of SPAN packets.
118  Note that all SPAN packets will show up on the trace output
119  with the first SPAN packet (since they are in the same frame)
120  thus making trace output of the original packet confusing */
121  mirror_frames[i]->flags |= VLIB_FRAME_TRACE;
122  c0->flags |= VLIB_BUFFER_IS_TRACED;
123 #endif
124  }
125  }
126  }));
127  /* *INDENT-ON* */
128 }
129 
132  vlib_frame_t * frame, vlib_rx_or_tx_t rxtx,
133  span_feat_t sf)
134 {
135  span_main_t *sm = &span_main;
136  vnet_main_t *vnm = vnet_get_main ();
137  u32 n_left_from, *from, *to_next;
138  u32 n_span_packets = 0;
139  u32 next_index;
141  static __thread vlib_frame_t **mirror_frames = 0;
142 
143  from = vlib_frame_vector_args (frame);
144  n_left_from = frame->n_vectors;
145  next_index = node->cached_next_index;
146 
147  vec_validate_aligned (mirror_frames, sm->max_sw_if_index,
149 
150  while (n_left_from > 0)
151  {
152  u32 n_left_to_next;
153 
154  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
155 
156  while (n_left_from >= 4 && n_left_to_next >= 2)
157  {
158  u32 bi0;
159  u32 bi1;
160  vlib_buffer_t *b0;
161  vlib_buffer_t *b1;
162  u32 sw_if_index0;
163  u32 next0 = 0;
164  u32 sw_if_index1;
165  u32 next1 = 0;
166 
167  /* speculatively enqueue b0, b1 to the current next frame */
168  to_next[0] = bi0 = from[0];
169  to_next[1] = bi1 = from[1];
170  to_next += 2;
171  n_left_to_next -= 2;
172  from += 2;
173  n_left_from -= 2;
174 
175  b0 = vlib_get_buffer (vm, bi0);
176  b1 = vlib_get_buffer (vm, bi1);
177  sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
178  sw_if_index1 = vnet_buffer (b1)->sw_if_index[rxtx];
179 
180  span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
181  span_mirror (vm, node, sw_if_index1, b1, mirror_frames, rxtx, sf);
182 
183  switch (sf)
184  {
185  case SPAN_FEAT_L2:
186  if (rxtx == VLIB_RX)
187  {
188  next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
189  L2INPUT_FEAT_SPAN);
190  next1 = vnet_l2_feature_next (b1, sm->l2_input_next,
191  L2INPUT_FEAT_SPAN);
192  }
193  else
194  {
195  next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
196  L2OUTPUT_FEAT_SPAN);
197  next1 = vnet_l2_feature_next (b1, sm->l2_output_next,
198  L2OUTPUT_FEAT_SPAN);
199  }
200  break;
201  case SPAN_FEAT_DEVICE:
202  default:
203  vnet_feature_next (&next0, b0);
204  vnet_feature_next (&next1, b1);
205  break;
206  }
207 
208  /* verify speculative enqueue, maybe switch current next frame */
209  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
210  to_next, n_left_to_next,
211  bi0, bi1, next0, next1);
212  }
213  while (n_left_from > 0 && n_left_to_next > 0)
214  {
215  u32 bi0;
216  vlib_buffer_t *b0;
217  u32 sw_if_index0;
218  u32 next0 = 0;
219 
220  /* speculatively enqueue b0 to the current next frame */
221  to_next[0] = bi0 = from[0];
222  to_next += 1;
223  n_left_to_next -= 1;
224  from += 1;
225  n_left_from -= 1;
226 
227  b0 = vlib_get_buffer (vm, bi0);
228  sw_if_index0 = vnet_buffer (b0)->sw_if_index[rxtx];
229 
230  span_mirror (vm, node, sw_if_index0, b0, mirror_frames, rxtx, sf);
231 
232  switch (sf)
233  {
234  case SPAN_FEAT_L2:
235  if (rxtx == VLIB_RX)
236  next0 = vnet_l2_feature_next (b0, sm->l2_input_next,
237  L2INPUT_FEAT_SPAN);
238  else
239  next0 = vnet_l2_feature_next (b0, sm->l2_output_next,
240  L2OUTPUT_FEAT_SPAN);
241  break;
242  case SPAN_FEAT_DEVICE:
243  default:
244  vnet_feature_next (&next0, b0);
245  break;
246  }
247 
248  /* verify speculative enqueue, maybe switch current next frame */
249  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
250  n_left_to_next, bi0, next0);
251  }
252 
253  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
254  }
255 
256 
257  for (sw_if_index = 0; sw_if_index < vec_len (mirror_frames); sw_if_index++)
258  {
259  vlib_frame_t *f = mirror_frames[sw_if_index];
260  if (f == 0)
261  continue;
262 
263  if (sf == SPAN_FEAT_L2)
264  vlib_put_frame_to_node (vm, l2output_node.index, f);
265  else
266  vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
267  mirror_frames[sw_if_index] = 0;
268  }
269  vlib_node_increment_counter (vm, span_node.index, SPAN_ERROR_HITS,
270  n_span_packets);
271 
272  return frame->n_vectors;
273 }
274 
275 static uword
277  vlib_frame_t * frame)
278 {
279  return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_DEVICE);
280 }
281 
282 static uword
284  vlib_frame_t * frame)
285 {
286  return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_DEVICE);
287 }
288 
289 static uword
291  vlib_frame_t * frame)
292 {
293  return span_node_inline_fn (vm, node, frame, VLIB_RX, SPAN_FEAT_L2);
294 }
295 
296 static uword
298  vlib_frame_t * frame)
299 {
300  return span_node_inline_fn (vm, node, frame, VLIB_TX, SPAN_FEAT_L2);
301 }
302 
303 #define span_node_defs \
304  .vector_size = sizeof (u32), \
305  .format_trace = format_span_trace, \
306  .type = VLIB_NODE_TYPE_INTERNAL, \
307  .n_errors = ARRAY_LEN(span_error_strings), \
308  .error_strings = span_error_strings, \
309  .n_next_nodes = 0, \
310  .next_nodes = { \
311  [0] = "error-drop" \
312  }
313 
314 /* *INDENT-OFF* */
317  .function = span_device_input_node_fn,
318  .name = "span-input",
319 };
320 
322 
325  .function = span_device_output_node_fn,
326  .name = "span-output",
327 };
328 
330 
333  .function = span_l2_input_node_fn,
334  .name = "span-l2-input",
335 };
336 
338 
341  .function = span_l2_output_node_fn,
342  .name = "span-l2-output",
343 };
344 
346 
348 {
349  span_main_t *sm = &span_main;
350 
351  sm->vlib_main = vm;
352  sm->vnet_main = vnet_get_main ();
353 
354  /* Initialize the feature next-node indexes */
356  span_l2_input_node.index,
359  sm->l2_input_next);
360 
362  span_l2_output_node.index,
365  sm->l2_output_next);
366  return 0;
367 }
368 
370 /* *INDENT-ON* */
371 
372 #undef span_node_defs
373 /*
374  * fd.io coding-style-patch-verification: ON
375  *
376  * Local Variables:
377  * eval: (c-set-style "gnu")
378  * End:
379  */
span_main_t span_main
Definition: span.c:24
#define CLIB_UNUSED(x)
Definition: clib.h:82
char ** l2output_get_feat_names(void)
Definition: l2_output.c:39
span_mirror_t mirror_rxtx[SPAN_FEAT_N][VLIB_N_RX_TX]
Definition: span.h:38
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
vlib_node_registration_t l2output_node
(constructor) VLIB_REGISTER_NODE (l2output_node)
Definition: l2_output.c:447
vlib_main_t * vlib_main
Definition: span.h:54
#define PREDICT_TRUE(x)
Definition: clib.h:112
static char * span_error_strings[]
Definition: node.c:57
u32 num_mirror_ports
Definition: span.h:33
u32 mirror_sw_if_index
Definition: span.h:63
span_error_t
Definition: node.c:49
int i
static uword span_l2_output_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:297
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 l2_output_next[32]
Definition: span.h:45
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:450
vlib_node_registration_t span_l2_output_node
(constructor) VLIB_REGISTER_NODE (span_l2_output_node)
Definition: node.c:339
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:685
static u32 vnet_l2_feature_next(vlib_buffer_t *b, u32 *next_nodes, u32 feat_bit)
Return the graph node index for the feature corresponding to the next set bit after clearing the curr...
Definition: feat_bitmap.h:94
vlib_node_registration_t span_input_node
(constructor) VLIB_REGISTER_NODE (span_input_node)
Definition: node.c:315
vlib_rx_or_tx_t
Definition: defs.h:44
clib_bitmap_t * mirror_ports
Definition: span.h:32
vlib_node_registration_t span_l2_input_node
(constructor) VLIB_REGISTER_NODE (span_l2_input_node)
Definition: node.c:331
#define static_always_inline
Definition: clib.h:99
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
static_always_inline uword span_node_inline_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, vlib_rx_or_tx_t rxtx, span_feat_t sf)
Definition: node.c:131
u32 sw_if_index
Definition: vxlan_gbp.api:37
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
unsigned int u32
Definition: types.h:88
clib_error_t * span_init(vlib_main_t *vm)
Definition: node.c:347
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:158
static uword span_device_input_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:276
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:223
static uword span_device_output_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:283
u8 * format_span_trace(u8 *s, va_list *args)
Definition: node.c:32
#define clib_bitmap_foreach(i, ai, body)
Macro to iterate across set bits in a bitmap.
Definition: bitmap.h:361
vlib_node_registration_t span_output_node
(constructor) VLIB_REGISTER_NODE (span_output_node)
Definition: node.c:323
span_interface_t * interfaces
Definition: span.h:48
vnet_main_t * vnet_main
Definition: span.h:55
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:190
#define PREDICT_FALSE(x)
Definition: clib.h:111
vlib_node_registration_t span_node
Definition: node.c:28
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:420
static void vnet_put_frame_to_sw_interface(vnet_main_t *vnm, u32 sw_if_index, vlib_frame_t *f)
vlib_main_t * vm
Definition: buffer.c:301
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:295
static void feat_bitmap_init_next_nodes(vlib_main_t *vm, u32 node_index, u32 num_features, char **feat_names, u32 *next_nodes)
Initialize the feature next-node indexes of a graph node.
Definition: feat_bitmap.h:43
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:452
char ** l2input_get_feat_names(void)
Return an array of strings containing graph node names of each feature.
Definition: l2_input.c:60
u32 l2_input_next[32]
Definition: span.h:44
#define span_node_defs
Definition: node.c:303
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:537
u16 flags
Definition: node.h:411
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, vlib_rx_or_tx_t rxtx, span_feat_t sf)
Definition: node.c:64
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
u32 src_sw_if_index
Definition: span.h:62
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
static uword span_l2_input_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: node.c:290
#define VLIB_FRAME_TRACE
Definition: node.h:458
span_feat_t
Definition: span.h:23
#define vnet_buffer(b)
Definition: buffer.h:368
#define foreach_span_error
Definition: node.c:46
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:117
u32 max_sw_if_index
Definition: span.h:51
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
Definition: defs.h:46