FD.io VPP  v21.10.1-2-g0a485f517
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;
150  vnet_get_config_data (&ctx->fcm->config_main,
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];
196  u16 reorders_nexts[VLIB_FRAME_SIZE];
199 
200  ASSERT (wp);
201 
203  n_left_from = frame->n_vectors;
204 
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  }
286  vlib_node_increment_counter (vm, node->node_index,
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  */
vlib.h
nsim_wheel_entry_t::tx_sw_if_index
u32 tx_sw_if_index
Definition: nsim.h:34
vlib_buffer_free
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:979
nsim_wheel_t::tail
u32 tail
Definition: nsim.h:45
trace
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:870
nsim_main_t::delay
f64 delay
Definition: nsim.h:102
nsim_main_t::seed
u32 seed
Definition: nsim.h:96
bufs
vlib_buffer_t * bufs[VLIB_FRAME_SIZE]
Definition: nat44_ei_out2in.c:717
nsim_set_actions
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_prefetch_buffer_header
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:231
frame
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: nat44_ei.c:3048
nsim_main_t::drop_fraction
f64 drop_fraction
Definition: nsim.h:105
nsim_wheel_entry_t::rx_sw_if_index
u32 rx_sw_if_index
Definition: nsim.h:33
nsim_next_t
nsim_next_t
Definition: node.c:75
nsim_trace_t::is_drop
int is_drop
Definition: node.c:26
vlib_get_buffers
vlib_get_buffers(vm, from, b, n_left_from)
next
u16 * next
Definition: nat44_ei_out2in.c:718
VLIB_NODE_TYPE_INTERNAL
@ VLIB_NODE_TYPE_INTERNAL
Definition: node.h:72
VLIB_FRAME_SIZE
#define VLIB_FRAME_SIZE
Definition: node.h:368
node
vlib_main_t vlib_node_runtime_t * node
Definition: nat44_ei.c:3047
nsim_wheel_entry_t::tx_time
f64 tx_time
Definition: nsim.h:32
u16
unsigned short u16
Definition: types.h:57
nsim_node_ctx
Definition: nsim.h:50
vm
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
VLIB_RX
@ VLIB_RX
Definition: defs.h:46
nsim_main_t::reorder_fraction
f64 reorder_fraction
Definition: nsim.h:106
vlib_buffer_enqueue_to_next
vlib_buffer_enqueue_to_next(vm, node, from,(u16 *) nexts, frame->n_vectors)
nsim_wheel_t
Definition: nsim.h:40
vlib_frame_t
Definition: node.h:372
nsim_trace_t
Definition: node.c:22
random_f64
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
nsim_trace_t::is_lost
int is_lost
Definition: node.c:27
nsim_inline
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
format_nsim_trace
static u8 * format_nsim_trace(u8 *s, va_list *args)
Definition: node.c:34
nsim_main_t::sw_if_index1
u32 sw_if_index1
Definition: nsim.h:89
error.h
nsim_error_strings
static char * nsim_error_strings[]
Definition: node.c:68
VLIB_NODE_FN
#define VLIB_NODE_FN(node)
Definition: node.h:202
nsim_wheel_entry_t
Definition: nsim.h:30
CLIB_UNUSED
#define CLIB_UNUSED(x)
Definition: clib.h:90
vnet_buffer
#define vnet_buffer(b)
Definition: buffer.h:441
VLIB_NODE_FLAG_TRACE
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:291
PREDICT_FALSE
#define PREDICT_FALSE(x)
Definition: clib.h:124
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
vlib_frame_vector_args
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:301
nsim_main_t::sw_if_index0
u32 sw_if_index0
Definition: nsim.h:89
NSIM_N_NEXT
@ NSIM_N_NEXT
Definition: node.c:78
uword
u64 uword
Definition: types.h:112
nsim_error_t
nsim_error_t
Definition: node.c:59
nsim_wheel_entry_t::output_next_index
u32 output_next_index
Definition: nsim.h:35
vlib_main_t::thread_index
u32 thread_index
Definition: main.h:215
vlib_node_increment_counter
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1244
nsim_feature_node
vlib_node_registration_t nsim_feature_node
(constructor) VLIB_REGISTER_NODE (nsim_feature_node)
Definition: node.c:338
foreach_nsim_error
#define foreach_nsim_error
Definition: node.c:53
f64
double f64
Definition: types.h:142
nsim_trace_t::tx_sw_if_index
u32 tx_sw_if_index
Definition: node.c:25
nsim_main
nsim_main_t nsim_main
Definition: nsim.c:39
vlib_node_registration_t
struct _vlib_node_registration vlib_node_registration_t
nsim_trace_buffer
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
nsim_dispatch_buffer
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
nsim_main_t::wheel_by_thread
nsim_wheel_t ** wheel_by_thread
Definition: nsim.h:99
NSIM_N_ERROR
@ NSIM_N_ERROR
Definition: node.c:64
vlib_buffer_t::current_config_index
u32 current_config_index
Used by feature subgraph arcs to visit enabled feature nodes.
Definition: buffer.h:156
always_inline
#define always_inline
Definition: rdma_mlx5dv.h:23
nsim_trace_t::expires
f64 expires
Definition: node.c:24
format
description fragment has unexpected format
Definition: map.api:433
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
nsim_buffer_fwd_lookup
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
unsigned int u32
Definition: types.h:88
nsim_wheel_t::cursize
u32 cursize
Definition: nsim.h:43
ctx
long ctx[MAX_CONNS]
Definition: main.c:144
nsim_main_t
Definition: nsim.h:80
nsim_wheel_t::entries
nsim_wheel_entry_t * entries
Definition: nsim.h:46
actions
vl_api_flow_action_t actions
Definition: flow_types.api:224
nsim_wheel_t::wheel_size
u32 wheel_size
Definition: nsim.h:42
slow_path
static u32 slow_path(nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_header_t *ip0, ip4_address_t i2o_addr, u16 i2o_port, u32 rx_fib_index0, nat_protocol_t nat_proto, nat44_ei_session_t **sessionp, vlib_node_runtime_t *node, u32 next0, u32 thread_index, f64 now)
Definition: nat44_ei_in2out.c:304
vlib_main_t
Definition: main.h:102
vnet_feature_get_config_main
static_always_inline vnet_feature_config_main_t * vnet_feature_get_config_main(u16 arc)
Definition: feature.h:244
vlib_node_t
Definition: node.h:247
vlib_add_trace
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:628
b
vlib_buffer_t ** b
Definition: nat44_ei_out2in.c:717
u8
unsigned char u8
Definition: types.h:56
NSIM_NEXT_DROP
@ NSIM_NEXT_DROP
Definition: node.c:77
vnet_get_config_data
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
i
int i
Definition: flowhash_template.h:376
nsim_main_t::output_next_index1
u32 output_next_index1
Definition: nsim.h:90
vlib_time_now
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:327
nsim_main_t::output_next_index0
u32 output_next_index0
Definition: nsim.h:90
vnet.h
nsim_node
vlib_node_registration_t nsim_node
(constructor) VLIB_REGISTER_NODE (nsim_node)
Definition: node.c:50
vlib_node_runtime_t
Definition: node.h:454
from
from
Definition: nat44_ei_hairpinning.c:415
PREDICT_TRUE
#define PREDICT_TRUE(x)
Definition: clib.h:125
nsim_main_t::output_next_index_by_sw_if_index
u32 * output_next_index_by_sw_if_index
Definition: nsim.h:93
sw_if_index
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
VLIB_TX
@ VLIB_TX
Definition: defs.h:47
nsim_main_t::arc_index
u16 arc_index
Definition: nsim.h:86
n_left_from
n_left_from
Definition: nat44_ei_hairpinning.c:416
type
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_buffer_t::flags
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,...
Definition: buffer.h:133
nsim_wheel_entry_t::buffer_index
u32 buffer_index
Definition: nsim.h:36
vlib_buffer_t
VLIB buffer representation.
Definition: buffer.h:111
nsim.h
VLIB_REGISTER_NODE
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169