FD.io VPP  v20.09-64-g4f7b92f0a
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 <vnet/pg/pg.h>
20 #include <vppinfra/error.h>
21 #include <nsim/nsim.h>
22 
23 typedef struct
24 {
27  int is_drop;
28  int is_lost;
29 } nsim_trace_t;
30 
31 #ifndef CLIB_MARCH_VARIANT
32 
33 /* packet trace format function */
34 static u8 *
35 format_nsim_trace (u8 * s, va_list * args)
36 {
37  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
38  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
39  nsim_trace_t *t = va_arg (*args, nsim_trace_t *);
40 
41  if (t->is_drop)
42  s = format (s, "NSIM: dropped, %s", t->is_lost ?
43  "simulated network loss" : "no space in ring");
44  else
45  s = format (s, "NSIM: tx time %.6f sw_if_index %d",
46  t->expires, t->tx_sw_if_index);
47 
48  return s;
49 }
50 
52 #endif /* CLIB_MARCH_VARIANT */
53 
54 #define foreach_nsim_error \
55 _(BUFFERED, "Packets buffered") \
56 _(DROPPED, "Packets dropped due to lack of space") \
57 _(LOSS, "Network loss simulation drop packets") \
58 _(REORDERED, "Packets reordered")
59 
60 typedef enum
61 {
62 #define _(sym,str) NSIM_ERROR_##sym,
64 #undef _
66 } nsim_error_t;
67 
68 #ifndef CLIB_MARCH_VARIANT
69 static char *nsim_error_strings[] = {
70 #define _(sym,string) string,
72 #undef _
73 };
74 #endif /* CLIB_MARCH_VARIANT */
75 
76 typedef enum
77 {
80 } nsim_next_t;
81 
82 static void
84  nsim_node_ctx_t * ctx, u32 n_actions)
85 {
86  int i;
87 
88  memset (ctx->action, 0, n_actions * sizeof (ctx->action[0]));
89 
90  if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
91  {
92  for (i = 0; i < n_actions; i++)
93  if (random_f64 (&nsm->seed) <= nsm->drop_fraction)
94  ctx->action[i] |= NSIM_ACTION_DROP;
95  }
96 
97  if (PREDICT_FALSE (nsm->reorder_fraction != 0.0))
98  {
99  for (i = 0; i < n_actions; i++)
100  if (random_f64 (&nsm->seed) <= nsm->reorder_fraction)
101  ctx->action[i] |= NSIM_ACTION_REORDER;
102  }
103 }
104 
105 static void
107  vlib_buffer_t * b, nsim_node_ctx_t * ctx, u32 is_drop)
108 {
109  if (b->flags & VLIB_BUFFER_IS_TRACED)
110  {
111  nsim_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
112  t->expires = ctx->expires;
113  t->is_drop = is_drop;
114  t->is_lost = ctx->action[0] & NSIM_ACTION_DROP;
115  t->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
116  }
117 }
118 
119 always_inline void
121  u32 * next, u8 is_cross_connect)
122 {
123  if (is_cross_connect)
124  {
125  vnet_buffer (b)->sw_if_index[VLIB_TX] =
126  (vnet_buffer (b)->sw_if_index[VLIB_RX] == nsm->sw_if_index0) ?
127  nsm->sw_if_index1 : nsm->sw_if_index0;
128  *next =
129  (vnet_buffer (b)->sw_if_index[VLIB_TX] == nsm->sw_if_index0) ?
131  }
132  else /* output feature, even easier... */
133  {
134  u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
136  }
137 }
138 
139 always_inline void
141  nsim_main_t * nsm, nsim_wheel_t * wp, vlib_buffer_t * b,
142  u32 bi, nsim_node_ctx_t * ctx, u8 is_cross_connect,
143  u8 is_trace)
144 {
145  if (PREDICT_TRUE (!(ctx->action[0] & NSIM_ACTION_DROP)))
146  {
147  if (PREDICT_FALSE (ctx->action[0] & NSIM_ACTION_REORDER))
148  {
149  u32 next;
150  ctx->reord[0] = bi;
152  &b->current_config_index, &next, 0);
153  ctx->reord_nexts[0] = next;
154  ctx->reord += 1;
155  ctx->reord_nexts += 1;
156  goto trace;
157  }
158 
159  nsim_wheel_entry_t *ep = wp->entries + wp->tail;
160  wp->tail++;
161  if (wp->tail == wp->wheel_size)
162  wp->tail = 0;
163  wp->cursize++;
164 
165  ep->tx_time = ctx->expires;
166  ep->rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
168  is_cross_connect);
169  ep->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
170  ep->buffer_index = bi;
171  ctx->n_buffered += 1;
172  }
173  else
174  {
175  ctx->n_loss += 1;
176  ctx->drop[0] = bi;
177  ctx->drop += 1;
178  }
179 
180 trace:
181 
182  if (PREDICT_FALSE (is_trace))
183  nsim_trace_buffer (vm, node, b, ctx, 0);
184 
185  ctx->action += 1;
186 }
187 
190  vlib_node_runtime_t * node, vlib_frame_t * frame, int is_trace,
191  int is_cross_connect)
192 {
193  nsim_main_t *nsm = &nsim_main;
194  u32 n_left_from, *from, drops[VLIB_FRAME_SIZE], reorders[VLIB_FRAME_SIZE];
195  nsim_wheel_t *wp = nsm->wheel_by_thread[vm->thread_index];
196  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
197  u16 reorders_nexts[VLIB_FRAME_SIZE];
200 
201  ASSERT (wp);
202 
203  from = vlib_frame_vector_args (frame);
204  n_left_from = frame->n_vectors;
205 
206  vlib_get_buffers (vm, from, bufs, n_left_from);
207  b = bufs;
208 
210  ctx.n_loss = 0;
211  ctx.n_buffered = 0;
212  ctx.drop = drops;
213  ctx.reord = reorders;
214  ctx.reord_nexts = reorders_nexts;
215  ctx.action = actions;
216  ctx.expires = vlib_time_now (vm) + nsm->delay;
217 
218  nsim_set_actions (nsm, b, &ctx, n_left_from);
219 
220  while (n_left_from >= 8)
221  {
222  vlib_prefetch_buffer_header (b[4], STORE);
223  vlib_prefetch_buffer_header (b[5], STORE);
224  vlib_prefetch_buffer_header (b[6], STORE);
225  vlib_prefetch_buffer_header (b[7], STORE);
226 
227  if (PREDICT_FALSE (wp->cursize + 4 >= wp->wheel_size))
228  goto slow_path;
229 
230  nsim_dispatch_buffer (vm, node, nsm, wp, b[0], from[0], &ctx,
231  is_cross_connect, is_trace);
232  nsim_dispatch_buffer (vm, node, nsm, wp, b[1], from[1], &ctx,
233  is_cross_connect, is_trace);
234  nsim_dispatch_buffer (vm, node, nsm, wp, b[2], from[2], &ctx,
235  is_cross_connect, is_trace);
236  nsim_dispatch_buffer (vm, node, nsm, wp, b[3], from[3], &ctx,
237  is_cross_connect, is_trace);
238 
239  b += 4;
240  from += 4;
241  n_left_from -= 4;
242  }
243 
244 slow_path:
245 
246  while (n_left_from > 0)
247  {
248  /* Drop if out of wheel space and not drop or reorder */
249  if (PREDICT_TRUE (wp->cursize < wp->wheel_size
250  || (ctx.action[0] & NSIM_ACTION_DROP)
251  || (ctx.action[0] & NSIM_ACTION_REORDER)))
252  {
253  nsim_dispatch_buffer (vm, node, nsm, wp, b[0], from[0], &ctx,
254  is_cross_connect, is_trace);
255  }
256  else
257  {
258  ctx.drop[0] = from[0];
259  ctx.drop += 1;
260  if (PREDICT_FALSE (is_trace))
261  nsim_trace_buffer (vm, node, b[0], &ctx, 1);
262  ctx.action += 1;
263  }
264 
265  b += 1;
266  from += 1;
267  n_left_from -= 1;
268  }
269 
270  if (PREDICT_FALSE (ctx.drop > drops))
271  {
272  u32 n_left_to_drop = ctx.drop - drops;
273  vlib_buffer_free (vm, drops, n_left_to_drop);
274  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_LOSS,
275  ctx.n_loss);
276  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_DROPPED,
277  n_left_to_drop - ctx.n_loss);
278  }
279  if (PREDICT_FALSE (ctx.reord > reorders))
280  {
281  u32 n_reordered = ctx.reord - reorders;
282  vlib_buffer_enqueue_to_next (vm, node, reorders, reorders_nexts,
283  n_reordered);
284  vlib_node_increment_counter (vm, node->node_index, NSIM_ERROR_REORDERED,
285  n_reordered);
286  }
288  NSIM_ERROR_BUFFERED, ctx.n_buffered);
289  return frame->n_vectors;
290 }
291 
294 {
295  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
296  return nsim_inline (vm, node, frame,
297  1 /* is_trace */ , 1 /* is_cross_connect */ );
298  else
299  return nsim_inline (vm, node, frame,
300  0 /* is_trace */ , 1 /* is_cross_connect */ );
301 }
302 
303 /* *INDENT-OFF* */
304 #ifndef CLIB_MARCH_VARIANT
306 {
307  .name = "nsim",
308  .vector_size = sizeof (u32),
309  .format_trace = format_nsim_trace,
311 
312  .n_errors = ARRAY_LEN(nsim_error_strings),
313  .error_strings = nsim_error_strings,
314 
315  .n_next_nodes = NSIM_N_NEXT,
316 
317  /* edit / add dispositions here */
318  .next_nodes = {
319  [NSIM_NEXT_DROP] = "error-drop",
320  },
321 };
322 #endif /* CLIB_MARCH_VARIANT */
323 /* *INDENT-ON* */
324 
328 {
329  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
330  return nsim_inline (vm, node, frame,
331  1 /* is_trace */ , 0 /* is_cross_connect */ );
332  else
333  return nsim_inline (vm, node, frame,
334  0 /* is_trace */ , 0 /* is_cross_connect */ );
335 }
336 
337 /* *INDENT-OFF* */
338 #ifndef CLIB_MARCH_VARIANT
340 {
341  .name = "nsim-output-feature",
342  .vector_size = sizeof (u32),
343  .format_trace = format_nsim_trace,
345 
346  .n_errors = ARRAY_LEN(nsim_error_strings),
347  .error_strings = nsim_error_strings,
348 
349  .n_next_nodes = NSIM_N_NEXT,
350 
351  /* edit / add dispositions here */
352  .next_nodes = {
353  [NSIM_NEXT_DROP] = "error-drop",
354  },
355 };
356 #endif /* CLIB_MARCH_VARIANT */
357 /* *INDENT-ON* */
358 
359 /*
360  * fd.io coding-style-patch-verification: ON
361  *
362  * Local Variables:
363  * eval: (c-set-style "gnu")
364  * End:
365  */
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:69
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:60
#define PREDICT_TRUE(x)
Definition: clib.h:121
Definition: nsim.h:30
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:333
vlib_node_registration_t nsim_node
(constructor) VLIB_REGISTER_NODE (nsim_node)
Definition: node.c:51
u32 thread_index
Definition: main.h:249
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
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:339
unsigned char u8
Definition: types.h:56
#define foreach_nsim_error
Definition: node.c:54
u32 tx_sw_if_index
Definition: node.c:26
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
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
unsigned int u32
Definition: types.h:88
u16 * reord_nexts
Definition: nsim.h:56
f64 expires
Definition: node.c:25
#define VLIB_FRAME_SIZE
Definition: node.h:377
int is_drop
Definition: node.c:27
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:76
u8 * action
Definition: nsim.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:120
#define always_inline
Definition: ipsec.h:28
u32 tail
Definition: nsim.h:45
u32 node_index
Node index.
Definition: node.h:487
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:169
u16 n_vectors
Definition: node.h:396
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:1582
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:189
nsim_wheel_t ** wheel_by_thread
Definition: nsim.h:99
static u8 * format_nsim_trace(u8 *s, va_list *args)
Definition: node.c:35
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:83
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
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:28
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:577
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:106
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:301
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:140
static void nsim_buffer_fwd_lookup(nsim_main_t *nsm, vlib_buffer_t *b, u32 *next, u8 is_cross_connect)
Definition: node.c:120
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:33
Definition: defs.h:46