+ drop = drops;
+
+ while (n_left_from >= 8)
+ {
+ vlib_prefetch_buffer_header (b[4], STORE);
+ vlib_prefetch_buffer_header (b[5], STORE);
+ vlib_prefetch_buffer_header (b[6], STORE);
+ vlib_prefetch_buffer_header (b[7], STORE);
+
+ memset (&is_drop, 0, sizeof (is_drop));
+ next[0] = next[1] = next[2] = next[3] = NSIM_NEXT_DROP;
+ if (PREDICT_FALSE (wp->cursize + 4 >= wp->wheel_size))
+ goto slow_path;
+ if (PREDICT_FALSE (nsm->drop_fraction != 0.0))
+ {
+ rnd[0] = random_f64 (&nsm->seed);
+ rnd[1] = random_f64 (&nsm->seed);
+ rnd[2] = random_f64 (&nsm->seed);
+ rnd[3] = random_f64 (&nsm->seed);
+
+ if (rnd[0] <= nsm->drop_fraction)
+ {
+ b[0]->error = loss_error;
+ is_drop[0] = 1;
+ }
+ if (rnd[1] <= nsm->drop_fraction)
+ {
+ b[1]->error = loss_error;
+ is_drop[1] = 1;
+ }
+ if (rnd[2] <= nsm->drop_fraction)
+ {
+ b[2]->error = loss_error;
+ is_drop[2] = 1;
+ }
+ if (rnd[3] <= nsm->drop_fraction)
+ {
+ b[3]->error = loss_error;
+ is_drop[3] = 1;
+ }
+ }
+
+ if (PREDICT_TRUE (is_drop[0] == 0))
+ {
+ ep = wp->entries + wp->tail;
+ wp->tail++;
+ if (wp->tail == wp->wheel_size)
+ wp->tail = 0;
+ wp->cursize++;
+
+ ep->tx_time = expires;
+ ep->rx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
+ if (is_cross_connect)
+ {
+ ep->tx_sw_if_index =
+ (vnet_buffer (b[0])->sw_if_index[VLIB_RX] ==
+ nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
+ ep->output_next_index =
+ (ep->tx_sw_if_index ==
+ nsm->sw_if_index0) ? nsm->
+ output_next_index0 : nsm->output_next_index1;
+ }
+ else /* output feature, even easier... */
+ {
+ ep->tx_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
+ ep->output_next_index =
+ nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
+ }
+ ep->buffer_index = from[0];
+ buffered++;
+ }
+
+ if (is_trace)
+ {
+ if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ nsim_trace_t *t = vlib_add_trace (vm, node, b[1], sizeof (*t));
+ t->expires = expires;
+ t->is_drop = is_drop[1];
+ t->is_lost = b[1]->error == loss_error;
+ t->tx_sw_if_index = (is_drop[1] == 0) ? ep->tx_sw_if_index : 0;
+ }
+ }
+
+ if (PREDICT_TRUE (is_drop[1] == 0))
+ {
+ ep = wp->entries + wp->tail;
+ wp->tail++;
+ if (wp->tail == wp->wheel_size)
+ wp->tail = 0;
+ wp->cursize++;
+
+ ep->tx_time = expires;
+ ep->rx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
+ if (is_cross_connect)
+ {
+ ep->tx_sw_if_index =
+ (vnet_buffer (b[1])->sw_if_index[VLIB_RX] ==
+ nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
+ ep->output_next_index =
+ (ep->tx_sw_if_index ==
+ nsm->sw_if_index0) ? nsm->
+ output_next_index0 : nsm->output_next_index1;
+ }
+ else /* output feature, even easier... */
+ {
+ ep->tx_sw_if_index = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
+ ep->output_next_index =
+ nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
+ }
+ ep->buffer_index = from[1];
+ buffered++;
+ }
+
+ if (is_trace)
+ {
+ if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ nsim_trace_t *t = vlib_add_trace (vm, node, b[2], sizeof (*t));
+ t->expires = expires;
+ t->is_drop = is_drop[2];
+ t->is_lost = b[2]->error == loss_error;
+ t->tx_sw_if_index = (is_drop[2] == 0) ? ep->tx_sw_if_index : 0;
+ }
+ }
+ if (PREDICT_TRUE (is_drop[2] == 0))
+ {
+ ep = wp->entries + wp->tail;
+ wp->tail++;
+ if (wp->tail == wp->wheel_size)
+ wp->tail = 0;
+ wp->cursize++;
+
+ ep->tx_time = expires;
+ ep->rx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
+ if (is_cross_connect)
+ {
+ ep->tx_sw_if_index =
+ (vnet_buffer (b[2])->sw_if_index[VLIB_RX] ==
+ nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
+ ep->output_next_index =
+ (ep->tx_sw_if_index ==
+ nsm->sw_if_index0) ? nsm->
+ output_next_index0 : nsm->output_next_index1;
+ }
+ else /* output feature, even easier... */
+ {
+ ep->tx_sw_if_index = vnet_buffer (b[2])->sw_if_index[VLIB_TX];
+ ep->output_next_index =
+ nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
+ }
+ ep->buffer_index = from[2];
+ buffered++;
+ }
+
+ if (is_trace)
+ {
+ if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ nsim_trace_t *t = vlib_add_trace (vm, node, b[2], sizeof (*t));
+ t->expires = expires;
+ t->is_drop = is_drop[2];
+ t->is_lost = b[2]->error == loss_error;
+ t->tx_sw_if_index = (is_drop[2] == 0) ? ep->tx_sw_if_index : 0;
+ }
+ }
+ if (PREDICT_TRUE (is_drop[3] == 0))
+ {
+ ep = wp->entries + wp->tail;
+ wp->tail++;
+ if (wp->tail == wp->wheel_size)
+ wp->tail = 0;
+ wp->cursize++;
+
+ ep->tx_time = expires;
+ ep->rx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
+ if (is_cross_connect)
+ {
+ ep->tx_sw_if_index =
+ (vnet_buffer (b[3])->sw_if_index[VLIB_RX] ==
+ nsm->sw_if_index0) ? nsm->sw_if_index1 : nsm->sw_if_index0;
+ ep->output_next_index =
+ (ep->tx_sw_if_index ==
+ nsm->sw_if_index0) ? nsm->
+ output_next_index0 : nsm->output_next_index1;
+ }
+ else /* output feature, even easier... */
+ {
+ ep->tx_sw_if_index = vnet_buffer (b[3])->sw_if_index[VLIB_TX];
+ ep->output_next_index =
+ nsm->output_next_index_by_sw_if_index[ep->tx_sw_if_index];
+ }
+ ep->buffer_index = from[3];
+ buffered++;
+ }
+
+ if (is_trace)
+ {
+ if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ nsim_trace_t *t = vlib_add_trace (vm, node, b[3], sizeof (*t));
+ t->expires = expires;
+ t->is_drop = is_drop[3];
+ t->is_lost = b[3]->error == loss_error;
+ t->tx_sw_if_index = (is_drop[3] == 0) ? ep->tx_sw_if_index : 0;
+ }
+ }
+
+ if (PREDICT_FALSE (is_drop[0]))
+ *drop++ = from[0];
+ if (PREDICT_FALSE (is_drop[1]))
+ *drop++ = from[1];
+ if (PREDICT_FALSE (is_drop[2]))
+ *drop++ = from[2];
+ if (PREDICT_FALSE (is_drop[3]))
+ *drop++ = from[3];
+
+ b += 4;
+ next += 4;
+ from += 4;
+ n_left_from -= 4;
+ }
+
+slow_path: