+ bond_packet_trace_t *t0;
+ ethernet_header_t *eth;
+ u32 next0 = 0;
+
+ vlib_trace_buffer (vm, node, next0, b[0], 0 /* follow_chain */ );
+ vlib_set_trace_count (vm, node, --n_trace);
+ t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
+ eth = (ethernet_header_t *) vlib_buffer_get_current (b[0]);
+ t0->ethernet = *eth;
+ t0->sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
+ if (!h)
+ {
+ t0->bond_sw_if_index = *vec_elt_at_index (bif->active_slaves, 0);
+ }
+ else
+ {
+ t0->bond_sw_if_index = *vec_elt_at_index (bif->active_slaves, h[0]);
+ h++;
+ }
+ b++;
+ n_left--;
+ }
+}
+
+VNET_DEVICE_CLASS_TX_FN (bond_dev_class) (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
+ bond_main_t *bm = &bond_main;
+ u16 thread_index = vm->thread_index;
+ bond_if_t *bif = pool_elt_at_index (bm->interfaces, rund->dev_instance);
+ uword n_slaves;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE];
+ u32 *from = vlib_frame_vector_args (frame);
+ u32 n_left = frame->n_vectors;
+ u32 hashes[VLIB_FRAME_SIZE], *h;
+ vnet_main_t *vnm = vnet_get_main ();
+ bond_per_thread_data_t *ptd = vec_elt_at_index (bm->per_thread_data,
+ thread_index);
+ u32 p, sw_if_index;
+
+ if (PREDICT_FALSE (bif->admin_up == 0))
+ {
+ vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
+ vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
+ VNET_INTERFACE_COUNTER_DROP,
+ thread_index, bif->sw_if_index,
+ frame->n_vectors);
+ vlib_error_count (vm, node->node_index, BOND_TX_ERROR_IF_DOWN,
+ frame->n_vectors);
+ return frame->n_vectors;
+ }
+
+ n_slaves = vec_len (bif->active_slaves);
+ if (PREDICT_FALSE (n_slaves == 0))
+ {
+ vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
+ vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
+ VNET_INTERFACE_COUNTER_DROP,
+ thread_index, bif->sw_if_index,
+ frame->n_vectors);
+ vlib_error_count (vm, node->node_index, BOND_TX_ERROR_NO_SLAVE,
+ frame->n_vectors);
+ return frame->n_vectors;
+ }
+
+ vlib_get_buffers (vm, from, bufs, n_left);
+
+ /* active-backup mode, ship everything to first sw if index */
+ if ((bif->lb == BOND_LB_AB) || PREDICT_FALSE (n_slaves == 1))
+ {
+ sw_if_index = *vec_elt_at_index (bif->active_slaves, 0);
+
+ bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, 0);
+ bond_update_sw_if_index (ptd, bif, from, bufs, &sw_if_index, n_left,
+ /* single_sw_if_index */ 1);
+ goto done;
+ }
+
+ if (bif->lb == BOND_LB_BC)
+ {
+ sw_if_index = *vec_elt_at_index (bif->active_slaves, 0);
+
+ bond_tx_inline (vm, node, bif, bufs, hashes, n_left, n_slaves,
+ BOND_LB_BC);
+ bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, 0);
+ bond_update_sw_if_index (ptd, bif, from, bufs, &sw_if_index, n_left,
+ /* single_sw_if_index */ 1);
+ goto done;
+ }
+
+ if (bif->lb == BOND_LB_L2)
+ bond_tx_inline (vm, node, bif, bufs, hashes, n_left, n_slaves,
+ BOND_LB_L2);
+ else if (bif->lb == BOND_LB_L34)
+ bond_tx_inline (vm, node, bif, bufs, hashes, n_left, n_slaves,
+ BOND_LB_L34);
+ else if (bif->lb == BOND_LB_L23)
+ bond_tx_inline (vm, node, bif, bufs, hashes, n_left, n_slaves,
+ BOND_LB_L23);
+ else if (bif->lb == BOND_LB_RR)
+ bond_tx_inline (vm, node, bif, bufs, hashes, n_left, n_slaves,
+ BOND_LB_RR);
+ else
+ ASSERT (0);
+
+ /* calculate port out of hash */
+ h = hashes;
+ if (BOND_MODULO_SHORTCUT (n_slaves))
+ bond_hash_to_port (h, frame->n_vectors, n_slaves, 1);
+ else
+ bond_hash_to_port (h, frame->n_vectors, n_slaves, 0);
+
+ bond_tx_trace (vm, node, bif, bufs, frame->n_vectors, h);
+
+ bond_update_sw_if_index (ptd, bif, from, bufs, hashes, frame->n_vectors,
+ /* single_sw_if_index */ 0);
+
+done:
+ for (p = 0; p < n_slaves; p++)
+ {
+ vlib_frame_t *f;
+ u32 *to_next;
+
+ sw_if_index = *vec_elt_at_index (bif->active_slaves, p);
+ if (PREDICT_TRUE (ptd->per_port_queue[p].n_buffers))