+/* always_inline void */
+/* l2_process_one (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, u32 ti0, */
+/* u32 * next0) */
+/* { */
+/* lisp_gpe_tunnel_t *t0; */
+
+/* t0 = pool_elt_at_index (lgm->tunnels, ti0); */
+/* ASSERT (0 != t0); */
+
+/* if (PREDICT_TRUE (LISP_NO_ACTION == t0->action)) */
+/* { */
+/* /\* compute 'flow' hash *\/ */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* encap_one_inline (lgm, b0, t0, next0); */
+/* } */
+/* else */
+/* { */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* } */
+/* } */
+
+/* always_inline void */
+/* l2_process_two (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1, */
+/* u32 ti0, u32 ti1, u32 * next0, u32 * next1) */
+/* { */
+/* lisp_gpe_tunnel_t *t0, *t1; */
+
+/* t0 = pool_elt_at_index (lgm->tunnels, ti0); */
+/* t1 = pool_elt_at_index (lgm->tunnels, ti1); */
+
+/* ASSERT (0 != t0 && 0 != t1); */
+
+/* if (PREDICT_TRUE (LISP_NO_ACTION == t0->action */
+/* && LISP_NO_ACTION == t1->action)) */
+/* { */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1); */
+/* encap_two_inline (lgm, b0, b1, t0, t1, next0, next1); */
+/* } */
+/* else */
+/* { */
+/* if (LISP_NO_ACTION == t0->action) */
+/* { */
+/* if (PREDICT_TRUE (t0->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b0)->ip.flow_hash = l2_flow_hash (b0); */
+/* encap_one_inline (lgm, b0, t0, next0); */
+/* l2_process_tunnel_action (b1, t1->action, next1); */
+/* } */
+/* else if (LISP_NO_ACTION == t1->action) */
+/* { */
+/* if (PREDICT_TRUE (t1->sub_tunnels_lbv_count > 1)) */
+/* vnet_buffer (b1)->ip.flow_hash = l2_flow_hash (b1); */
+/* encap_one_inline (lgm, b1, t1, next1); */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* } */
+/* else */
+/* { */
+/* l2_process_tunnel_action (b0, t0->action, next0); */
+/* l2_process_tunnel_action (b1, t1->action, next1); */
+/* } */
+/* } */
+/* } */
+
+/**
+ * @brief LISP-GPE interface TX (encap) function for L2 overlays.
+ * @node l2_lisp_gpe_interface_tx
+ *
+ * The L2 LISP-GPE interface TX (encap) function.
+ *
+ * Uses bridge domain index, source and destination ethernet addresses to
+ * lookup tunnel. If the tunnel is multihomed a flow has is used to determine
+ * the sub-tunnel and therefore the rewrite string to be used to encapsulate
+ * the packets.
+ *
+ * @param[in] vm vlib_main_t corresponding to the current thread.
+ * @param[in] node vlib_node_runtime_t data for this node.
+ * @param[in] frame vlib_frame_t whose contents should be dispatched.
+ *
+ * @return number of vectors in frame.
+ */
+static uword
+l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, next_index, *from, *to_next;
+ lisp_gpe_main_t *lgm = &lisp_gpe_main;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 bi0, bi1;
+ vlib_buffer_t *b0, *b1;
+ u32 next0, next1;
+ lisp_gpe_tunnel_t *t0 = 0, *t1 = 0;
+ // ethernet_header_t *e0, *e1;
+
+ next0 = next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t *p2, *p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, LOAD);
+ vlib_prefetch_buffer_header (p3, LOAD);
+
+ CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+ CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+
+ bi0 = from[0];
+ bi1 = from[1];
+ to_next[0] = bi0;
+ to_next[1] = bi1;
+ from += 2;
+ to_next += 2;
+ n_left_to_next -= 2;
+ n_left_from -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ /* e0 = vlib_buffer_get_current (b0); */
+ /* e1 = vlib_buffer_get_current (b1); */
+
+ /* lookup dst + src mac */
+ /* ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index, */
+ /* e0->src_address, e0->dst_address); */
+ /* ti1 = lisp_l2_fib_lookup (lgm, vnet_buffer (b1)->l2.bd_index, */
+ /* e1->src_address, e1->dst_address); */
+
+ /* if (PREDICT_TRUE ((u32) ~ 0 != ti0) && (u32) ~ 0 != ti1) */
+ /* { */
+ /* /\* process both tunnels *\/ */
+ /* l2_process_two (lgm, b0, b1, ti0, ti1, &next0, &next1); */
+ /* } */
+ /* else */
+ /* { */
+ /* if ((u32) ~ 0 != ti0) */
+ /* { */
+ /* /\* process tunnel for b0 *\/ */
+ /* l2_process_one (lgm, b0, ti0, &next0); */
+
+ /* /\* no tunnel found for b1, send to control plane *\/ */
+ /* next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* else if ((u32) ~ 0 != ti1) */
+ /* { */
+ /* /\* process tunnel for b1 *\/ */
+ /* l2_process_one (lgm, b1, ti1, &next1); */
+
+ /* /\* no tunnel found b0, send to control plane *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* else */
+ /* { */
+ /* /\* no tunnels found *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b1)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+ /* } */
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof (*tr));
+ tr->tunnel_index = t0 - lgm->tunnels;
+ }
+ if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b1,
+ sizeof (*tr));
+ tr->tunnel_index = t1 - lgm->tunnels;
+ }
+
+ vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, bi1, next0,
+ next1);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ vlib_buffer_t *b0;
+ u32 bi0, ti0, next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
+ ethernet_header_t *e0;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ e0 = vlib_buffer_get_current (b0);
+
+ /* lookup dst + src mac */
+ ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index,
+ e0->src_address, e0->dst_address);
+
+ /* if (PREDICT_TRUE ((u32) ~ 0 != ti0)) */
+ /* { */
+ /* l2_process_one (lgm, b0, ti0, &next0); */
+ /* } */
+ /* else */
+ /* { */
+ /* /\* no tunnel found send to control plane *\/ */
+ /* next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP; */
+ /* vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC; */
+ /* } */
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof (*tr));
+ tr->tunnel_index = ti0 ? ti0 : ~0;
+ }
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);