+static void
+nsim_set_actions (nsim_main_t * nsm, vlib_buffer_t ** b,
+ nsim_node_ctx_t * ctx, u32 n_actions)
+{
+ int i;
+
+ memset (ctx->action, 0, n_actions * sizeof (ctx->action[0]));
+
+ if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
+ {
+ for (i = 0; i < n_actions; i++)
+ if (random_f64 (&nsm->seed) <= nsm->drop_fraction)
+ ctx->action[i] |= NSIM_ACTION_DROP;
+ }
+
+ if (PREDICT_FALSE (nsm->reorder_fraction != 0.0))
+ {
+ for (i = 0; i < n_actions; i++)
+ if (random_f64 (&nsm->seed) <= nsm->reorder_fraction)
+ ctx->action[i] |= NSIM_ACTION_REORDER;
+ }
+}
+
+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)
+{
+ if (b->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ nsim_trace_t *t = vlib_add_trace (vm, node, b, sizeof (*t));
+ t->expires = ctx->expires;
+ t->is_drop = is_drop;
+ t->is_lost = ctx->action[0] & NSIM_ACTION_DROP;
+ t->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
+ }
+}
+
+always_inline void
+nsim_buffer_fwd_lookup (nsim_main_t * nsm, vlib_buffer_t * b,
+ u32 * next, u8 is_cross_connect)
+{
+ if (is_cross_connect)
+ {
+ vnet_buffer (b)->sw_if_index[VLIB_TX] =
+ (vnet_buffer (b)->sw_if_index[VLIB_RX] == nsm->sw_if_index0) ?
+ nsm->sw_if_index1 : nsm->sw_if_index0;
+ *next =
+ (vnet_buffer (b)->sw_if_index[VLIB_TX] == nsm->sw_if_index0) ?
+ nsm->output_next_index0 : nsm->output_next_index1;
+ }
+ else /* output feature, even easier... */
+ {
+ u32 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
+ *next = nsm->output_next_index_by_sw_if_index[sw_if_index];
+ }
+}
+
+always_inline 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)
+{
+ if (PREDICT_TRUE (!(ctx->action[0] & NSIM_ACTION_DROP)))
+ {
+ if (PREDICT_FALSE (ctx->action[0] & NSIM_ACTION_REORDER))
+ {
+ u32 next;
+ ctx->reord[0] = bi;
+ vnet_get_config_data (&ctx->fcm->config_main,
+ &b->current_config_index, &next, 0);
+ ctx->reord_nexts[0] = next;
+ ctx->reord += 1;
+ ctx->reord_nexts += 1;
+ goto trace;
+ }
+
+ nsim_wheel_entry_t *ep = wp->entries + wp->tail;
+ wp->tail++;
+ if (wp->tail == wp->wheel_size)
+ wp->tail = 0;
+ wp->cursize++;
+
+ ep->tx_time = ctx->expires;
+ ep->rx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
+ nsim_buffer_fwd_lookup (nsm, b, &ep->output_next_index,
+ is_cross_connect);
+ ep->tx_sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX];
+ ep->buffer_index = bi;
+ ctx->n_buffered += 1;
+ }
+ else
+ {
+ ctx->n_loss += 1;
+ ctx->drop[0] = bi;
+ ctx->drop += 1;
+ }
+
+trace:
+
+ if (PREDICT_FALSE (is_trace))
+ nsim_trace_buffer (vm, node, b, ctx, 0);
+
+ ctx->action += 1;
+}
+