Check if LISP is enable
[vpp.git] / vnet / vnet / lisp-gpe / interface.c
index 0f7f6fc..7537962 100644 (file)
@@ -23,7 +23,8 @@
 
 #define foreach_lisp_gpe_tx_next        \
   _(DROP, "error-drop")                 \
-  _(IP4_LOOKUP, "ip4-lookup")
+  _(IP4_LOOKUP, "ip4-lookup")           \
+  _(IP6_LOOKUP, "ip6-lookup")
 
 typedef enum
 {
@@ -49,6 +50,104 @@ format_lisp_gpe_tx_trace (u8 * s, va_list * args)
   return s;
 }
 
+always_inline void
+get_one_tunnel_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
+                       lisp_gpe_tunnel_t ** t0, u8 is_v4)
+{
+  u32 adj_index0, tunnel_index0;
+  ip_adjacency_t * adj0;
+
+  /* Get adjacency and from it the tunnel_index */
+  adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+
+  if (is_v4)
+    adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
+  else
+    adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
+
+  tunnel_index0 = adj0->rewrite_header.node_index;
+  t0[0] = pool_elt_at_index(lgm->tunnels, tunnel_index0);
+
+  ASSERT(t0[0] != 0);
+}
+
+always_inline void
+encap_one_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
+                  lisp_gpe_tunnel_t * t0, u32 * next0, u8 is_v4)
+{
+  ASSERT(sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+  ASSERT(sizeof(ip6_udp_lisp_gpe_header_t) == 56);
+
+  if (is_v4)
+    {
+      ip_udp_encap_one (lgm->vlib_main, b0, t0->rewrite, 36, 1);
+      next0[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+
+    }
+  else
+    {
+      ip_udp_encap_one (lgm->vlib_main, b0, t0->rewrite, 56, 0);
+      next0[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
+    }
+}
+
+always_inline void
+get_two_tunnels_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
+                        vlib_buffer_t * b1, lisp_gpe_tunnel_t ** t0,
+                        lisp_gpe_tunnel_t ** t1, u8 is_v4)
+{
+  u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
+  ip_adjacency_t * adj0, * adj1;
+
+  /* Get adjacency and from it the tunnel_index */
+  adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+  adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+
+  if (is_v4)
+    {
+      adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
+      adj1 = ip_get_adjacency (lgm->lm4, adj_index1);
+    }
+  else
+    {
+      adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
+      adj1 = ip_get_adjacency (lgm->lm6, adj_index1);
+    }
+
+  tunnel_index0 = adj0->rewrite_header.node_index;
+  tunnel_index1 = adj1->rewrite_header.node_index;
+
+  t0[0] = pool_elt_at_index(lgm->tunnels, tunnel_index0);
+  t1[0] = pool_elt_at_index(lgm->tunnels, tunnel_index1);
+
+  ASSERT(t0[0] != 0);
+  ASSERT(t1[0] != 0);
+}
+
+always_inline void
+encap_two_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1,
+                  lisp_gpe_tunnel_t * t0, lisp_gpe_tunnel_t * t1, u32 * next0,
+                  u32 * next1, u8 is_v4)
+{
+  ASSERT(sizeof(ip4_udp_lisp_gpe_header_t) == 36);
+  ASSERT(sizeof(ip6_udp_lisp_gpe_header_t) == 56);
+
+  if (is_v4)
+    {
+      ip_udp_encap_one (lgm->vlib_main, b0, t0->rewrite, 36, 1);
+      ip_udp_encap_one (lgm->vlib_main, b1, t1->rewrite, 36, 1);
+      next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+    }
+  else
+    {
+      ip_udp_encap_one (lgm->vlib_main, b0, t0->rewrite, 56, 0);
+      ip_udp_encap_one (lgm->vlib_main, b1, t1->rewrite, 56, 0);
+      next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
+    }
+}
+
+#define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
+
 static uword
 lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
                        vlib_frame_t * from_frame)
@@ -74,9 +173,8 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
           u32 bi0, bi1;
           vlib_buffer_t * b0, * b1;
           u32 next0, next1;
-          u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
-          ip_adjacency_t * adj0, * adj1;
-          lisp_gpe_tunnel_t * t0, * t1;
+          lisp_gpe_tunnel_t * t0 = 0, * t1 = 0;
+          u8 is_v4_eid0, is_v4_eid1;
 
           next0 = next1 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
 
@@ -106,24 +204,33 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
           b0 = vlib_get_buffer (vm, bi0);
           b1 = vlib_get_buffer (vm, bi1);
 
-          /* Get adjacency and from it the tunnel_index */
-          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-          adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+          is_v4_eid0 = is_v4_packet(vlib_buffer_get_current (b0));
+          is_v4_eid1 = is_v4_packet(vlib_buffer_get_current (b1));
 
-          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
-          adj1 = ip_get_adjacency (lgm->lookup_main, adj_index1);
-
-          tunnel_index0 = adj0->rewrite_header.node_index;
-          tunnel_index1 = adj1->rewrite_header.node_index;
-
-          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
-          t1 = pool_elt_at_index (lgm->tunnels, tunnel_index1);
-
-          ASSERT(t0 != 0);
-          ASSERT(t1 != 0);
+          if (PREDICT_TRUE(is_v4_eid0 == is_v4_eid1))
+            {
+              get_two_tunnels_inline (lgm, b0, b1, &t0, &t1,
+                                      is_v4_eid0 ? 1 : 0);
+            }
+          else
+            {
+              get_one_tunnel_inline (lgm, b0, &t0, is_v4_eid0 ? 1 : 0);
+              get_one_tunnel_inline (lgm, b1, &t1, is_v4_eid1 ? 1 : 0);
+            }
 
-          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
-          ip4_udp_encap_two (vm, b0, b1, t0->rewrite, t1->rewrite, 36);
+          if (PREDICT_TRUE(
+              ip_addr_version(&t0->dst) == ip_addr_version(&t1->dst)))
+            {
+              encap_two_inline (lgm, b0, b1, t0, t1, &next0, &next1,
+                                ip_addr_version(&t0->dst) == IP4 ? 1 : 0);
+            }
+          else
+            {
+              encap_one_inline (lgm, b0, t0, &next0,
+                                ip_addr_version(&t0->dst) == IP4 ? 1 : 0);
+              encap_one_inline (lgm, b1, t1, &next1,
+                                ip_addr_version(&t1->dst) == IP4 ? 1 : 0);
+            }
 
           /* Reset to look up tunnel partner in the configured FIB */
           vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
@@ -152,10 +259,9 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
       while (n_left_from > 0 && n_left_to_next > 0)
         {
           vlib_buffer_t * b0;
-          u32 bi0, adj_index0, tunnel_index0;
-          u32 next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
+          u32 bi0, next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
           lisp_gpe_tunnel_t * t0 = 0;
-          ip_adjacency_t * adj0;
+          u8 is_v4_0;
 
           bi0 = from[0];
           to_next[0] = bi0;
@@ -166,17 +272,11 @@ lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
 
           b0 = vlib_get_buffer (vm, bi0);
 
-          /* Get adjacency and from it the tunnel_index */
-          adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
-          adj0 = ip_get_adjacency (lgm->lookup_main, adj_index0);
-
-          tunnel_index0 = adj0->rewrite_header.node_index;
-          t0 = pool_elt_at_index (lgm->tunnels, tunnel_index0);
+          is_v4_0 = is_v4_packet(vlib_buffer_get_current (b0));
+          get_one_tunnel_inline (lgm, b0, &t0, is_v4_0 ? 1 : 0);
 
-          ASSERT(t0 != 0);
-
-          ASSERT (sizeof(ip4_udp_lisp_gpe_header_t) == 36);
-          ip4_udp_encap_one (vm, b0, t0->rewrite, 36);
+          encap_one_inline (lgm, b0, t0, &next0,
+                            ip_addr_version(&t0->dst) == IP4 ? 1 : 0);
 
           /* Reset to look up tunnel partner in the configured FIB */
           vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
@@ -271,7 +371,8 @@ add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
       a.dst_address = addr;
       a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
       a.add_adj = add_adj;
-      a.n_add_adj = 1;
+      a.n_add_adj = is_add ? 1 : 0;
+
       ip4_add_del_route (im4, &a);
 
       if (is_add)
@@ -302,7 +403,7 @@ add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
       a.dst_address = addr;
       a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
       a.add_adj = add_adj;
-      a.n_add_adj = 1;
+      a.n_add_adj = is_add ? 1 : 0;
 
       ip6_add_del_route (im6, &a);
 
@@ -335,7 +436,8 @@ add_del_lisp_gpe_default_route (u32 table_id, u8 is_v4, u8 is_add)
 
   adj.n_adj = 1;
   adj.explicit_fib_index = ~0;
-  adj.lookup_next_index = lgm->ip4_lookup_next_lgpe_ip4_lookup;
+  adj.lookup_next_index = is_v4 ? lgm->ip4_lookup_next_lgpe_ip4_lookup :
+                                  lgm->ip6_lookup_next_lgpe_ip6_lookup;
   /* default route has tunnel_index ~0 */
   adj.rewrite_header.sw_if_index = ~0;
 
@@ -378,16 +480,22 @@ lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id, u8 is_ip4)
     }
 }
 
-void
+int
 vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
                              u32 * hw_if_indexp)
 {
   lisp_gpe_main_t * lgm = &lisp_gpe_main;
   vnet_main_t * vnm = lgm->vnet_main;
   vnet_hw_interface_t * hi;
-  u32 hw_if_index = ~0, lookup_next_index, flen;
+  u32 hw_if_index = ~0, lookup_next_index4, lookup_next_index6, flen;
   uword * hip, * vni;
 
+  if (vnet_lisp_gpe_enable_disable_status() == 0)
+    {
+      clib_warning ("LISP is disabled!");
+      return VNET_API_ERROR_LISP_DISABLED;
+    }
+
   hip = hash_get(lgm->lisp_gpe_hw_if_index_by_table_id, a->table_id);
 
   if (a->is_add)
@@ -395,7 +503,7 @@ vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
       if (hip)
         {
           clib_warning ("Interface for vrf %d already exists", a->table_id);
-          return;
+          return -1;
         }
 
       /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
@@ -421,12 +529,17 @@ vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
       hash_set(lgm->tunnel_term_sw_if_index_by_vni, a->vni, hi->sw_if_index);
       hash_set(lgm->vni_by_tunnel_term_sw_if_index, hi->sw_if_index, a->vni);
 
-      /* set ingress arc from lgpe_ip4_lookup */
-      lookup_next_index = vlib_node_add_next (lgm->vlib_main,
-                                              lgpe_ip4_lookup_node.index,
-                                              hi->output_node_index);
+      /* set ingress arc from lgpe_ipX_lookup */
+      lookup_next_index4 = vlib_node_add_next (lgm->vlib_main,
+                                               lgpe_ip4_lookup_node.index,
+                                               hi->output_node_index);
+      lookup_next_index6 = vlib_node_add_next (lgm->vlib_main,
+                                               lgpe_ip6_lookup_node.index,
+                                               hi->output_node_index);
       hash_set(lgm->lgpe_ip4_lookup_next_index_by_table_id, a->table_id,
-               lookup_next_index);
+               lookup_next_index4);
+      hash_set(lgm->lgpe_ip6_lookup_next_index_by_table_id, a->table_id,
+               lookup_next_index6);
 
       /* insert default routes that point to lgpe-ipx-lookup */
       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 1);
@@ -453,7 +566,7 @@ vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
       if (hip == 0)
         {
           clib_warning("The interface for vrf %d doesn't exist", a->table_id);
-          return;
+          return -1;
         }
       hi = vnet_get_hw_interface (vnm, hip[0]);
 
@@ -472,6 +585,8 @@ vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 0);
       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 0);
     }
+
+  return 0;
 }
 
 static clib_error_t *
@@ -480,6 +595,8 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
 {
   unformat_input_t _line_input, * line_input = &_line_input;
   u8 is_add = 1;
+  clib_error_t * error = 0;
+  int rv = 0;
   u32 table_id;
 
   vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
@@ -505,8 +622,14 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
 
   a->is_add = is_add;
   a->table_id = table_id;
-  vnet_lisp_gpe_add_del_iface (a, 0);
-  return 0;
+  rv = vnet_lisp_gpe_add_del_iface (a, 0);
+  if (0 != rv)
+    {
+      error = clib_error_return(0, "failed to %s gpe iface!",
+                                is_add ? "add" : "delete");
+    }
+
+  return error;
 }
 
 VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {