2 * node.c - skeleton vpp engine plug-in dual-loop node skeleton
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>
31 #ifndef CLIB_MARCH_VARIANT
33 /* packet trace format function */
35 format_nsim_trace (u8 * s, va_list * args)
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 *);
42 s = format (s, "NSIM: dropped, %s", t->is_lost ?
43 "simulated network loss" : "no space in ring");
45 s = format (s, "NSIM: tx time %.6f sw_if_index %d",
46 t->expires, t->tx_sw_if_index);
51 vlib_node_registration_t nsim_node;
52 #endif /* CLIB_MARCH_VARIANT */
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")
61 #define _(sym,str) NSIM_ERROR_##sym,
67 #ifndef CLIB_MARCH_VARIANT
68 static char *nsim_error_strings[] = {
69 #define _(sym,string) string,
73 #endif /* CLIB_MARCH_VARIANT */
82 nsim_inline (vlib_main_t * vm,
83 vlib_node_runtime_t * node, vlib_frame_t * frame, int is_trace,
86 nsim_main_t *nsm = &nsim_main;
87 u32 n_left_from, *from;
88 u32 *to_next, n_left_to_next;
89 u32 drops[VLIB_FRAME_SIZE], *drop;
90 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
92 u16 nexts[VLIB_FRAME_SIZE], *next;
93 u32 my_thread_index = vm->thread_index;
94 nsim_wheel_t *wp = nsm->wheel_by_thread[my_thread_index];
95 f64 now = vlib_time_now (vm);
96 f64 expires = now + nsm->delay;
98 u32 no_buffer_error = node->errors[NSIM_ERROR_DROPPED];
99 u32 loss_error = node->errors[NSIM_ERROR_LOSS];
101 nsim_wheel_entry_t *ep = 0;
105 from = vlib_frame_vector_args (frame);
106 n_left_from = frame->n_vectors;
108 vlib_get_buffers (vm, from, bufs, n_left_from);
113 while (n_left_from >= 8)
115 vlib_prefetch_buffer_header (b[4], STORE);
116 vlib_prefetch_buffer_header (b[5], STORE);
117 vlib_prefetch_buffer_header (b[6], STORE);
118 vlib_prefetch_buffer_header (b[7], STORE);
120 memset (&is_drop, 0, sizeof (is_drop));
121 next[0] = next[1] = next[2] = next[3] = NSIM_NEXT_DROP;
122 if (PREDICT_FALSE (wp->cursize + 4 >= wp->wheel_size))
124 if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
126 rnd[0] = random_f64 (&nsm->seed);
127 rnd[1] = random_f64 (&nsm->seed);
128 rnd[2] = random_f64 (&nsm->seed);
129 rnd[3] = random_f64 (&nsm->seed);
131 if (rnd[0] <= nsm->drop_fraction)
133 b[0]->error = loss_error;
136 if (rnd[1] <= nsm->drop_fraction)
138 b[1]->error = loss_error;
141 if (rnd[2] <= nsm->drop_fraction)
143 b[2]->error = loss_error;
146 if (rnd[3] <= nsm->drop_fraction)
148 b[3]->error = loss_error;
153 if (PREDICT_TRUE (is_drop[0] == 0))
155 ep = wp->entries + wp->tail;
157 if (wp->tail == wp->wheel_size)
161 ep->tx_time = expires;
162 ep->rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
163 if (is_cross_connect)
166 (vnet_buffer (b[0])->sw_if_index[VLIB_RX] ==
167 nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
168 ep->output_next_index =
169 (ep->tx_sw_if_index ==
170 nsm->sw_if_index0) ? nsm->
171 output_next_index0 : nsm->output_next_index1;
173 else /* output feature, even easier... */
175 ep->tx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
176 ep->output_next_index =
177 nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
179 ep->buffer_index = from[0];
185 if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
187 nsim_trace_t *t = vlib_add_trace (vm, node, b[1], sizeof (*t));
188 t->expires = expires;
189 t->is_drop = is_drop[1];
190 t->is_lost = b[1]->error == loss_error;
191 t->tx_sw_if_index = (is_drop[1] == 0) ? ep->tx_sw_if_index : 0;
195 if (PREDICT_TRUE (is_drop[1] == 0))
197 ep = wp->entries + wp->tail;
199 if (wp->tail == wp->wheel_size)
203 ep->tx_time = expires;
204 ep->rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
205 if (is_cross_connect)
208 (vnet_buffer (b[1])->sw_if_index[VLIB_RX] ==
209 nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
210 ep->output_next_index =
211 (ep->tx_sw_if_index ==
212 nsm->sw_if_index0) ? nsm->
213 output_next_index0 : nsm->output_next_index1;
215 else /* output feature, even easier... */
217 ep->tx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
218 ep->output_next_index =
219 nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
221 ep->buffer_index = from[1];
227 if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
229 nsim_trace_t *t = vlib_add_trace (vm, node, b[2], sizeof (*t));
230 t->expires = expires;
231 t->is_drop = is_drop[2];
232 t->is_lost = b[2]->error == loss_error;
233 t->tx_sw_if_index = (is_drop[2] == 0) ? ep->tx_sw_if_index : 0;
236 if (PREDICT_TRUE (is_drop[2] == 0))
238 ep = wp->entries + wp->tail;
240 if (wp->tail == wp->wheel_size)
244 ep->tx_time = expires;
245 ep->rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
246 if (is_cross_connect)
249 (vnet_buffer (b[2])->sw_if_index[VLIB_RX] ==
250 nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
251 ep->output_next_index =
252 (ep->tx_sw_if_index ==
253 nsm->sw_if_index0) ? nsm->
254 output_next_index0 : nsm->output_next_index1;
256 else /* output feature, even easier... */
258 ep->tx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
259 ep->output_next_index =
260 nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
262 ep->buffer_index = from[2];
268 if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
270 nsim_trace_t *t = vlib_add_trace (vm, node, b[2], sizeof (*t));
271 t->expires = expires;
272 t->is_drop = is_drop[2];
273 t->is_lost = b[2]->error == loss_error;
274 t->tx_sw_if_index = (is_drop[2] == 0) ? ep->tx_sw_if_index : 0;
277 if (PREDICT_TRUE (is_drop[3] == 0))
279 ep = wp->entries + wp->tail;
281 if (wp->tail == wp->wheel_size)
285 ep->tx_time = expires;
286 ep->rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
287 if (is_cross_connect)
290 (vnet_buffer (b[3])->sw_if_index[VLIB_RX] ==
291 nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
292 ep->output_next_index =
293 (ep->tx_sw_if_index ==
294 nsm->sw_if_index0) ? nsm->
295 output_next_index0 : nsm->output_next_index1;
297 else /* output feature, even easier... */
299 ep->tx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
300 ep->output_next_index =
301 nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
303 ep->buffer_index = from[3];
309 if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
311 nsim_trace_t *t = vlib_add_trace (vm, node, b[3], sizeof (*t));
312 t->expires = expires;
313 t->is_drop = is_drop[3];
314 t->is_lost = b[3]->error == loss_error;
315 t->tx_sw_if_index = (is_drop[3] == 0) ? ep->tx_sw_if_index : 0;
319 if (PREDICT_FALSE (is_drop[0]))
321 if (PREDICT_FALSE (is_drop[1]))
323 if (PREDICT_FALSE (is_drop[2]))
325 if (PREDICT_FALSE (is_drop[3]))
336 while (n_left_from > 0)
338 next[0] = NSIM_NEXT_DROP;
340 if (PREDICT_TRUE (wp->cursize < wp->wheel_size))
342 if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
344 /* Get a random number on the closed interval [0,1] */
345 rnd[0] = random_f64 (&nsm->seed);
347 if (rnd[0] <= nsm->drop_fraction)
349 b[0]->error = loss_error;
355 ep = wp->entries + wp->tail;
357 if (wp->tail == wp->wheel_size)
361 ep->tx_time = expires;
362 ep->rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
363 if (is_cross_connect)
366 (vnet_buffer (b[0])->sw_if_index[VLIB_RX] ==
367 nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
368 ep->output_next_index =
369 (ep->tx_sw_if_index ==
370 nsm->sw_if_index0) ? nsm->
371 output_next_index0 : nsm->output_next_index1;
373 else /* output feature, even easier... */
375 ep->tx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
376 ep->output_next_index =
377 nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
379 ep->buffer_index = from[0];
382 else /* out of wheel space, drop pkt */
384 b[0]->error = no_buffer_error;
391 if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
393 nsim_trace_t *t = vlib_add_trace (vm, node, b[0], sizeof (*t));
394 t->expires = expires;
395 t->is_drop = is_drop[0];
396 t->is_lost = b[0]->error == loss_error;
397 t->tx_sw_if_index = (is_drop[0] == 0) ? ep->tx_sw_if_index : 0;
403 if (PREDICT_FALSE (is_drop[0]))
411 if (PREDICT_FALSE (drop > drops))
413 u32 n_left_to_drop = drop - drops;
416 while (n_left_to_drop > 0)
419 vlib_get_next_frame (vm, node, NSIM_NEXT_DROP, to_next,
421 this_copy_size = clib_min (n_left_to_drop, n_left_to_next);
422 clib_memcpy_fast (to_next, drop, this_copy_size * sizeof (u32));
423 n_left_to_next -= this_copy_size;
424 vlib_put_next_frame (vm, node, NSIM_NEXT_DROP, n_left_to_next);
425 drop += this_copy_size;
426 n_left_to_drop -= this_copy_size;
429 vlib_node_increment_counter (vm, node->node_index,
430 NSIM_ERROR_BUFFERED, buffered);
431 return frame->n_vectors;
434 VLIB_NODE_FN (nsim_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
435 vlib_frame_t * frame)
437 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
438 return nsim_inline (vm, node, frame,
439 1 /* is_trace */ , 1 /* is_cross_connect */ );
441 return nsim_inline (vm, node, frame,
442 0 /* is_trace */ , 1 /* is_cross_connect */ );
446 #ifndef CLIB_MARCH_VARIANT
447 VLIB_REGISTER_NODE (nsim_node) =
450 .vector_size = sizeof (u32),
451 .format_trace = format_nsim_trace,
452 .type = VLIB_NODE_TYPE_INTERNAL,
454 .n_errors = ARRAY_LEN(nsim_error_strings),
455 .error_strings = nsim_error_strings,
457 .n_next_nodes = NSIM_N_NEXT,
459 /* edit / add dispositions here */
461 [NSIM_NEXT_DROP] = "error-drop",
464 #endif /* CLIB_MARCH_VARIANT */
467 VLIB_NODE_FN (nsim_feature_node) (vlib_main_t * vm,
468 vlib_node_runtime_t * node,
469 vlib_frame_t * frame)
471 if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
472 return nsim_inline (vm, node, frame,
473 1 /* is_trace */ , 0 /* is_cross_connect */ );
475 return nsim_inline (vm, node, frame,
476 0 /* is_trace */ , 0 /* is_cross_connect */ );
480 #ifndef CLIB_MARCH_VARIANT
481 VLIB_REGISTER_NODE (nsim_feature_node) =
483 .name = "nsim-output-feature",
484 .vector_size = sizeof (u32),
485 .format_trace = format_nsim_trace,
486 .type = VLIB_NODE_TYPE_INTERNAL,
488 .n_errors = ARRAY_LEN(nsim_error_strings),
489 .error_strings = nsim_error_strings,
491 .n_next_nodes = NSIM_N_NEXT,
493 /* edit / add dispositions here */
495 [NSIM_NEXT_DROP] = "error-drop",
498 #endif /* CLIB_MARCH_VARIANT */
502 * fd.io coding-style-patch-verification: ON
505 * eval: (c-set-style "gnu")