vxlan: crash on configuring vxlan tunnel on l3 mode
[vpp.git] / src / vnet / vxlan / vxlan.c
index 97098b8..484b7c2 100644 (file)
@@ -82,6 +82,8 @@ format_vxlan_tunnel (u8 * s, va_list * args)
   if (PREDICT_FALSE (t->decap_next_index != VXLAN_INPUT_NEXT_L2_INPUT))
     s = format (s, "decap-next-%U ", format_decap_next, t->decap_next_index);
 
+  s = format (s, "l3 %u ", t->is_l3);
+
   if (PREDICT_FALSE (ip46_address_is_multicast (&t->dst)))
     s = format (s, "mcast-sw-if-idx %d ", t->mcast_sw_if_index);
 
@@ -245,7 +247,8 @@ const static fib_node_vft_t vxlan_vft = {
   _ (src)                                                                     \
   _ (dst)                                                                     \
   _ (src_port)                                                                \
-  _ (dst_port)
+  _ (dst_port)                                                                \
+  _ (is_l3)
 
 static void
 vxlan_rewrite (vxlan_tunnel_t * t, bool is_ip6)
@@ -442,29 +445,34 @@ int vnet_vxlan_add_del_tunnel
          return VNET_API_ERROR_INSTANCE_IN_USE;
        }
 
-      f64 now = vlib_time_now (vm);
-      u32 rnd;
-      rnd = (u32) (now * 1e6);
-      rnd = random_u32 (&rnd);
-
-      memcpy (hw_addr + 2, &rnd, sizeof (rnd));
-      hw_addr[0] = 2;
-      hw_addr[1] = 0xfe;
-
       hash_set (vxm->instance_used, user_instance, 1);
 
       t->dev_instance = dev_instance;  /* actual */
       t->user_instance = user_instance; /* name */
       t->flow_index = ~0;
 
-      if (ethernet_register_interface (vnm, vxlan_device_class.index,
-                                      dev_instance, hw_addr, &t->hw_if_index,
-                                      vxlan_eth_flag_change))
+      if (a->is_l3 == 0)
+       t->hw_if_index =
+         vnet_register_interface (vnm, vxlan_device_class.index, dev_instance,
+                                  vxlan_hw_class.index, dev_instance);
+      else
        {
-         hash_unset (vxm->instance_used, t->user_instance);
+         f64 now = vlib_time_now (vm);
+         u32 rnd;
+         rnd = (u32) (now * 1e6);
+         rnd = random_u32 (&rnd);
+         memcpy (hw_addr + 2, &rnd, sizeof (rnd));
+         hw_addr[0] = 2;
+         hw_addr[1] = 0xfe;
+         if (ethernet_register_interface (
+               vnm, vxlan_device_class.index, dev_instance, hw_addr,
+               &t->hw_if_index, vxlan_eth_flag_change))
+           {
+             hash_unset (vxm->instance_used, t->user_instance);
 
-         pool_put (vxm->tunnels, t);
-         return VNET_API_ERROR_SYSCALL_ERROR_2;
+             pool_put (vxm->tunnels, t);
+             return VNET_API_ERROR_SYSCALL_ERROR_2;
+           }
        }
 
       vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, t->hw_if_index);
@@ -498,7 +506,10 @@ int vnet_vxlan_add_del_tunnel
 
       if (add_failed)
        {
-         ethernet_delete_interface (vnm, t->hw_if_index);
+         if (a->is_l3 == 0)
+           vnet_delete_hw_interface (vnm, t->hw_if_index);
+         else
+           ethernet_delete_interface (vnm, t->hw_if_index);
          hash_unset (vxm->instance_used, t->user_instance);
          pool_put (vxm->tunnels, t);
          return VNET_API_ERROR_INVALID_REGISTRATION;
@@ -573,15 +584,16 @@ int vnet_vxlan_add_del_tunnel
               *  - the forwarding interface is for-us
               *  - the accepting interface is that from the API
               */
-             mfib_table_entry_path_update (t->encap_fib_index,
-                                           &mpfx, MFIB_SOURCE_VXLAN, &path);
+             mfib_table_entry_path_update (t->encap_fib_index, &mpfx,
+                                           MFIB_SOURCE_VXLAN,
+                                           MFIB_ENTRY_FLAG_NONE, &path);
 
              path.frp_sw_if_index = a->mcast_sw_if_index;
              path.frp_flags = FIB_ROUTE_PATH_FLAG_NONE;
              path.frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT;
-             mfei = mfib_table_entry_path_update (t->encap_fib_index,
-                                                  &mpfx,
-                                                  MFIB_SOURCE_VXLAN, &path);
+             mfei = mfib_table_entry_path_update (
+               t->encap_fib_index, &mpfx, MFIB_SOURCE_VXLAN,
+               MFIB_ENTRY_FLAG_NONE, &path);
 
              /*
               * Create the mcast adjacency to send traffic to the group
@@ -647,7 +659,10 @@ int vnet_vxlan_add_del_tunnel
          mcast_shared_remove (&t->dst);
        }
 
-      ethernet_delete_interface (vnm, t->hw_if_index);
+      if (t->is_l3 == 0)
+       vnet_delete_hw_interface (vnm, t->hw_if_index);
+      else
+       ethernet_delete_interface (vnm, t->hw_if_index);
       hash_unset (vxm->instance_used, t->user_instance);
 
       fib_node_deinit (&t->node);
@@ -717,6 +732,7 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
   u8 grp_set = 0;
   u8 ipv4_set = 0;
   u8 ipv6_set = 0;
+  u8 is_l3 = 0;
   u32 instance = ~0;
   u32 encap_fib_index = 0;
   u32 mcast_sw_if_index = ~0;
@@ -764,6 +780,8 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
          encap_fib_index =
            fib_table_find (fib_ip_proto (ipv6_set), table_id);
        }
+      else if (unformat (line_input, "l3"))
+       is_l3 = 1;
       else if (unformat (line_input, "decap-next %U", unformat_decap_next,
                         &decap_next_index, ipv4_set))
        ;
@@ -786,6 +804,13 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
   if (parse_error)
     return parse_error;
 
+  if (is_l3 && decap_next_index == VXLAN_INPUT_NEXT_L2_INPUT)
+    {
+      vlib_node_t *node = vlib_get_node_by_name (
+       vm, (u8 *) (ipv4_set ? "ip4-input" : "ip6-input"));
+      decap_next_index = get_decap_next_for_node (node->index, ipv4_set);
+    }
+
   if (encap_fib_index == ~0)
     return clib_error_return (0, "nonexistent encap-vrf-id %d", table_id);
 
@@ -819,12 +844,11 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
   if (vni >> 24)
     return clib_error_return (0, "vni %d out of range", vni);
 
-  vnet_vxlan_add_del_tunnel_args_t a = {
-    .is_add = is_add,
-    .is_ip6 = ipv6_set,
-    .instance = instance,
+  vnet_vxlan_add_del_tunnel_args_t a = { .is_add = is_add,
+                                        .is_ip6 = ipv6_set,
+                                        .instance = instance,
 #define _(x) .x = x,
-    foreach_copy_field
+                                        foreach_copy_field
 #undef _
   };
 
@@ -893,7 +917,7 @@ VLIB_CLI_COMMAND (create_vxlan_tunnel_command, static) = {
     "create vxlan tunnel src <local-vtep-addr>"
     " {dst <remote-vtep-addr>|group <mcast-vtep-addr> <intf-name>} vni <nn>"
     " [instance <id>]"
-    " [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [del]"
+    " [encap-vrf-id <nn>] [decap-next [l2|node <name>]] [del] [l3]"
     " [src_port <local-vtep-udp-port>] [dst_port <remote-vtep-udp-port>]",
   .function = vxlan_add_del_tunnel_command_fn,
 };
@@ -1051,7 +1075,7 @@ set_ip4_vxlan_bypass (vlib_main_t * vm,
 /*?
  * This command adds the 'ip4-vxlan-bypass' graph node for a given interface.
  * By adding the IPv4 vxlan-bypass graph node to an interface, the node checks
- *  for and validate input vxlan packet and bypass ip4-lookup, ip4-local,
+ * for and validate input vxlan packet and bypass ip4-lookup, ip4-local,
  * ip4-udp-lookup nodes to speedup vxlan packet forwarding. This node will
  * cause extra overhead to for non-vxlan packets which is kept at a minimum.
  *
@@ -1108,7 +1132,7 @@ set_ip6_vxlan_bypass (vlib_main_t * vm,
 /*?
  * This command adds the 'ip6-vxlan-bypass' graph node for a given interface.
  * By adding the IPv6 vxlan-bypass graph node to an interface, the node checks
- *  for and validate input vxlan packet and bypass ip6-lookup, ip6-local,
+ * for and validate input vxlan packet and bypass ip6-lookup, ip6-local,
  * ip6-udp-lookup nodes to speedup vxlan packet forwarding. This node will
  * cause extra overhead to for non-vxlan packets which is kept at a minimum.
  *