From 3e38422ab905d26ab1625c74268e30c94327ea54 Mon Sep 17 00:00:00 2001 From: Nathan Skrzypczak Date: Wed, 21 Apr 2021 19:56:34 +0200 Subject: [PATCH] vxlan: Fix L3 mode Type: fix Partially revert fix SEGV reported in VPP-1962 [commit a4b0541f64eef02fa0d003d8f831cfdeb45d3668] This adds an is_l3 option to choose between L2 & L3 mode add tunnel creation time Change-Id: Ia2c91a1099074b7d23fc031b78ed0f68628eeabe Signed-off-by: Nathan Skrzypczak --- src/vnet/vxlan/test/vpp_vxlan_tunnel.py | 7 +- src/vnet/vxlan/vxlan.api | 38 +++++++++ src/vnet/vxlan/vxlan.c | 68 ++++++++++----- src/vnet/vxlan/vxlan.h | 1 + src/vnet/vxlan/vxlan_api.c | 147 +++++++++++++++----------------- 5 files changed, 158 insertions(+), 103 deletions(-) diff --git a/src/vnet/vxlan/test/vpp_vxlan_tunnel.py b/src/vnet/vxlan/test/vpp_vxlan_tunnel.py index dce5ab86c07..d7e087da6f8 100644 --- a/src/vnet/vxlan/test/vpp_vxlan_tunnel.py +++ b/src/vnet/vxlan/test/vpp_vxlan_tunnel.py @@ -38,7 +38,7 @@ class VppVxlanTunnel(VppInterface): mcast_itf=None, mcast_sw_if_index=INDEX_INVALID, decap_next_index=INDEX_INVALID, - encap_vrf_id=None, instance=0xffffffff): + encap_vrf_id=None, instance=0xffffffff, is_l3=False): """ Create VXLAN Tunnel interface """ super(VppVxlanTunnel, self).__init__(test) self.src = src @@ -51,16 +51,17 @@ class VppVxlanTunnel(VppInterface): self.encap_vrf_id = encap_vrf_id self.decap_next_index = decap_next_index self.instance = instance + self.is_l3 = is_l3 if (self.mcast_itf): self.mcast_sw_if_index = self.mcast_itf.sw_if_index def add_vpp_config(self): - reply = self.test.vapi.vxlan_add_del_tunnel_v2( + reply = self.test.vapi.vxlan_add_del_tunnel_v3( is_add=1, src_address=self.src, dst_address=self.dst, vni=self.vni, src_port=self.src_port, dst_port=self.dst_port, mcast_sw_if_index=self.mcast_sw_if_index, - encap_vrf_id=self.encap_vrf_id, + encap_vrf_id=self.encap_vrf_id, is_l3=self.is_l3, instance=self.instance, decap_next_index=self.decap_next_index) self.set_sw_if_index(reply.sw_if_index) self._test.registry.register(self, self._test.logger) diff --git a/src/vnet/vxlan/vxlan.api b/src/vnet/vxlan/vxlan.api index 2370fb5157c..b7e678595d8 100644 --- a/src/vnet/vxlan/vxlan.api +++ b/src/vnet/vxlan/vxlan.api @@ -74,6 +74,38 @@ define vxlan_add_del_tunnel_v2 u32 vni; }; +/** \brief Create or delete a VXLAN tunnel + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - Use 1 to create the tunnel, 0 to remove it + @param instance - optional unique custom device instance, else ~0. + @param src_address - Source IP address + @param dst_address - Destination IP address, can be multicast + @param src_port - Source UDP port. It is not included in sent packets. Used only for port registration + @param dst_port - Destination UDP port + @param mcast_sw_if_index - Interface for multicast destination + @param encap_vrf_id - Encap route table FIB index + @param decap_next_index - index of decap next graph node + @param vni - The VXLAN Network Identifier, uint24 + @param is_l3 - if true, create the interface in L3 mode, w/o MAC +*/ +define vxlan_add_del_tunnel_v3 +{ + u32 client_index; + u32 context; + bool is_add [default=true]; + u32 instance [default=0xffffffff]; /* If non-~0, specifies a custom dev instance */ + vl_api_address_t src_address; + vl_api_address_t dst_address; + u16 src_port; + u16 dst_port; + vl_api_interface_index_t mcast_sw_if_index; + u32 encap_vrf_id; + u32 decap_next_index; + u32 vni; + bool is_l3 [default=false]; +}; + define vxlan_add_del_tunnel_reply { u32 context; @@ -86,6 +118,12 @@ define vxlan_add_del_tunnel_v2_reply i32 retval; vl_api_interface_index_t sw_if_index; }; +define vxlan_add_del_tunnel_v3_reply +{ + u32 context; + i32 retval; + vl_api_interface_index_t sw_if_index; +}; define vxlan_tunnel_dump { diff --git a/src/vnet/vxlan/vxlan.c b/src/vnet/vxlan/vxlan.c index 97098b83774..dcf480578a7 100644 --- a/src/vnet/vxlan/vxlan.c +++ b/src/vnet/vxlan/vxlan.c @@ -442,29 +442,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) + 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 +503,10 @@ int vnet_vxlan_add_del_tunnel if (add_failed) { - ethernet_delete_interface (vnm, t->hw_if_index); + if (a->is_l3) + 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; @@ -647,7 +655,11 @@ int vnet_vxlan_add_del_tunnel mcast_shared_remove (&t->dst); } - ethernet_delete_interface (vnm, t->hw_if_index); + vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, t->hw_if_index); + if (hw->dev_class_index == vxlan_device_class.index) + 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 +729,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 +777,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 +801,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 +841,12 @@ 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, + .is_l3 = is_l3, + .instance = instance, #define _(x) .x = x, - foreach_copy_field + foreach_copy_field #undef _ }; @@ -893,7 +915,7 @@ VLIB_CLI_COMMAND (create_vxlan_tunnel_command, static) = { "create vxlan tunnel src " " {dst |group } vni " " [instance ]" - " [encap-vrf-id ] [decap-next [l2|node ]] [del]" + " [encap-vrf-id ] [decap-next [l2|node ]] [del] [l3]" " [src_port ] [dst_port ]", .function = vxlan_add_del_tunnel_command_fn, }; diff --git a/src/vnet/vxlan/vxlan.h b/src/vnet/vxlan/vxlan.h index 129bb43291b..be819ab1069 100644 --- a/src/vnet/vxlan/vxlan.h +++ b/src/vnet/vxlan/vxlan.h @@ -214,6 +214,7 @@ typedef struct /* we normally use is_ip4, but since this adds to the * structure, this seems less of a breaking change */ u8 is_ip6; + u8 is_l3; u32 instance; ip46_address_t src, dst; u32 mcast_sw_if_index; diff --git a/src/vnet/vxlan/vxlan_api.c b/src/vnet/vxlan/vxlan_api.c index 6975d834e2a..381bb832f7a 100644 --- a/src/vnet/vxlan/vxlan_api.c +++ b/src/vnet/vxlan/vxlan_api.c @@ -52,6 +52,7 @@ _ (VXLAN_ADD_DEL_TUNNEL, vxlan_add_del_tunnel) \ _ (VXLAN_TUNNEL_DUMP, vxlan_tunnel_dump) \ _ (VXLAN_ADD_DEL_TUNNEL_V2, vxlan_add_del_tunnel_v2) \ + _ (VXLAN_ADD_DEL_TUNNEL_V3, vxlan_add_del_tunnel_v3) \ _ (VXLAN_TUNNEL_V2_DUMP, vxlan_tunnel_v2_dump) \ _ (VXLAN_OFFLOAD_RX, vxlan_offload_rx) @@ -124,62 +125,58 @@ static void REPLY_MACRO (VL_API_SW_INTERFACE_SET_VXLAN_BYPASS_REPLY); } -static void vl_api_vxlan_add_del_tunnel_t_handler - (vl_api_vxlan_add_del_tunnel_t * mp) +static int +vxlan_add_del_tunnel_clean_input (vnet_vxlan_add_del_tunnel_args_t *a, + u32 encap_vrf_id) { - vl_api_vxlan_add_del_tunnel_reply_t *rmp; - int rv = 0; - bool is_ipv6; - u32 fib_index; - ip46_address_t src, dst; + a->is_ip6 = !ip46_address_is_ip4 (&a->src); - ip_address_decode (&mp->src_address, &src); - ip_address_decode (&mp->dst_address, &dst); - - if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst)) + a->encap_fib_index = fib_table_find (fib_ip_proto (a->is_ip6), encap_vrf_id); + if (a->encap_fib_index == ~0) { - rv = VNET_API_ERROR_INVALID_VALUE; - goto out; + return VNET_API_ERROR_NO_SUCH_FIB; } - is_ipv6 = !ip46_address_is_ip4 (&src); + if (ip46_address_is_ip4 (&a->src) != ip46_address_is_ip4 (&a->dst)) + { + return VNET_API_ERROR_INVALID_VALUE; + } - fib_index = fib_table_find (fib_ip_proto (is_ipv6), - ntohl (mp->encap_vrf_id)); - if (fib_index == ~0) + /* Check src & dst are different */ + if (ip46_address_cmp (&a->dst, &a->src) == 0) { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; + return VNET_API_ERROR_SAME_SRC_DST; } + if (ip46_address_is_multicast (&a->dst) && + !vnet_sw_if_index_is_api_valid (a->mcast_sw_if_index)) + { + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + } + return 0; +} + +static void +vl_api_vxlan_add_del_tunnel_t_handler (vl_api_vxlan_add_del_tunnel_t *mp) +{ + vl_api_vxlan_add_del_tunnel_reply_t *rmp; + u32 sw_if_index = ~0; + int rv = 0; vnet_vxlan_add_del_tunnel_args_t a = { .is_add = mp->is_add, - .is_ip6 = is_ipv6, .instance = ntohl (mp->instance), .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index), - .encap_fib_index = fib_index, .decap_next_index = ntohl (mp->decap_next_index), .vni = ntohl (mp->vni), - .dst = dst, - .src = src, - .dst_port = is_ipv6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan, - .src_port = is_ipv6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan, }; - - /* Check src & dst are different */ - if (ip46_address_cmp (&a.dst, &a.src) == 0) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - if (ip46_address_is_multicast (&a.dst) && - !vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index)) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto out; - } - - u32 sw_if_index = ~0; + ip_address_decode (&mp->src_address, &a.src); + ip_address_decode (&mp->dst_address, &a.dst); + + rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id)); + if (rv) + goto out; + a.dst_port = a.is_ip6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan, + a.src_port = a.is_ip6 ? UDP_DST_PORT_vxlan6 : UDP_DST_PORT_vxlan, rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index); out: @@ -193,62 +190,58 @@ static void vl_api_vxlan_add_del_tunnel_v2_t_handler (vl_api_vxlan_add_del_tunnel_v2_t *mp) { vl_api_vxlan_add_del_tunnel_v2_reply_t *rmp; + u32 sw_if_index = ~0; int rv = 0; - bool is_ipv6; - u32 fib_index; - ip46_address_t src, dst; - ip_address_decode (&mp->src_address, &src); - ip_address_decode (&mp->dst_address, &dst); + vnet_vxlan_add_del_tunnel_args_t a = { + .is_add = mp->is_add, + .instance = ntohl (mp->instance), + .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index), + .decap_next_index = ntohl (mp->decap_next_index), + .vni = ntohl (mp->vni), + .dst_port = ntohs (mp->dst_port), + .src_port = ntohs (mp->src_port), + }; - if (ip46_address_is_ip4 (&src) != ip46_address_is_ip4 (&dst)) - { - rv = VNET_API_ERROR_INVALID_VALUE; - goto out; - } + ip_address_decode (&mp->src_address, &a.src); + ip_address_decode (&mp->dst_address, &a.dst); - is_ipv6 = !ip46_address_is_ip4 (&src); + rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id)); + if (rv) + goto out; + rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index); +out: + REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V2_REPLY, + ({ rmp->sw_if_index = ntohl (sw_if_index); })); +} - fib_index = - fib_table_find (fib_ip_proto (is_ipv6), ntohl (mp->encap_vrf_id)); - if (fib_index == ~0) - { - rv = VNET_API_ERROR_NO_SUCH_FIB; - goto out; - } +static void +vl_api_vxlan_add_del_tunnel_v3_t_handler (vl_api_vxlan_add_del_tunnel_v3_t *mp) +{ + vl_api_vxlan_add_del_tunnel_v3_reply_t *rmp; + u32 sw_if_index = ~0; + int rv = 0; vnet_vxlan_add_del_tunnel_args_t a = { .is_add = mp->is_add, - .is_ip6 = is_ipv6, .instance = ntohl (mp->instance), .mcast_sw_if_index = ntohl (mp->mcast_sw_if_index), - .encap_fib_index = fib_index, .decap_next_index = ntohl (mp->decap_next_index), .vni = ntohl (mp->vni), - .dst = dst, - .src = src, .dst_port = ntohs (mp->dst_port), .src_port = ntohs (mp->src_port), + .is_l3 = mp->is_l3, }; - /* Check src & dst are different */ - if (ip46_address_cmp (&a.dst, &a.src) == 0) - { - rv = VNET_API_ERROR_SAME_SRC_DST; - goto out; - } - if (ip46_address_is_multicast (&a.dst) && - !vnet_sw_if_index_is_api_valid (a.mcast_sw_if_index)) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto out; - } + ip_address_decode (&mp->src_address, &a.src); + ip_address_decode (&mp->dst_address, &a.dst); - u32 sw_if_index = ~0; + rv = vxlan_add_del_tunnel_clean_input (&a, ntohl (mp->encap_vrf_id)); + if (rv) + goto out; rv = vnet_vxlan_add_del_tunnel (&a, &sw_if_index); - out: - REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V2_REPLY, + REPLY_MACRO2 (VL_API_VXLAN_ADD_DEL_TUNNEL_V3_REPLY, ({ rmp->sw_if_index = ntohl (sw_if_index); })); } -- 2.16.6