FD.io VPP  v21.01.1
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
2  * node.c - skeleton vpp engine plug-in dual-loop node skeleton
3  *
4  * Copyright (c) <current-year> <your-organization>
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #include <vlib/vlib.h>
18 #include <vnet/vnet.h>
19 #include <vppinfra/error.h>
20 #include <nsim/nsim.h>
21 
22 typedef struct
23 {
26  int is_drop;
27  int is_lost;
28 } nsim_trace_t;
29 
30 #ifndef CLIB_MARCH_VARIANT
31 
32 /* packet trace format function */
33 static u8 *
34 format_nsim_trace (u8 * s, va_list * args)
35 {
36  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
37  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
38  nsim_trace_t *t = va_arg (*args, nsim_trace_t *);
39 
40  if (t->is_drop)
41  s = format (s, "NSIM: dropped, %s", t->is_lost ?
42  "simulated network loss" : "no space in ring");
43  else
44  s = format (s, "NSIM: tx time %.6f sw_if_index %d",
45  t->expires, t->tx_sw_if_index);
46 
47  return s;
48 }
49 
51 #endif /* CLIB_MARCH_VARIANT */
52 
53 #define foreach_nsim_error \
54 _(BUFFERED, "Packets buffered") \
55 _(DROPPED, "Packets dropped due to lack of space") \
56 _(LOSS, "Network loss simulation drop packets") \
57 _(REORDERED, "Packets reordered")
58 
59 typedef enum
60 {
61 #define _(sym,str) NSIM_ERROR_##sym,
63 #undef _
65 } nsim_error_t;
66 
67 #ifndef CLIB_MARCH_VARIANT
68 static char *nsim_error_strings[] = {
69 #define _(sym,string) string,
71 #undef _
72 };
73 #endif /* CLIB_MARCH_VARIANT */
74 
75 typedef enum
76 {
79 } nsim_next_t;
80 
81 static void
83  nsim_node_ctx_t * ctx, u32 n_actions)
84 {
85  int i;
86 
87  memset (ctx->action, 0, n_actions * sizeof (ctx->action[0]));
88 
89  if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
90  {
91  for (i = 0; i < n_actions; i++)
92  if (random_f64 (&nsm->seed) <= nsm->drop_fraction)
93  ctx->action[i] |= NSIM_ACTION_DROP;
94  }
95 
96  if (PREDICT_FALSE (nsm->reorder_fraction != 0.0))
97  {
98  for (i = 0; i < n_actions; i++)
99  if (random_f64 (&nsm->seed) <= nsm->reorder_fraction)
100  ctx->action[i] |= NSIM_ACTION_REORDER;
101  }
102 }
103 
104 static void
106  vlib_buffer_t * b, nsim_node_ctx_t * ctx, u32 is_drop)
107 {
108  if (b->flags & VLIB_BUFFER_IS_TRACED)
109  {
110  nsim_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
111  t->expires = ctx->expires;
112  t->is_drop = is_drop;
113  t->is_lost = ctx->action[0] & NSIM_ACTION_DROP;
114  t->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
115  }
116 }
117 
118 always_inline void
120  u32 * next, u8 is_cross_connect)
121 {
122  if (is_cross_connect)
123  {
124  vnet_buffer (b)->sw_if_index[VLIB_TX] =
125  (vnet_buffer (b)->sw_if_index[VLIB_RX] == nsm->sw_if_index0) ?
126  nsm->sw_if_index1 : nsm->sw_if_index0;
127  *next =
128  (vnet_buffer (b)->sw_if_index[VLIB_TX] == nsm->sw_if_index0) ?
130  }
131  else /* output feature, even easier... */
132  {
133  u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
135  }
136 }
137 
138 always_inline void
140  nsim_main_t * nsm, nsim_wheel_t * wp, vlib_buffer_t * b,
141  u32 bi, nsim_node_ctx_t * ctx, u8 is_cross_connect,
142  u8 is_trace)
143 {
144  if (PREDICT_TRUE (!(ctx->action[0] & NSIM_ACTION_DROP)))
145  {
146  if (PREDICT_FALSE (ctx->action[0] & NSIM_ACTION_REORDER))
147  {
148  u32 next;
149  ctx->reord[0] = bi;
151  &b->current_config_index, &next, 0);
152  ctx->reord_nexts[0] = next;
153  ctx->reord += 1;
154  ctx->reord_nexts += 1;
155  goto trace;
156  }
157 
158  nsim_wheel_entry_t *ep = wp->entries + wp->tail;
159  wp->tail++;
160  if (wp->tail == wp->wheel_size)
161  wp->tail = 0;
162  wp->cursize++;
163 
164  ep->tx_time = ctx->expires;
165  ep->rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
167  is_cross_connect);
168  ep->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
169  ep->buffer_index = bi;
170  ctx->n_buffered += 1;
171  }
172  else
173  {
174  ctx->n_loss += 1;
175  ctx->drop[0] = bi;
176  ctx->drop += 1;
177  }
178 
179 trace:
180 
181  if (PREDICT_FALSE (is_trace))
182  nsim_trace_buffer (vm, node, b, ctx, 0);
183 
184  ctx->action += 1;
185 }
186 
189  vlib_node_runtime_t * node, vlib_frame_t * frame, int is_trace,
190  int is_cross_connect)
191 {
192  nsim_main_t *nsm = &nsim_main;
193  u32 n_left_from, *from, drops[VLIB_FRAME_SIZE], reorders[VLIB_FRAME_SIZE];
194  nsim_wheel_t *wp = nsm->wheel_by_thread[vm->thread_index];
195  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
196  u16 reorders_nexts[VLIB_FRAME_SIZE];
199 
200  ASSERT (wp);
201 
202  from = vlib_frame_vector_args (frame);
203  n_left_from = frame->n_vectors;
204 
205  vlib_get_buffers (vm, from, bufs, n_left_from);
206  b = bufs;
207 
209  ctx.n_loss = 0;
210  ctx.n_buffered = 0;
211  ctx.drop = drops;
212  ctx.reord = reorders;
213  ctx.reord_nexts = reorders_nexts;
214  ctx.action = actions;
215  ctx.expires = vlib_time_now (vm) + nsm->delay;
216 
217  nsim_set_actions (nsm, b, &ctx, n_left_from);
218 
219  while (n_left_from >= 8)
220  {
221  vlib_prefetch_buffer_header (b[4], STORE);
222  vlib_prefetch_buffer_header (b[5], STORE);
223  vlib_prefetch_buffer_header (b[6], STORE);
224  vlib_prefetch_buffer_header (b[7], STORE);
225 
226  if (PREDICT_FALSE (wp->cursize + 4 >= wp->wheel_size))
227  goto slow_path;
228 
229  nsim_dispatch_buffer (vm, node, nsm, wp, b[0], from[0], &ctx,
230  is_cross_connect, is_trace);
231  nsim_dispatch_buffer (vm, node, nsm, wp, b[1], from[1], &ctx,
232  is_cross_connect, is_trace);
233  nsim_dispatch_buffer (vm, node, nsm, wp, b[2], from[2], &ctx,
234  is_cross_connect, is_trace);
235  nsim_dispatch_buffer (vm, node, nsm, wp, b[3], from[3], &ctx,
236  is_cross_connect, is_trace);
237 
238  b += 4;
239  from += 4;
240  n_left_from -= 4;
241  }
242 
243 slow_path:
244 
245  while (n_left_from > 0)
246  {
247  /* Drop if out of wheel space and not drop or reorder */
248  if (PREDICT_TRUE (wp->cursize < wp->wheel_size
249  || (ctx.action[0] & NSIM_ACTION_DROP)
250  || (ctx.action[0] & NSIM_ACTION_REORDER)))
251  {
252  nsim_dispatch_buffer (vm, node, nsm, wp, b[0], from[0], &ctx,
253  is_cross_connect, is_trace);
254  }
255  else
256  {
257  ctx.drop[0] = from[0];
258  ctx.drop += 1;
259  if (PREDICT_FALSE (is_trace))
260  nsim_trace_buffer (vm, node, b[0], &ctx, 1);
261  ctx.action += 1;
262  }
263 
264  b += 1;
265  from += 1;
266  n_left_from -= 1;
267  }
268 
269  if (PREDICT_FALSE (ctx.drop > drops))
270  {
271  u32 n_left_to_drop = ctx.drop - drops;
272  vlib_buffer_free (vm, drops, n_left_to_drop);
273  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_LOSS,
274  ctx.n_loss);
275  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_DROPPED,
276  n_left_to_drop - ctx.n_loss);
277  }
278  if (PREDICT_FALSE (ctx.reord > reorders))
279  {
280  u32 n_reordered = ctx.reord - reorders;
281  vlib_buffer_enqueue_to_next (vm, node, reorders, reorders_nexts,
282  n_reordered);
283  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_REORDERED,
284  n_reordered);
285  }
287  NSIM_ERROR_BUFFERED, ctx.n_buffered);
288  return frame->n_vectors;
289 }
290 
293 {
294  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
295  return nsim_inline (vm, node, frame,
296  1 /* is_trace */ , 1 /* is_cross_connect */ );
297  else
298  return nsim_inline (vm, node, frame,
299  0 /* is_trace */ , 1 /* is_cross_connect */ );
300 }
301 
302 /* *INDENT-OFF* */
303 #ifndef CLIB_MARCH_VARIANT
305 {
306  .name = "nsim",
307  .vector_size = sizeof (u32),
308  .format_trace = format_nsim_trace,
310 
311  .n_errors = ARRAY_LEN(nsim_error_strings),
312  .error_strings = nsim_error_strings,
313 
314  .n_next_nodes = NSIM_N_NEXT,
315 
316  /* edit / add dispositions here */
317  .next_nodes = {
318  [NSIM_NEXT_DROP] = "error-drop",
319  },
320 };
321 #endif /* CLIB_MARCH_VARIANT */
322 /* *INDENT-ON* */
323 
327 {
328  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
329  return nsim_inline (vm, node, frame,
330  1 /* is_trace */ , 0 /* is_cross_connect */ );
331  else
332  return nsim_inline (vm, node, frame,
333  0 /* is_trace */ , 0 /* is_cross_connect */ );
334 }
335 
336 /* *INDENT-OFF* */
337 #ifndef CLIB_MARCH_VARIANT
339 {
340  .name = "nsim-output-feature",
341  .vector_size = sizeof (u32),
342  .format_trace = format_nsim_trace,
344 
345  .n_errors = ARRAY_LEN(nsim_error_strings),
346  .error_strings = nsim_error_strings,
347 
348  .n_next_nodes = NSIM_N_NEXT,
349 
350  /* edit / add dispositions here */
351  .next_nodes = {
352  [NSIM_NEXT_DROP] = "error-drop",
353  },
354 };
355 #endif /* CLIB_MARCH_VARIANT */
356 /* *INDENT-ON* */
357 
358 /*
359  * fd.io coding-style-patch-verification: ON
360  *
361  * Local Variables:
362  * eval: (c-set-style "gnu")
363  * End:
364  */
vnet_config_main_t config_main
Definition: feature.h:82
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:124
f64 expires
Definition: nsim.h:53
u32 * output_next_index_by_sw_if_index
Definition: nsim.h:93
static char * nsim_error_strings[]
Definition: node.c:68
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:899
#define CLIB_UNUSED(x)
Definition: clib.h:87
u32 * drop
Definition: nsim.h:54
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:937
nsim_error_t
Definition: node.c:59
#define PREDICT_TRUE(x)
Definition: clib.h:122
Definition: nsim.h:30
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
vlib_node_registration_t nsim_node
(constructor) VLIB_REGISTER_NODE (nsim_node)
Definition: node.c:50
u32 thread_index
Definition: main.h:250
vlib_main_t * vm
Definition: in2out_ed.c:1580
#define VLIB_NODE_FN(node)
Definition: node.h:203
vnet_feature_config_main_t * fcm
Definition: nsim.h:52
u32 output_next_index0
Definition: nsim.h:90
vlib_node_registration_t nsim_feature_node
(constructor) VLIB_REGISTER_NODE (nsim_feature_node)
Definition: node.c:338
unsigned char u8
Definition: types.h:56
#define foreach_nsim_error
Definition: node.c:53
u32 tx_sw_if_index
Definition: node.c:25
double f64
Definition: types.h:142
u32 tx_sw_if_index
Definition: nsim.h:34
u32 cursize
Definition: nsim.h:43
static u32 slow_path(dslite_main_t *dm, dslite_session_key_t *in2out_key, dslite_session_t **sp, u32 next, u8 *error, u32 thread_index)
Definition: dslite_in2out.c:34
u64 n_loss
Definition: nsim.h:59
description fragment has unexpected format
Definition: map.api:433
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:207
const cJSON *const b
Definition: cJSON.h:255
unsigned int u32
Definition: types.h:88
u16 * reord_nexts
Definition: nsim.h:56
f64 expires
Definition: node.c:24
#define VLIB_FRAME_SIZE
Definition: node.h:378
int is_drop
Definition: node.c:26
vl_api_fib_path_type_t type
Definition: fib_types.api:123
u32 * reord
Definition: nsim.h:55
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
static void * vnet_get_config_data(vnet_config_main_t *cm, u32 *config_index, u32 *next_index, u32 n_data_bytes)
Definition: config.h:123
nsim_next_t
Definition: node.c:75
u8 * action
Definition: nsim.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:121
#define always_inline
Definition: ipsec.h:28
u32 tail
Definition: nsim.h:45
u32 node_index
Node index.
Definition: node.h:488
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
u32 sw_if_index1
Definition: nsim.h:89
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
u16 n_vectors
Definition: node.h:397
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
nsim_wheel_entry_t * entries
Definition: nsim.h:46
u32 current_config_index
Used by feature subgraph arcs to visit enabled feature nodes.
Definition: buffer.h:147
#define ARRAY_LEN(x)
Definition: clib.h:67
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
f64 reorder_fraction
Definition: nsim.h:106
#define ASSERT(truth)
static uword nsim_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_trace, int is_cross_connect)
Definition: node.c:188
nsim_wheel_t ** wheel_by_thread
Definition: nsim.h:99
static u8 * format_nsim_trace(u8 *s, va_list *args)
Definition: node.c:34
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
u16 arc_index
Definition: nsim.h:86
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
u32 seed
Definition: nsim.h:96
u32 sw_if_index0
Definition: nsim.h:89
static void nsim_set_actions(nsim_main_t *nsm, vlib_buffer_t **b, nsim_node_ctx_t *ctx, u32 n_actions)
Definition: node.c:82
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
f64 tx_time
Definition: nsim.h:32
vl_api_flow_action_t actions
Definition: flow_types.api:224
u32 buffer_index
Definition: nsim.h:36
VLIB buffer representation.
Definition: buffer.h:102
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:297
int is_lost
Definition: node.c:27
u64 n_buffered
Definition: nsim.h:58
f64 delay
Definition: nsim.h:102
#define vnet_buffer(b)
Definition: buffer.h:417
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
static void nsim_trace_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, nsim_node_ctx_t *ctx, u32 is_drop)
Definition: node.c:105
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
u32 output_next_index
Definition: nsim.h:35
f64 drop_fraction
Definition: nsim.h:105
static void nsim_dispatch_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, nsim_main_t *nsm, nsim_wheel_t *wp, vlib_buffer_t *b, u32 bi, nsim_node_ctx_t *ctx, u8 is_cross_connect, u8 is_trace)
Definition: node.c:139
static void nsim_buffer_fwd_lookup(nsim_main_t *nsm, vlib_buffer_t *b, u32 *next, u8 is_cross_connect)
Definition: node.c:119
u32 wheel_size
Definition: nsim.h:42
static_always_inline vnet_feature_config_main_t * vnet_feature_get_config_main(u16 arc)
Definition: feature.h:244
u32 output_next_index1
Definition: nsim.h:90
nsim_main_t nsim_main
Definition: nsim.c:39
u32 rx_sw_if_index
Definition: nsim.h:33
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
Definition: defs.h:46