L2 over LISP and GRE (VPP-457)
[vpp.git] / vnet / vnet / gre / gre.c
index 9f8adc7..0028118 100644 (file)
@@ -47,11 +47,11 @@ u8 * format_gre_tx_trace (u8 * s, va_list * args)
   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
   gre_tx_trace_t * t = va_arg (*args, gre_tx_trace_t *);
-    
+
   s = format (s, "GRE: tunnel %d len %d src %U dst %U",
-              t->tunnel_id, clib_net_to_host_u16 (t->length),
-              format_ip4_address, &t->src.as_u8,
-              format_ip4_address, &t->dst.as_u8);
+             t->tunnel_id, clib_net_to_host_u16 (t->length),
+             format_ip4_address, &t->src.as_u8,
+             format_ip4_address, &t->dst.as_u8);
   return s;
 }
 
@@ -158,7 +158,7 @@ unformat_gre_header (unformat_input_t * input, va_list * args)
     vec_add2 (*result, p, n_bytes);
     clib_memcpy (p, h, n_bytes);
   }
-  
+
   return 1;
 }
 
@@ -198,15 +198,15 @@ static uword gre_set_rewrite (vnet_main_t * vnm,
   h->ip4.ttl = 64;
   h->ip4.protocol = IP_PROTOCOL_GRE;
   h->gre.protocol = clib_host_to_net_u16 (protocol);
-                    
+
   return sizeof (h[0]);
-#endif  
+#endif
 }
 
 static uword
 gre_interface_tx (vlib_main_t * vm,
-                  vlib_node_runtime_t * node,
-                  vlib_frame_t * frame)
+                 vlib_node_runtime_t * node,
+                 vlib_frame_t * frame)
 {
   gre_main_t * gm = &gre_main;
   u32 next_index;
@@ -218,71 +218,140 @@ gre_interface_tx (vlib_main_t * vm,
   from = vlib_frame_vector_args (frame);
 
   /* Number of buffers / pkts */
-  n_left_from = frame->n_vectors;   
+  n_left_from = frame->n_vectors;
 
   /* Speculatively send the first buffer to the last disposition we used */
   next_index = node->cached_next_index;
-  
+
   while (n_left_from > 0)
     {
       /* 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);
 
-      /* 
+      /*
        * FIXME DUAL LOOP
        */
 
       while (n_left_from > 0 && n_left_to_next > 0)
        {
-          u32 bi0, adj_index0, next0;
+         u32 bi0, adj_index0, next0;
          const ip_adjacency_t * adj0;
-          const dpo_id_t *dpo0;
-          ip4_header_t * ip0;
-          vlib_buffer_t * b0;
-
-          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);
-          ip0 = vlib_buffer_get_current (b0);
-
-          /* Fixup the checksum and len fields in the LISP tunnel encap
-           * that was applied at the midchain node */
-          ip0->length = 
-            clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
-          ip0->checksum = ip4_header_checksum (ip0);
-
-          /* Follow the DPO on which the midchain is stacked */
-          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+         const dpo_id_t *dpo0;
+         ip4_header_t * ip0;
+         vlib_buffer_t * b0;
+
+         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);
+         ip0 = vlib_buffer_get_current (b0);
+
+         /* Fixup the checksum and len fields in the GRE tunnel encap
+          * that was applied at the midchain node */
+         ip0->length =
+           clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+         ip0->checksum = ip4_header_checksum (ip0);
+
+         /* Follow the DPO on which the midchain is stacked */
+         adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
          adj0 = adj_get(adj_index0);
-          dpo0 = &adj0->sub_type.midchain.next_dpo;
-          next0 = dpo0->dpoi_next_node;
-          vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
-
-          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 = t - gm->tunnels;
-              tr->length = ip0->length;
-              tr->src.as_u32 = ip0->src_address.as_u32;
-              tr->dst.as_u32 = ip0->dst_address.as_u32;
-            }
+         dpo0 = &adj0->sub_type.midchain.next_dpo;
+         next0 = dpo0->dpoi_next_node;
+         vnet_buffer(b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+         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 = t - gm->tunnels;
+             tr->length = ip0->length;
+             tr->src.as_u32 = ip0->src_address.as_u32;
+             tr->dst.as_u32 = ip0->dst_address.as_u32;
+           }
 
          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);
+    }
+
+  vlib_node_increment_counter (vm, gre_input_node.index,
+                              GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
+
+  return frame->n_vectors;
+}
+
+static uword
+gre_l2_interface_tx (vlib_main_t * vm,
+                    vlib_node_runtime_t * node,
+                    vlib_frame_t * frame)
+{
+  gre_main_t * gm = &gre_main;
+  u32 next_index;
+  u32 * from, * to_next, n_left_from, n_left_to_next;
+  vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
+  const gre_tunnel_t *gt = pool_elt_at_index (gm->tunnels, rd->dev_instance);
+
+  /* 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;
+
+  /* Speculatively send the first buffer to the last disposition we used */
+  next_index = node->cached_next_index;
+
+  while (n_left_from > 0)
+    {
+      /* 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);
+
+      /*
+       * FIXME DUAL LOOP
+       */
+
+      while (n_left_from > 0 && n_left_to_next > 0)
+       {
+         vlib_buffer_t * b0;
+         u32 bi0;
+
+         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);
+
+         vnet_buffer(b0)->ip.adj_index[VLIB_TX] = gt->adj_index[FIB_LINK_ETHERNET];
+
+         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 = gt - gm->tunnels;
+             tr->length = vlib_buffer_length_in_chain (vm, b0);
+             tr->src.as_u32 = gt->tunnel_src.as_u32;
+             tr->dst.as_u32 = gt->tunnel_src.as_u32;
+           }
+
+         vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+                                          to_next, n_left_to_next,
+                                          bi0, gt->l2_tx_arc);
+       }
+
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
 
   vlib_node_increment_counter (vm, gre_input_node.index,
-                               GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
+                              GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
 
   return frame->n_vectors;
 }
@@ -290,11 +359,27 @@ gre_interface_tx (vlib_main_t * vm,
 static clib_error_t *
 gre_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 {
+  gre_main_t * gm = &gre_main;
+  vnet_hw_interface_t * hi;
+  gre_tunnel_t *t;
+  u32 ti;
+
+  hi = vnet_get_hw_interface (vnm, hw_if_index);
+  ti = gm->tunnel_index_by_sw_if_index[hi->sw_if_index];
+
+  if (~0 == ti)
+      /* not one of ours */
+      return (NULL);
+
+  t = pool_elt_at_index(gm->tunnels, ti);
+
   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
     vnet_hw_interface_set_flags (vnm, hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP);
   else
     vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
 
+  gre_tunnel_stack(t);
+
   return /* no error */ 0;
 }
 
@@ -313,6 +398,15 @@ static u8 * format_gre_device (u8 * s, va_list * args)
   return s;
 }
 
+static u8 * format_gre_l2_device (u8 * s, va_list * args)
+{
+  u32 dev_instance = va_arg (*args, u32);
+  CLIB_UNUSED (int verbose) = va_arg (*args, int);
+
+  s = format (s, "GRE L2-tunnel: id %d\n", dev_instance);
+  return s;
+}
+
 VNET_DEVICE_CLASS (gre_device_class) = {
   .name = "GRE tunnel device",
   .format_device_name = format_gre_tunnel_name,
@@ -328,6 +422,21 @@ VNET_DEVICE_CLASS (gre_device_class) = {
 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_device_class,
                                   gre_interface_tx)
 
+VNET_DEVICE_CLASS (gre_l2_device_class) = {
+  .name = "GRE L2 tunnel device",
+  .format_device_name = format_gre_tunnel_name,
+  .format_device = format_gre_l2_device,
+  .format_tx_trace = format_gre_tx_trace,
+  .tx_function = gre_l2_interface_tx,
+  .admin_up_down_function = gre_interface_admin_up_down,
+#ifdef SOON
+  .clear counter = 0;
+#endif
+};
+
+VLIB_DEVICE_TX_FUNCTION_MULTIARCH (gre_l2_device_class,
+                                  gre_l2_interface_tx)
+
 
 VNET_HW_INTERFACE_CLASS (gre_hw_interface_class) = {
   .name = "GRE",