Convert GRE nodes to new buffer APIs and multiarch

Change-Id: I3b3c8333287bb704ac7b0bbc81b3dbb059e8d2ac
Signed-off-by: Benoît Ganne <bganne@cisco.com>
diff --git a/src/vnet/gre/gre.c b/src/vnet/gre/gre.c
index 028eefb..72c76fc 100644
--- a/src/vnet/gre/gre.c
+++ b/src/vnet/gre/gre.c
@@ -19,6 +19,8 @@
 #include <vnet/gre/gre.h>
 #include <vnet/adj/adj_midchain.h>
 
+extern gre_main_t gre_main;
+
 #ifndef CLIB_MARCH_VARIANT
 gre_main_t gre_main;
 
@@ -56,7 +58,10 @@
   ip46_address_t dst;
 } gre_tx_trace_t;
 
-static u8 *
+extern u8 *format_gre_tx_trace (u8 * s, va_list * args);
+
+#ifndef CLIB_MARCH_VARIANT
+u8 *
 format_gre_tx_trace (u8 * s, va_list * args)
 {
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
@@ -70,7 +75,6 @@
   return s;
 }
 
-#ifndef CLIB_MARCH_VARIANT
 u8 *
 format_gre_protocol (u8 * s, va_list * args)
 {
@@ -324,7 +328,6 @@
 }
 #endif /* CLIB_MARCH_VARIANT */
 
-
 typedef enum
 {
   GRE_ENCAP_NEXT_L2_MIDCHAIN,
@@ -335,173 +338,145 @@
  * @brief TX function. Only called for L2 payload including TEB or ERSPAN.
  *        L3 traffic uses the adj-midchains.
  */
-VLIB_NODE_FN (gre_encap_node) (vlib_main_t * vm,
-			       vlib_node_runtime_t * node,
+VLIB_NODE_FN (gre_encap_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
 			       vlib_frame_t * frame)
 {
   gre_main_t *gm = &gre_main;
-  vnet_main_t *vnm = gm->vnet_main;
-  u32 next_index;
-  u32 *from, *to_next, n_left_from, n_left_to_next;
-  u32 sw_if_index0 = ~0;
-  u32 sw_if_index1 = ~0;
-  adj_index_t adj_index0 = ADJ_INDEX_INVALID;
-  adj_index_t adj_index1 = ADJ_INDEX_INVALID;
-  gre_tunnel_t *gt0 = NULL;
-  gre_tunnel_t *gt1 = NULL;
+  u32 *from, n_left_from;
+  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
+  u32 sw_if_index[2] = { ~0, ~0 };
+  const gre_tunnel_t *gt[2] = { 0 };
+  adj_index_t adj_index[2] = { ADJ_INDEX_INVALID, ADJ_INDEX_INVALID };
 
-  /* Vector of buffer / pkt indices we're supposed to process */
   from = vlib_frame_vector_args (frame);
-
-  /* Number of buffers / pkts */
   n_left_from = frame->n_vectors;
+  vlib_get_buffers (vm, from, bufs, n_left_from);
 
-  /* Speculatively send the first buffer to the last disposition we used */
-  next_index = GRE_ENCAP_NEXT_L2_MIDCHAIN;
-
-  while (n_left_from > 0)
+  while (n_left_from >= 2)
     {
-      /* set up to enqueue to our disposition with index = next_index */
-      vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
 
-      while (n_left_from >= 4 && n_left_to_next >= 2)
+      if (PREDICT_FALSE
+	  (sw_if_index[0] != vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
 	{
-	  u32 bi0 = from[0];
-	  u32 bi1 = from[1];
-	  vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
-	  vlib_buffer_t *b1 = vlib_get_buffer (vm, bi1);
-
-	  to_next[0] = bi0;
-	  to_next[1] = bi1;
-	  from += 2;
-	  to_next += 2;
-	  n_left_to_next -= 2;
-	  n_left_from -= 2;
-
-	  if (sw_if_index0 != vnet_buffer (b0)->sw_if_index[VLIB_TX])
-	    {
-	      sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
-	      vnet_hw_interface_t *hi0 =
-		vnet_get_sup_hw_interface (vnm, sw_if_index0);
-	      gt0 = &gm->tunnels[hi0->dev_instance];
-	      adj_index0 = gt0->l2_adj_index;
-	    }
-
-	  if (sw_if_index1 != vnet_buffer (b1)->sw_if_index[VLIB_TX])
-	    {
-	      if (sw_if_index0 == vnet_buffer (b1)->sw_if_index[VLIB_TX])
-		{
-		  sw_if_index1 = sw_if_index0;
-		  gt1 = gt0;
-		  adj_index1 = adj_index0;
-		}
-	      else
-		{
-		  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
-		  vnet_hw_interface_t *hi1 =
-		    vnet_get_sup_hw_interface (vnm, sw_if_index1);
-		  gt1 = &gm->tunnels[hi1->dev_instance];
-		  adj_index1 = gt1->l2_adj_index;
-		}
-	    }
-
-	  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = adj_index0;
-	  vnet_buffer (b1)->ip.adj_index[VLIB_TX] = adj_index1;
-
-	  if (PREDICT_FALSE (gt0->type == GRE_TUNNEL_TYPE_ERSPAN))
-	    {
-	      /* Encap GRE seq# and ERSPAN type II header */
-	      vlib_buffer_advance (b0, -sizeof (erspan_t2_t));
-	      erspan_t2_t *h0 = vlib_buffer_get_current (b0);
-	      u32 seq_num = clib_atomic_fetch_add (&gt0->gre_sn->seq_num, 1);
-	      u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
-	      h0->seq_num = clib_host_to_net_u32 (seq_num);
-	      h0->t2_u64 = hdr;
-	      h0->t2.cos_en_t_session |=
-		clib_host_to_net_u16 (gt0->session_id);
-	    }
-	  if (PREDICT_FALSE (gt1->type == GRE_TUNNEL_TYPE_ERSPAN))
-	    {
-	      /* Encap GRE seq# and ERSPAN type II header */
-	      vlib_buffer_advance (b1, -sizeof (erspan_t2_t));
-	      erspan_t2_t *h1 = vlib_buffer_get_current (b1);
-	      u32 seq_num = clib_atomic_fetch_add (&gt1->gre_sn->seq_num, 1);
-	      u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
-	      h1->seq_num = clib_host_to_net_u32 (seq_num);
-	      h1->t2_u64 = hdr;
-	      h1->t2.cos_en_t_session |=
-		clib_host_to_net_u16 (gt1->session_id);
-	    }
-
-	  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
-	    {
-	      gre_tx_trace_t *tr0 = vlib_add_trace (vm, node,
-						    b0, sizeof (*tr0));
-	      tr0->tunnel_id = gt0 - gm->tunnels;
-	      tr0->src = gt0->tunnel_src;
-	      tr0->dst = gt0->tunnel_dst.fp_addr;
-	      tr0->length = vlib_buffer_length_in_chain (vm, b0);
-	    }
-	  if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
-	    {
-	      gre_tx_trace_t *tr1 = vlib_add_trace (vm, node,
-						    b1, sizeof (*tr1));
-	      tr1->tunnel_id = gt1 - gm->tunnels;
-	      tr1->src = gt1->tunnel_src;
-	      tr1->dst = gt1->tunnel_dst.fp_addr;
-	      tr1->length = vlib_buffer_length_in_chain (vm, b1);
-	    }
+	  const vnet_hw_interface_t *hi;
+	  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
+	  hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
+	  gt[0] = &gm->tunnels[hi->dev_instance];
+	  adj_index[0] = gt[0]->l2_adj_index;
+	}
+      if (PREDICT_FALSE
+	  (sw_if_index[1] != vnet_buffer (b[1])->sw_if_index[VLIB_TX]))
+	{
+	  const vnet_hw_interface_t *hi;
+	  sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_TX];
+	  hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[1]);
+	  gt[1] = &gm->tunnels[hi->dev_instance];
+	  adj_index[1] = gt[1]->l2_adj_index;
 	}
 
-      while (n_left_from > 0 && n_left_to_next > 0)
+      vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
+      vnet_buffer (b[1])->ip.adj_index[VLIB_TX] = adj_index[1];
+
+      if (PREDICT_FALSE (gt[0]->type == GRE_TUNNEL_TYPE_ERSPAN))
 	{
-	  u32 bi0 = from[0];
-	  vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
-
-	  to_next[0] = bi0;
-	  from += 1;
-	  to_next += 1;
-	  n_left_from -= 1;
-	  n_left_to_next -= 1;
-
-	  if (sw_if_index0 != vnet_buffer (b0)->sw_if_index[VLIB_TX])
-	    {
-	      sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
-	      vnet_hw_interface_t *hi0 =
-		vnet_get_sup_hw_interface (vnm, sw_if_index0);
-	      gt0 = &gm->tunnels[hi0->dev_instance];
-	      adj_index0 = gt0->l2_adj_index;
-	    }
-
-	  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = adj_index0;
-
-	  if (PREDICT_FALSE (gt0->type == GRE_TUNNEL_TYPE_ERSPAN))
-	    {
-	      /* Encap GRE seq# and ERSPAN type II header */
-	      vlib_buffer_advance (b0, -sizeof (erspan_t2_t));
-	      erspan_t2_t *h0 = vlib_buffer_get_current (b0);
-	      u32 seq_num = clib_atomic_fetch_add (&gt0->gre_sn->seq_num, 1);
-	      u64 hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
-	      h0->seq_num = clib_host_to_net_u32 (seq_num);
-	      h0->t2_u64 = hdr;
-	      h0->t2.cos_en_t_session |=
-		clib_host_to_net_u16 (gt0->session_id);
-	    }
-
-	  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
-	    {
-	      gre_tx_trace_t *tr = vlib_add_trace (vm, node,
-						   b0, sizeof (*tr));
-	      tr->tunnel_id = gt0 - gm->tunnels;
-	      tr->src = gt0->tunnel_src;
-	      tr->dst = gt0->tunnel_dst.fp_addr;
-	      tr->length = vlib_buffer_length_in_chain (vm, b0);
-	    }
+	  /* Encap GRE seq# and ERSPAN type II header */
+	  erspan_t2_t *h0;
+	  u32 seq_num;
+	  u64 hdr;
+	  vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
+	  h0 = vlib_buffer_get_current (b[0]);
+	  seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
+	  hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
+	  h0->seq_num = clib_host_to_net_u32 (seq_num);
+	  h0->t2_u64 = hdr;
+	  h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
+	}
+      if (PREDICT_FALSE (gt[1]->type == GRE_TUNNEL_TYPE_ERSPAN))
+	{
+	  /* Encap GRE seq# and ERSPAN type II header */
+	  erspan_t2_t *h0;
+	  u32 seq_num;
+	  u64 hdr;
+	  vlib_buffer_advance (b[1], -sizeof (erspan_t2_t));
+	  h0 = vlib_buffer_get_current (b[1]);
+	  seq_num = clib_atomic_fetch_add (&gt[1]->gre_sn->seq_num, 1);
+	  hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
+	  h0->seq_num = clib_host_to_net_u32 (seq_num);
+	  h0->t2_u64 = hdr;
+	  h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[1]->session_id);
 	}
 
-      vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+      if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
+	{
+	  gre_tx_trace_t *tr = vlib_add_trace (vm, node,
+					       b[0], sizeof (*tr));
+	  tr->tunnel_id = gt[0] - gm->tunnels;
+	  tr->src = gt[0]->tunnel_src;
+	  tr->dst = gt[0]->tunnel_dst.fp_addr;
+	  tr->length = vlib_buffer_length_in_chain (vm, b[0]);
+	}
+      if (PREDICT_FALSE (b[1]->flags & VLIB_BUFFER_IS_TRACED))
+	{
+	  gre_tx_trace_t *tr = vlib_add_trace (vm, node,
+					       b[1], sizeof (*tr));
+	  tr->tunnel_id = gt[1] - gm->tunnels;
+	  tr->src = gt[1]->tunnel_src;
+	  tr->dst = gt[1]->tunnel_dst.fp_addr;
+	  tr->length = vlib_buffer_length_in_chain (vm, b[1]);
+	}
+
+      b += 2;
+      n_left_from -= 2;
     }
 
+  while (n_left_from >= 1)
+    {
+
+      if (PREDICT_FALSE
+	  (sw_if_index[0] != vnet_buffer (b[0])->sw_if_index[VLIB_TX]))
+	{
+	  const vnet_hw_interface_t *hi;
+	  sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_TX];
+	  hi = vnet_get_sup_hw_interface (gm->vnet_main, sw_if_index[0]);
+	  gt[0] = &gm->tunnels[hi->dev_instance];
+	  adj_index[0] = gt[0]->l2_adj_index;
+	}
+
+      vnet_buffer (b[0])->ip.adj_index[VLIB_TX] = adj_index[0];
+
+      if (PREDICT_FALSE (gt[0]->type == GRE_TUNNEL_TYPE_ERSPAN))
+	{
+	  /* Encap GRE seq# and ERSPAN type II header */
+	  erspan_t2_t *h0;
+	  u32 seq_num;
+	  u64 hdr;
+	  vlib_buffer_advance (b[0], -sizeof (erspan_t2_t));
+	  h0 = vlib_buffer_get_current (b[0]);
+	  seq_num = clib_atomic_fetch_add (&gt[0]->gre_sn->seq_num, 1);
+	  hdr = clib_host_to_net_u64 (ERSPAN_HDR2);
+	  h0->seq_num = clib_host_to_net_u32 (seq_num);
+	  h0->t2_u64 = hdr;
+	  h0->t2.cos_en_t_session |= clib_host_to_net_u16 (gt[0]->session_id);
+	}
+
+      if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
+	{
+	  gre_tx_trace_t *tr = vlib_add_trace (vm, node,
+					       b[0], sizeof (*tr));
+	  tr->tunnel_id = gt[0] - gm->tunnels;
+	  tr->src = gt[0]->tunnel_src;
+	  tr->dst = gt[0]->tunnel_dst.fp_addr;
+	  tr->length = vlib_buffer_length_in_chain (vm, b[0]);
+	}
+
+      b += 1;
+      n_left_from -= 1;
+    }
+
+  vlib_buffer_enqueue_to_single_next (vm, node, from,
+				      GRE_ENCAP_NEXT_L2_MIDCHAIN,
+				      frame->n_vectors);
+
   vlib_node_increment_counter (vm, node->node_index,
 			       GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
 
@@ -530,6 +505,7 @@
 };
 /* *INDENT-ON* */
 
+#ifndef CLIB_MARCH_VARIANT
 static u8 *
 format_gre_tunnel_name (u8 * s, va_list * args)
 {
@@ -566,7 +542,6 @@
 #endif
 };
 
-#ifndef CLIB_MARCH_VARIANT
 VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
   .name = "GRE",
   .format_header = format_gre_header_with_length,
@@ -576,6 +551,7 @@
   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
 };
 /* *INDENT-ON* */
+#endif /* CLIB_MARCH_VARIANT */
 
 static void
 add_protocol (gre_main_t * gm, gre_protocol_t protocol, char *protocol_name)
@@ -637,8 +613,6 @@
 
 VLIB_INIT_FUNCTION (gre_init);
 
-#endif /* CLIB_MARCH_VARIANT */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *