From ea96292985760b7fc3af54669e3eab35e7561a10 Mon Sep 17 00:00:00 2001 From: Artem Glazychev Date: Fri, 28 May 2021 19:09:14 +0700 Subject: [PATCH] vxlan-gpe: add udp-port configuration support similar behavior as here: 839dcc0fb7313638d9b8f52a9db81350dddfe461 Type: improvement Signed-off-by: Artem Glazychev Change-Id: I1b0a8f8f3dab48839e27df7065cf5f786cf0b5e9 --- src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c | 5 +- src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c | 4 +- src/vnet/vxlan-gpe/decap.c | 435 ++++++++++-------------- src/vnet/vxlan-gpe/vxlan_gpe.api | 59 +++- src/vnet/vxlan-gpe/vxlan_gpe.c | 61 ++-- src/vnet/vxlan-gpe/vxlan_gpe.h | 24 +- src/vnet/vxlan-gpe/vxlan_gpe_api.c | 147 +++++++- test/test_vxlan_gpe.py | 227 +++++++++---- test/vpp_papi_provider.py | 37 -- test/vpp_vxlan_gpe_tunnel.py | 83 +++++ 10 files changed, 687 insertions(+), 395 deletions(-) create mode 100644 test/vpp_vxlan_gpe_tunnel.py diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c index 9f6d181f0b1..d61832d975a 100644 --- a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_api.c @@ -27,6 +27,7 @@ #include #include #include +#include /* define message IDs */ #include @@ -92,7 +93,7 @@ static void vl_api_vxlan_gpe_ioam_vni_enable_t_handler clib_memcpy (&key4.remote, &mp->remote.un.ip4, sizeof (key4.remote)); vni = clib_net_to_host_u32 (mp->vni); key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; + key4.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE); p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); } @@ -141,7 +142,7 @@ static void vl_api_vxlan_gpe_ioam_vni_disable_t_handler clib_memcpy (&key4.remote, &mp->remote, sizeof (key4.remote)); vni = clib_net_to_host_u32 (mp->vni); key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; + key4.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE); p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); } diff --git a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c index 108b0c0765b..59798dc7494 100644 --- a/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c +++ b/src/plugins/ioam/lib-vxlan-gpe/vxlan_gpe_ioam.c @@ -19,6 +19,7 @@ #include #include #include +#include vxlan_gpe_ioam_main_t vxlan_gpe_ioam_main; @@ -478,7 +479,7 @@ vxlan_gpe_set_ioam_rewrite_command_fn (vlib_main_t * key4.local = local.ip4.as_u32; key4.remote = remote.ip4.as_u32; key4.vni = clib_host_to_net_u32 (vni << 8); - key4.pad = 0; + key4.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE); p = hash_get_mem (gm->vxlan4_gpe_tunnel_by_key, &key4); } else @@ -488,6 +489,7 @@ vxlan_gpe_set_ioam_rewrite_command_fn (vlib_main_t * key6.remote.as_u64[0] = remote.ip6.as_u64[0]; key6.remote.as_u64[1] = remote.ip6.as_u64[1]; key6.vni = clib_host_to_net_u32 (vni << 8); + key6.port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN6_GPE); p = hash_get_mem (gm->vxlan6_gpe_tunnel_by_key, &key6); } diff --git a/src/vnet/vxlan-gpe/decap.c b/src/vnet/vxlan-gpe/decap.c index 035e8a3fd6a..62513614389 100644 --- a/src/vnet/vxlan-gpe/decap.c +++ b/src/vnet/vxlan-gpe/decap.c @@ -79,10 +79,106 @@ format_vxlan_gpe_with_length (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 *); - return s; } +typedef struct +{ + vxlan4_gpe_tunnel_key_t key; + vxlan_gpe_decap_info_t val; +} vxlan4_gpe_tunnel_cache_t; + +static const vxlan_gpe_decap_info_t decap_not_found = { + .tunnel_index = ~0, + .next_index = VXLAN_GPE_INPUT_NEXT_DROP, + .error = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL +}; + +always_inline vxlan_gpe_decap_info_t +vxlan4_gpe_find_tunnel (vxlan_gpe_main_t *nngm, + vxlan4_gpe_tunnel_cache_t *cache, + ip4_vxlan_gpe_header_t *iuvn4_0) +{ + /* Make sure VXLAN GPE tunnel exist according to packet S/D IP, UDP port and + * VNI */ + vxlan4_gpe_tunnel_key_t key4 = { + .local = iuvn4_0->ip4.dst_address.as_u32, + .remote = iuvn4_0->ip4.src_address.as_u32, + .vni = iuvn4_0->vxlan.vni_res, + .port = (u32) iuvn4_0->udp.dst_port, + }; + + if (PREDICT_TRUE (key4.as_u64[0] == cache->key.as_u64[0] && + key4.as_u64[1] == cache->key.as_u64[1])) + { + /* cache hit */ + return cache->val; + } + + uword *p = hash_get_mem (nngm->vxlan4_gpe_tunnel_by_key, &key4); + if (PREDICT_TRUE (p != 0)) + { + u32 next = (iuvn4_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? + nngm->decap_next_node_list[iuvn4_0->vxlan.protocol] : + VXLAN_GPE_INPUT_NEXT_DROP; + + cache->key.as_u64[0] = key4.as_u64[0]; + cache->key.as_u64[1] = key4.as_u64[1]; + + cache->val.error = 0; + cache->val.tunnel_index = p[0]; + cache->val.next_index = next; + + return cache->val; + } + + return decap_not_found; +} + +typedef struct +{ + vxlan6_gpe_tunnel_key_t key; + vxlan_gpe_decap_info_t val; +} vxlan6_gpe_tunnel_cache_t; + +always_inline vxlan_gpe_decap_info_t +vxlan6_gpe_find_tunnel (vxlan_gpe_main_t *nngm, + vxlan6_gpe_tunnel_cache_t *cache, + ip6_vxlan_gpe_header_t *iuvn6_0) +{ + /* Make sure VXLAN GPE tunnel exist according to packet S/D IP, UDP port and + * VNI */ + vxlan6_gpe_tunnel_key_t key6; + + ip6_address_copy (&key6.local, &iuvn6_0->ip6.dst_address); + ip6_address_copy (&key6.remote, &iuvn6_0->ip6.src_address); + key6.vni = iuvn6_0->vxlan.vni_res; + key6.port = iuvn6_0->udp.dst_port; + + if (PREDICT_TRUE (memcmp (&key6, &cache->key, sizeof (cache->key)) == 0)) + { + /* cache hit */ + return cache->val; + } + + uword *p = hash_get_mem (nngm->vxlan6_gpe_tunnel_by_key, &key6); + if (PREDICT_TRUE (p != 0)) + { + u32 next = (iuvn6_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? + nngm->decap_next_node_list[iuvn6_0->vxlan.protocol] : + VXLAN_GPE_INPUT_NEXT_DROP; + + clib_memcpy_fast (&cache->key, &key6, sizeof (key6)); + cache->val.error = 0; + cache->val.tunnel_index = p[0]; + cache->val.next_index = next; + + return cache->val; + } + + return decap_not_found; +} + /** * @brief Common processing for IPv4 and IPv6 VXLAN GPE decap dispatch functions * @@ -111,17 +207,16 @@ vxlan_gpe_input (vlib_main_t * vm, vxlan_gpe_main_t *nngm = &vxlan_gpe_main; vnet_main_t *vnm = nngm->vnet_main; vnet_interface_main_t *im = &vnm->interface_main; - u32 last_tunnel_index = ~0; - vxlan4_gpe_tunnel_key_t last_key4; - vxlan6_gpe_tunnel_key_t last_key6; + vxlan4_gpe_tunnel_cache_t last4; + vxlan6_gpe_tunnel_cache_t last6; u32 pkts_decapsulated = 0; u32 thread_index = vm->thread_index; u32 stats_sw_if_index, stats_n_packets, stats_n_bytes; if (is_ip4) - clib_memset (&last_key4, 0xff, sizeof (last_key4)); + clib_memset (&last4, 0xff, sizeof (last4)); else - clib_memset (&last_key6, 0xff, sizeof (last_key6)); + clib_memset (&last6, 0xff, sizeof (last6)); from = vlib_frame_vector_args (from_frame); n_left_from = from_frame->n_vectors; @@ -143,11 +238,8 @@ vxlan_gpe_input (vlib_main_t * vm, u32 next0, next1; ip4_vxlan_gpe_header_t *iuvn4_0, *iuvn4_1; ip6_vxlan_gpe_header_t *iuvn6_0, *iuvn6_1; - uword *p0, *p1; - u32 tunnel_index0, tunnel_index1; + vxlan_gpe_decap_info_t di0, di1; vxlan_gpe_tunnel_t *t0, *t1; - vxlan4_gpe_tunnel_key_t key4_0, key4_1; - vxlan6_gpe_tunnel_key_t key6_0, key6_1; u32 error0, error1; u32 sw_if_index0, sw_if_index1, len0, len1; @@ -193,6 +285,9 @@ vxlan_gpe_input (vlib_main_t * vm, /* pop (ip, udp, vxlan) */ vlib_buffer_advance (b0, sizeof (*iuvn4_0)); vlib_buffer_advance (b1, sizeof (*iuvn4_1)); + + di0 = vxlan4_gpe_find_tunnel (nngm, &last4, iuvn4_0); + di1 = vxlan4_gpe_find_tunnel (nngm, &last4, iuvn4_1); } else { @@ -210,125 +305,20 @@ vxlan_gpe_input (vlib_main_t * vm, /* pop (ip, udp, vxlan) */ vlib_buffer_advance (b0, sizeof (*iuvn6_0)); vlib_buffer_advance (b1, sizeof (*iuvn6_1)); - } - tunnel_index0 = ~0; - tunnel_index1 = ~0; - error0 = 0; - error1 = 0; - - if (is_ip4) - { - next0 = - (iuvn4_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn4_0->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - next1 = - (iuvn4_1->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn4_1->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - - key4_0.local = iuvn4_0->ip4.dst_address.as_u32; - key4_1.local = iuvn4_1->ip4.dst_address.as_u32; - - key4_0.remote = iuvn4_0->ip4.src_address.as_u32; - key4_1.remote = iuvn4_1->ip4.src_address.as_u32; - - key4_0.vni = iuvn4_0->vxlan.vni_res; - key4_1.vni = iuvn4_1->vxlan.vni_res; - - key4_0.pad = 0; - key4_1.pad = 0; + di0 = vxlan6_gpe_find_tunnel (nngm, &last6, iuvn6_0); + di1 = vxlan6_gpe_find_tunnel (nngm, &last6, iuvn6_1); } - else /* is_ip6 */ - { - next0 = (iuvn6_0->vxlan.protocol < node->n_next_nodes) ? - iuvn6_0->vxlan.protocol : VXLAN_GPE_INPUT_NEXT_DROP; - next1 = (iuvn6_1->vxlan.protocol < node->n_next_nodes) ? - iuvn6_1->vxlan.protocol : VXLAN_GPE_INPUT_NEXT_DROP; - - key6_0.local.as_u64[0] = iuvn6_0->ip6.dst_address.as_u64[0]; - key6_0.local.as_u64[1] = iuvn6_0->ip6.dst_address.as_u64[1]; - key6_1.local.as_u64[0] = iuvn6_1->ip6.dst_address.as_u64[0]; - key6_1.local.as_u64[1] = iuvn6_1->ip6.dst_address.as_u64[1]; - - key6_0.remote.as_u64[0] = iuvn6_0->ip6.src_address.as_u64[0]; - key6_0.remote.as_u64[1] = iuvn6_0->ip6.src_address.as_u64[1]; - key6_1.remote.as_u64[0] = iuvn6_1->ip6.src_address.as_u64[0]; - key6_1.remote.as_u64[1] = iuvn6_1->ip6.src_address.as_u64[1]; - - key6_0.vni = iuvn6_0->vxlan.vni_res; - key6_1.vni = iuvn6_1->vxlan.vni_res; - } - - /* Processing packet 0 */ - if (is_ip4) - { - /* Processing for key4_0 */ - if (PREDICT_FALSE ((key4_0.as_u64[0] != last_key4.as_u64[0]) - || (key4_0.as_u64[1] != - last_key4.as_u64[1]))) - { - p0 = hash_get_mem (nngm->vxlan4_gpe_tunnel_by_key, &key4_0); - - if (p0 == 0) - { - error0 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace0; - } - last_key4.as_u64[0] = key4_0.as_u64[0]; - last_key4.as_u64[1] = key4_0.as_u64[1]; - tunnel_index0 = last_tunnel_index = p0[0]; - } - else - tunnel_index0 = last_tunnel_index; - } - else /* is_ip6 */ + /* Process packet 0 */ + next0 = di0.next_index; + error0 = di0.error; + if (error0 != 0) { - next0 = - (iuvn6_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn6_0->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - next1 = - (iuvn6_1->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn6_1->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - - key6_0.local.as_u64[0] = iuvn6_0->ip6.dst_address.as_u64[0]; - key6_0.local.as_u64[1] = iuvn6_0->ip6.dst_address.as_u64[1]; - key6_1.local.as_u64[0] = iuvn6_1->ip6.dst_address.as_u64[0]; - key6_1.local.as_u64[1] = iuvn6_1->ip6.dst_address.as_u64[1]; - - key6_0.remote.as_u64[0] = iuvn6_0->ip6.src_address.as_u64[0]; - key6_0.remote.as_u64[1] = iuvn6_0->ip6.src_address.as_u64[1]; - key6_1.remote.as_u64[0] = iuvn6_1->ip6.src_address.as_u64[0]; - key6_1.remote.as_u64[1] = iuvn6_1->ip6.src_address.as_u64[1]; - - key6_0.vni = iuvn6_0->vxlan.vni_res; - key6_1.vni = iuvn6_1->vxlan.vni_res; - - /* Processing for key6_0 */ - if (PREDICT_FALSE - (memcmp (&key6_0, &last_key6, sizeof (last_key6)) != 0)) - { - p0 = hash_get_mem (nngm->vxlan6_gpe_tunnel_by_key, &key6_0); - - if (p0 == 0) - { - error0 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace0; - } - - memcpy (&last_key6, &key6_0, sizeof (key6_0)); - tunnel_index0 = last_tunnel_index = p0[0]; - } - else - tunnel_index0 = last_tunnel_index; + goto trace0; } - t0 = pool_elt_at_index (nngm->tunnels, tunnel_index0); - + t0 = pool_elt_at_index (nngm->tunnels, di0.tunnel_index); sw_if_index0 = t0->sw_if_index; len0 = vlib_buffer_length_in_chain (vm, b0); @@ -372,54 +362,18 @@ vxlan_gpe_input (vlib_main_t * vm, vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->next_index = next0; tr->error = error0; - tr->tunnel_index = tunnel_index0; + tr->tunnel_index = di0.tunnel_index; } /* Process packet 1 */ - if (is_ip4) + next1 = di1.next_index; + error1 = di1.error; + if (error1 != 0) { - /* Processing for key4_1 */ - if (PREDICT_FALSE ((key4_1.as_u64[0] != last_key4.as_u64[0]) - || (key4_1.as_u64[1] != - last_key4.as_u64[1]))) - { - p1 = hash_get_mem (nngm->vxlan4_gpe_tunnel_by_key, &key4_1); - - if (p1 == 0) - { - error1 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace1; - } - - last_key4.as_u64[0] = key4_1.as_u64[0]; - last_key4.as_u64[1] = key4_1.as_u64[1]; - tunnel_index1 = last_tunnel_index = p1[0]; - } - else - tunnel_index1 = last_tunnel_index; + goto trace1; } - else /* is_ip6 */ - { - /* Processing for key6_1 */ - if (PREDICT_FALSE - (memcmp (&key6_1, &last_key6, sizeof (last_key6)) != 0)) - { - p1 = hash_get_mem (nngm->vxlan6_gpe_tunnel_by_key, &key6_1); - if (p1 == 0) - { - error1 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace1; - } - - memcpy (&last_key6, &key6_1, sizeof (key6_1)); - tunnel_index1 = last_tunnel_index = p1[0]; - } - else - tunnel_index1 = last_tunnel_index; - } - - t1 = pool_elt_at_index (nngm->tunnels, tunnel_index1); + t1 = pool_elt_at_index (nngm->tunnels, di1.tunnel_index); sw_if_index1 = t1->sw_if_index; len1 = vlib_buffer_length_in_chain (vm, b1); @@ -466,7 +420,7 @@ vxlan_gpe_input (vlib_main_t * vm, vlib_add_trace (vm, node, b1, sizeof (*tr)); tr->next_index = next1; tr->error = error1; - tr->tunnel_index = tunnel_index1; + tr->tunnel_index = di1.tunnel_index; } vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next, @@ -481,11 +435,8 @@ vxlan_gpe_input (vlib_main_t * vm, u32 next0; ip4_vxlan_gpe_header_t *iuvn4_0; ip6_vxlan_gpe_header_t *iuvn6_0; - uword *p0; - u32 tunnel_index0; + vxlan_gpe_decap_info_t di0; vxlan_gpe_tunnel_t *t0; - vxlan4_gpe_tunnel_key_t key4_0; - vxlan6_gpe_tunnel_key_t key6_0; u32 error0; u32 sw_if_index0, len0; @@ -509,6 +460,8 @@ vxlan_gpe_input (vlib_main_t * vm, /* pop (ip, udp, vxlan) */ vlib_buffer_advance (b0, sizeof (*iuvn4_0)); + + di0 = vxlan4_gpe_find_tunnel (nngm, &last4, iuvn4_0); } else { @@ -521,77 +474,18 @@ vxlan_gpe_input (vlib_main_t * vm, /* pop (ip, udp, vxlan) */ vlib_buffer_advance (b0, sizeof (*iuvn6_0)); - } - - tunnel_index0 = ~0; - error0 = 0; - if (is_ip4) - { - next0 = - (iuvn4_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn4_0->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - - key4_0.local = iuvn4_0->ip4.dst_address.as_u32; - key4_0.remote = iuvn4_0->ip4.src_address.as_u32; - key4_0.vni = iuvn4_0->vxlan.vni_res; - key4_0.pad = 0; - - /* Processing for key4_0 */ - if (PREDICT_FALSE ((key4_0.as_u64[0] != last_key4.as_u64[0]) - || (key4_0.as_u64[1] != - last_key4.as_u64[1]))) - { - p0 = hash_get_mem (nngm->vxlan4_gpe_tunnel_by_key, &key4_0); - - if (p0 == 0) - { - error0 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace00; - } - - last_key4.as_u64[0] = key4_0.as_u64[0]; - last_key4.as_u64[1] = key4_0.as_u64[1]; - tunnel_index0 = last_tunnel_index = p0[0]; + di0 = vxlan6_gpe_find_tunnel (nngm, &last6, iuvn6_0); } - else - tunnel_index0 = last_tunnel_index; - } - else /* is_ip6 */ - { - next0 = - (iuvn6_0->vxlan.protocol < VXLAN_GPE_PROTOCOL_MAX) ? - nngm->decap_next_node_list[iuvn6_0->vxlan.protocol] : - VXLAN_GPE_INPUT_NEXT_DROP; - - key6_0.local.as_u64[0] = iuvn6_0->ip6.dst_address.as_u64[0]; - key6_0.local.as_u64[1] = iuvn6_0->ip6.dst_address.as_u64[1]; - key6_0.remote.as_u64[0] = iuvn6_0->ip6.src_address.as_u64[0]; - key6_0.remote.as_u64[1] = iuvn6_0->ip6.src_address.as_u64[1]; - key6_0.vni = iuvn6_0->vxlan.vni_res; - - /* Processing for key6_0 */ - if (PREDICT_FALSE - (memcmp (&key6_0, &last_key6, sizeof (last_key6)) != 0)) - { - p0 = hash_get_mem (nngm->vxlan6_gpe_tunnel_by_key, &key6_0); - - if (p0 == 0) - { - error0 = VXLAN_GPE_ERROR_NO_SUCH_TUNNEL; - goto trace00; - } - memcpy (&last_key6, &key6_0, sizeof (key6_0)); - tunnel_index0 = last_tunnel_index = p0[0]; - } - else - tunnel_index0 = last_tunnel_index; + next0 = di0.next_index; + error0 = di0.error; + if (error0 != 0) + { + goto trace00; } - t0 = pool_elt_at_index (nngm->tunnels, tunnel_index0); - + t0 = pool_elt_at_index (nngm->tunnels, di0.tunnel_index); sw_if_index0 = t0->sw_if_index; len0 = vlib_buffer_length_in_chain (vm, b0); @@ -637,7 +531,7 @@ vxlan_gpe_input (vlib_main_t * vm, vlib_add_trace (vm, node, b0, sizeof (*tr)); tr->next_index = next0; tr->error = error0; - tr->tunnel_index = tunnel_index0; + tr->tunnel_index = di0.tunnel_index; } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, bi0, next0); @@ -794,6 +688,9 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, matching a local VTEP address */ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs; + vxlan4_gpe_tunnel_cache_t last4; + vxlan6_gpe_tunnel_cache_t last6; + from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; next_index = node->cached_next_index; @@ -804,9 +701,15 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, ip4_forward_next_trace (vm, node, frame, VLIB_TX); if (is_ip4) - vtep4_key_init (&last_vtep4); + { + vtep4_key_init (&last_vtep4); + clib_memset (&last4, 0xff, sizeof last4); + } else - vtep6_key_init (&last_vtep6); + { + vtep6_key_init (&last_vtep6); + clib_memset (&last6, 0xff, sizeof last6); + } while (n_left_from > 0) { @@ -818,6 +721,9 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, ip4_header_t *ip40, *ip41; ip6_header_t *ip60, *ip61; udp_header_t *udp0, *udp1; + ip4_vxlan_gpe_header_t *iuvn4_0, *iuvn4_1; + ip6_vxlan_gpe_header_t *iuvn6_0, *iuvn6_1; + vxlan_gpe_decap_info_t di0, di1; u32 bi0, ip_len0, udp_len0, flags0, next0; u32 bi1, ip_len1, udp_len1, flags1, next1; i32 len_diff0, len_diff1; @@ -874,12 +780,20 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, goto exit0; /* not UDP packet */ if (is_ip4) - udp0 = ip4_next_header (ip40); + { + udp0 = ip4_next_header (ip40); + iuvn4_0 = vlib_buffer_get_current (b0); + di0 = vxlan4_gpe_find_tunnel (ngm, &last4, iuvn4_0); + } else - udp0 = ip6_next_header (ip60); + { + udp0 = ip6_next_header (ip60); + iuvn6_0 = vlib_buffer_get_current (b0); + di0 = vxlan6_gpe_find_tunnel (ngm, &last6, iuvn6_0); + } - if (udp0->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE)) - goto exit0; /* not VXLAN packet */ + if (PREDICT_FALSE (di0.tunnel_index == ~0)) + goto exit0; /* unknown interface */ /* Validate DIP against VTEPs */ if (is_ip4) @@ -957,12 +871,20 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, goto exit1; /* not UDP packet */ if (is_ip4) - udp1 = ip4_next_header (ip41); + { + udp1 = ip4_next_header (ip41); + iuvn4_1 = vlib_buffer_get_current (b1); + di1 = vxlan4_gpe_find_tunnel (ngm, &last4, iuvn4_1); + } else - udp1 = ip6_next_header (ip61); + { + udp1 = ip6_next_header (ip61); + iuvn6_1 = vlib_buffer_get_current (b1); + di1 = vxlan6_gpe_find_tunnel (ngm, &last6, iuvn6_1); + } - if (udp1->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE)) - goto exit1; /* not VXLAN packet */ + if (PREDICT_FALSE (di1.tunnel_index == ~0)) + goto exit1; /* unknown interface */ /* Validate DIP against VTEPs */ if (is_ip4) @@ -1046,6 +968,9 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, ip4_header_t *ip40; ip6_header_t *ip60; udp_header_t *udp0; + ip4_vxlan_gpe_header_t *iuvn4_0; + ip6_vxlan_gpe_header_t *iuvn6_0; + vxlan_gpe_decap_info_t di0; u32 bi0, ip_len0, udp_len0, flags0, next0; i32 len_diff0; u8 error0, good_udp0, proto0; @@ -1075,12 +1000,20 @@ ip_vxlan_gpe_bypass_inline (vlib_main_t * vm, goto exit; /* not UDP packet */ if (is_ip4) - udp0 = ip4_next_header (ip40); + { + udp0 = ip4_next_header (ip40); + iuvn4_0 = vlib_buffer_get_current (b0); + di0 = vxlan4_gpe_find_tunnel (ngm, &last4, iuvn4_0); + } else - udp0 = ip6_next_header (ip60); + { + udp0 = ip6_next_header (ip60); + iuvn6_0 = vlib_buffer_get_current (b0); + di0 = vxlan6_gpe_find_tunnel (ngm, &last6, iuvn6_0); + } - if (udp0->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE)) - goto exit; /* not VXLAN packet */ + if (PREDICT_FALSE (di0.tunnel_index == ~0)) + goto exit; /* unknown interface */ /* Validate DIP against VTEPs */ diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.api b/src/vnet/vxlan-gpe/vxlan_gpe.api index 35d8c642192..3cbd7ab7f71 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.api +++ b/src/vnet/vxlan-gpe/vxlan_gpe.api @@ -13,7 +13,7 @@ * limitations under the License. */ -option version = "2.0.0"; +option version = "2.1.0"; import "vnet/interface_types.api"; import "vnet/ip/ip_types.api"; @@ -32,12 +32,48 @@ define vxlan_gpe_add_del_tunnel bool is_add [default=true]; }; +/** \brief Create or delete a VXLAN-GPE tunnel + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param local - Source IP address + @param remote - Destination IP address, can be multicast + @param local_port - Source UDP port. It is not included in sent packets. Used only for port registration + @param remote_port - Destination UDP port + @param mcast_sw_if_index - Interface for multicast destination + @param encap_vrf_id - Encap route table FIB index + @param decap_vrf_id - Decap route table FIB index + @param protocol - Encapsulated protocol + @param vni - The VXLAN Network Identifier, uint24 + @param is_add - Use 1 to create the tunnel, 0 to remove it +*/ +define vxlan_gpe_add_del_tunnel_v2 +{ + u32 client_index; + u32 context; + vl_api_address_t local; + vl_api_address_t remote; + u16 local_port; + u16 remote_port; + vl_api_interface_index_t mcast_sw_if_index; + u32 encap_vrf_id; + u32 decap_vrf_id; + vl_api_ip_proto_t protocol; + u32 vni; + bool is_add [default=true]; +}; + define vxlan_gpe_add_del_tunnel_reply { u32 context; i32 retval; vl_api_interface_index_t sw_if_index; }; +define vxlan_gpe_add_del_tunnel_v2_reply +{ + u32 context; + i32 retval; + vl_api_interface_index_t sw_if_index; +}; define vxlan_gpe_tunnel_dump { @@ -45,6 +81,12 @@ define vxlan_gpe_tunnel_dump u32 context; vl_api_interface_index_t sw_if_index; }; +define vxlan_gpe_tunnel_v2_dump +{ + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; +}; define vxlan_gpe_tunnel_details { @@ -59,6 +101,21 @@ define vxlan_gpe_tunnel_details u32 decap_vrf_id; bool is_ipv6; }; +define vxlan_gpe_tunnel_v2_details +{ + u32 context; + vl_api_interface_index_t sw_if_index; + vl_api_address_t local; + vl_api_address_t remote; + u16 local_port; + u16 remote_port; + u32 vni; + vl_api_ip_proto_t protocol; + vl_api_interface_index_t mcast_sw_if_index; + u32 encap_vrf_id; + u32 decap_vrf_id; + bool is_ipv6; +}; /** \brief Interface set vxlan-gpe-bypass request @param client_index - opaque cookie to identify the sender diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.c b/src/vnet/vxlan-gpe/vxlan_gpe.c index 6fd0561099b..17ffcadcd9f 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.c +++ b/src/vnet/vxlan-gpe/vxlan_gpe.c @@ -87,11 +87,12 @@ format_vxlan_gpe_tunnel (u8 * s, va_list * args) vxlan_gpe_tunnel_t *t = va_arg (*args, vxlan_gpe_tunnel_t *); vxlan_gpe_main_t *ngm = &vxlan_gpe_main; - s = format (s, "[%d] lcl %U rmt %U vni %d fib-idx %d sw-if-idx %d ", - t - ngm->tunnels, - format_ip46_address, &t->local, IP46_TYPE_ANY, - format_ip46_address, &t->remote, IP46_TYPE_ANY, - t->vni, t->encap_fib_index, t->sw_if_index); + s = format (s, + "[%d] lcl %U rmt %U lcl_port %d rmt_port %d vni %d " + "fib-idx %d sw-if-idx %d ", + t - ngm->tunnels, format_ip46_address, &t->local, IP46_TYPE_ANY, + format_ip46_address, &t->remote, IP46_TYPE_ANY, t->local_port, + t->remote_port, t->vni, t->encap_fib_index, t->sw_if_index); #if 0 /* next_dpo not yet used by vxlan-gpe-encap node */ @@ -248,12 +249,14 @@ const static fib_node_vft_t vxlan_gpe_vft = { .fnv_back_walk = vxlan_gpe_tunnel_back_walk, }; -#define foreach_gpe_copy_field \ -_(vni) \ -_(protocol) \ -_(mcast_sw_if_index) \ -_(encap_fib_index) \ -_(decap_fib_index) +#define foreach_gpe_copy_field \ + _ (vni) \ + _ (protocol) \ + _ (mcast_sw_if_index) \ + _ (encap_fib_index) \ + _ (decap_fib_index) \ + _ (local_port) \ + _ (remote_port) #define foreach_copy_ipv4 { \ _(local.ip4.as_u32) \ @@ -304,8 +307,8 @@ vxlan4_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size, ip0->checksum = ip4_header_checksum (ip0); /* UDP header, randomize src port on something, maybe? */ - h0->udp.src_port = clib_host_to_net_u16 (4790); - h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE); + h0->udp.src_port = clib_host_to_net_u16 (t->local_port); + h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port); /* VXLAN header. Are we having fun yet? */ h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P; @@ -363,8 +366,8 @@ vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size, ip0->dst_address.as_u64[1] = t->remote.ip6.as_u64[1]; /* UDP header, randomize src port on something, maybe? */ - h0->udp.src_port = clib_host_to_net_u16 (4790); - h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_VXLAN_GPE); + h0->udp.src_port = clib_host_to_net_u16 (t->local_port); + h0->udp.dst_port = clib_host_to_net_u16 (t->remote_port); /* VXLAN header. Are we having fun yet? */ h0->vxlan.flags = VXLAN_GPE_FLAGS_I | VXLAN_GPE_FLAGS_P; @@ -453,12 +456,19 @@ int vnet_vxlan_gpe_add_del_tunnel vxlan6_gpe_tunnel_key_t key6, *key6_copy; u32 is_ip6 = a->is_ip6; + /* Set udp-ports */ + if (a->local_port == 0) + a->local_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE; + + if (a->remote_port == 0) + a->remote_port = is_ip6 ? UDP_DST_PORT_VXLAN6_GPE : UDP_DST_PORT_VXLAN_GPE; + if (!is_ip6) { key4.local = a->local.ip4.as_u32; key4.remote = a->remote.ip4.as_u32; key4.vni = clib_host_to_net_u32 (a->vni << 8); - key4.pad = 0; + key4.port = (u32) clib_host_to_net_u16 (a->local_port); p = hash_get_mem (ngm->vxlan4_gpe_tunnel_by_key, &key4); } @@ -469,6 +479,7 @@ int vnet_vxlan_gpe_add_del_tunnel key6.remote.as_u64[0] = a->remote.ip6.as_u64[0]; key6.remote.as_u64[1] = a->remote.ip6.as_u64[1]; key6.vni = clib_host_to_net_u32 (a->vni << 8); + key6.port = (u32) clib_host_to_net_u16 (a->local_port); p = hash_get_mem (ngm->vxlan6_gpe_tunnel_by_key, &key6); } @@ -719,12 +730,12 @@ int vnet_vxlan_gpe_add_del_tunnel if (a->is_add) { /* register udp ports */ - if (!is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_VXLAN_GPE, 1)) - udp_register_dst_port (ngm->vlib_main, UDP_DST_PORT_VXLAN_GPE, - vxlan4_gpe_input_node.index, 1 /* is_ip4 */ ); - if (is_ip6 && !udp_is_valid_dst_port (UDP_DST_PORT_VXLAN6_GPE, 0)) - udp_register_dst_port (ngm->vlib_main, UDP_DST_PORT_VXLAN6_GPE, - vxlan6_gpe_input_node.index, 0 /* is_ip4 */ ); + if (!is_ip6 && !udp_is_valid_dst_port (a->local_port, 1)) + udp_register_dst_port (ngm->vlib_main, a->local_port, + vxlan4_gpe_input_node.index, 1 /* is_ip4 */); + if (is_ip6 && !udp_is_valid_dst_port (a->remote_port, 0)) + udp_register_dst_port (ngm->vlib_main, a->remote_port, + vxlan6_gpe_input_node.index, 0 /* is_ip4 */); } return 0; @@ -749,6 +760,8 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, u8 protocol = VXLAN_GPE_PROTOCOL_IP4; u32 vni; u8 vni_set = 0; + u32 local_port = 0; + u32 remote_port = 0; int rv; u32 tmp; vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a; @@ -833,6 +846,10 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, } else if (unformat (line_input, "vni %d", &vni)) vni_set = 1; + else if (unformat (line_input, "local_port %d", &local_port)) + ; + else if (unformat (line_input, "remote_port %d", &remote_port)) + ; else if (unformat (line_input, "next-ip4")) protocol = VXLAN_GPE_PROTOCOL_IP4; else if (unformat (line_input, "next-ip6")) diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.h b/src/vnet/vxlan-gpe/vxlan_gpe.h index 0f8250a1788..5d21ee66d67 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.h +++ b/src/vnet/vxlan-gpe/vxlan_gpe.h @@ -64,7 +64,7 @@ typedef CLIB_PACKED (struct { /** * @brief Key struct for IPv4 VXLAN GPE tunnel. - * Key fields: local remote, vni + * Key fields: local remote, vni, udp-port * all fields in NET byte order * VNI shifted 8 bits */ @@ -76,7 +76,7 @@ typedef CLIB_PACKED(struct { u32 remote; u32 vni; - u32 pad; + u32 port; }; u64 as_u64[2]; }; @@ -85,7 +85,7 @@ typedef CLIB_PACKED(struct { /** * @brief Key struct for IPv6 VXLAN GPE tunnel. - * Key fields: local remote, vni + * Key fields: local remote, vni, udp-port * all fields in NET byte order * VNI shifted 8 bits */ @@ -94,9 +94,21 @@ typedef CLIB_PACKED(struct { ip6_address_t local; ip6_address_t remote; u32 vni; + u32 port; }) vxlan6_gpe_tunnel_key_t; /* *INDENT-ON* */ +typedef union +{ + struct + { + u32 tunnel_index; + u16 next_index; + u8 error; + }; + u64 as_u64; +} vxlan_gpe_decap_info_t; + /** * @brief Struct for VXLAN GPE tunnel */ @@ -117,6 +129,10 @@ typedef struct ip46_address_t local; /** tunnel remote address */ ip46_address_t remote; + /** local udp-port **/ + u16 local_port; + /** remote udp-port **/ + u16 remote_port; /* mcast packet output intfc index (used only if dst is mcast) */ u32 mcast_sw_if_index; @@ -248,6 +264,8 @@ typedef struct u32 encap_fib_index; u32 decap_fib_index; u32 vni; + u16 local_port; + u16 remote_port; } vnet_vxlan_gpe_add_del_tunnel_args_t; diff --git a/src/vnet/vxlan-gpe/vxlan_gpe_api.c b/src/vnet/vxlan-gpe/vxlan_gpe_api.c index 243ddfb7fe1..9423b2745be 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe_api.c +++ b/src/vnet/vxlan-gpe/vxlan_gpe_api.c @@ -122,6 +122,73 @@ out: /* *INDENT-ON* */ } +static void +vl_api_vxlan_gpe_add_del_tunnel_v2_t_handler ( + vl_api_vxlan_gpe_add_del_tunnel_v2_t *mp) +{ + vl_api_vxlan_gpe_add_del_tunnel_v2_reply_t *rmp; + int rv = 0; + vnet_vxlan_gpe_add_del_tunnel_args_t _a, *a = &_a; + u32 encap_fib_index, decap_fib_index; + u8 protocol; + uword *p; + ip4_main_t *im = &ip4_main; + u32 sw_if_index = ~0; + + p = hash_get (im->fib_index_by_table_id, ntohl (mp->encap_vrf_id)); + if (!p) + { + rv = VNET_API_ERROR_NO_SUCH_FIB; + goto out; + } + encap_fib_index = p[0]; + + protocol = mp->protocol; + + /* Interpret decap_vrf_id as an opaque if sending to other-than-ip4-input */ + if (protocol == VXLAN_GPE_INPUT_NEXT_IP4_INPUT) + { + p = hash_get (im->fib_index_by_table_id, ntohl (mp->decap_vrf_id)); + if (!p) + { + rv = VNET_API_ERROR_NO_SUCH_INNER_FIB; + goto out; + } + decap_fib_index = p[0]; + } + else + { + decap_fib_index = ntohl (mp->decap_vrf_id); + } + + clib_memset (a, 0, sizeof (*a)); + + a->is_add = mp->is_add; + ip_address_decode (&mp->local, &a->local); + ip_address_decode (&mp->remote, &a->remote); + + /* Check src & dst are different */ + if (ip46_address_is_equal (&a->local, &a->remote)) + { + rv = VNET_API_ERROR_SAME_SRC_DST; + goto out; + } + + a->local_port = ntohs (mp->local_port); + a->remote_port = ntohs (mp->remote_port); + a->is_ip6 = !ip46_address_is_ip4 (&a->local); + a->mcast_sw_if_index = ntohl (mp->mcast_sw_if_index); + a->encap_fib_index = encap_fib_index; + a->decap_fib_index = decap_fib_index; + a->protocol = protocol; + a->vni = ntohl (mp->vni); + rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index); + +out: + REPLY_MACRO2 (VL_API_VXLAN_GPE_ADD_DEL_TUNNEL_V2_REPLY, + ({ rmp->sw_if_index = ntohl (sw_if_index); })); +} + static void send_vxlan_gpe_tunnel_details (vxlan_gpe_tunnel_t * t, vl_api_registration_t * reg, u32 context) { @@ -177,9 +244,9 @@ static void vl_api_vxlan_gpe_tunnel_dump_t_handler { /* *INDENT-OFF* */ pool_foreach (t, vgm->tunnels) - { - send_vxlan_gpe_tunnel_details(t, reg, mp->context); - } + { + send_vxlan_gpe_tunnel_details (t, reg, mp->context); + } /* *INDENT-ON* */ } else @@ -194,6 +261,80 @@ static void vl_api_vxlan_gpe_tunnel_dump_t_handler } } +static void +send_vxlan_gpe_tunnel_v2_details (vxlan_gpe_tunnel_t *t, + vl_api_registration_t *reg, u32 context) +{ + vl_api_vxlan_gpe_tunnel_v2_details_t *rmp; + ip4_main_t *im4 = &ip4_main; + ip6_main_t *im6 = &ip6_main; + u8 is_ipv6 = !(t->flags & VXLAN_GPE_TUNNEL_IS_IPV4); + + rmp = vl_msg_api_alloc (sizeof (*rmp)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->_vl_msg_id = + ntohs (REPLY_MSG_ID_BASE + VL_API_VXLAN_GPE_TUNNEL_V2_DETAILS); + + ip_address_encode (&t->local, is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, + &rmp->local); + ip_address_encode (&t->remote, is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4, + &rmp->remote); + rmp->local_port = htons (t->local_port); + rmp->remote_port = htons (t->remote_port); + + if (ip46_address_is_ip4 (&t->local)) + { + rmp->encap_vrf_id = htonl (im4->fibs[t->encap_fib_index].ft_table_id); + rmp->decap_vrf_id = htonl (im4->fibs[t->decap_fib_index].ft_table_id); + } + else + { + rmp->encap_vrf_id = htonl (im6->fibs[t->encap_fib_index].ft_table_id); + rmp->decap_vrf_id = htonl (im6->fibs[t->decap_fib_index].ft_table_id); + } + rmp->mcast_sw_if_index = htonl (t->mcast_sw_if_index); + rmp->vni = htonl (t->vni); + rmp->protocol = t->protocol; + rmp->sw_if_index = htonl (t->sw_if_index); + rmp->context = context; + + vl_api_send_msg (reg, (u8 *) rmp); +} + +static void +vl_api_vxlan_gpe_tunnel_v2_dump_t_handler ( + vl_api_vxlan_gpe_tunnel_v2_dump_t *mp) +{ + vl_api_registration_t *reg; + vxlan_gpe_main_t *vgm = &vxlan_gpe_main; + vxlan_gpe_tunnel_t *t; + u32 sw_if_index; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + sw_if_index = ntohl (mp->sw_if_index); + + if (~0 == sw_if_index) + { + pool_foreach (t, vgm->tunnels) + { + send_vxlan_gpe_tunnel_v2_details (t, reg, mp->context); + } + } + else + { + if ((sw_if_index >= vec_len (vgm->tunnel_index_by_sw_if_index)) || + (~0 == vgm->tunnel_index_by_sw_if_index[sw_if_index])) + { + return; + } + t = &vgm->tunnels[vgm->tunnel_index_by_sw_if_index[sw_if_index]]; + send_vxlan_gpe_tunnel_v2_details (t, reg, mp->context); + } +} + #include static clib_error_t * diff --git a/test/test_vxlan_gpe.py b/test/test_vxlan_gpe.py index c5d6bf07f7c..28c31ccd3bb 100644 --- a/test/test_vxlan_gpe.py +++ b/test/test_vxlan_gpe.py @@ -7,13 +7,13 @@ from framework import VppTestCase, VppTestRunner, running_extended_tests from template_bd import BridgeDomain from scapy.layers.l2 import Ether -from scapy.packet import Raw +from scapy.packet import Raw, bind_layers from scapy.layers.inet import IP, UDP from scapy.layers.vxlan import VXLAN import util from vpp_ip_route import VppIpRoute, VppRoutePath - +from vpp_vxlan_gpe_tunnel import VppVxlanGpeTunnel from vpp_ip import INVALID_INDEX @@ -79,14 +79,14 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): self.assertEqual(pkt[IP].dst, type(self).mcast_ip4) # Verify UDP destination port is VXLAN-GPE 4790, source UDP port # could be arbitrary. - self.assertEqual(pkt[UDP].dport, type(self).dport) + self.assertEqual(pkt[UDP].dport, self.dport) # Verify UDP checksum self.assert_udp_checksum_valid(pkt) # Verify VNI self.assertEqual(pkt[VXLAN].vni, vni) @classmethod - def create_vxlan_gpe_flood_test_bd(cls, vni, n_ucast_tunnels): + def create_vxlan_gpe_flood_test_bd(cls, vni, n_ucast_tunnels, port): # Create 10 ucast vxlan tunnels under bd ip_range_start = 10 ip_range_end = ip_range_start + n_ucast_tunnels @@ -100,15 +100,18 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): register=False) rip.add_vpp_config() - r = cls.vapi.vxlan_gpe_add_del_tunnel( - src_addr=cls.pg0.local_ip4, - dst_addr=dest_ip4, - vni=vni) + r = VppVxlanGpeTunnel(cls, + src_addr=cls.pg0.local_ip4, + dst_addr=dest_ip4, + src_port=port, + dst_port=port, + vni=vni) + r.add_vpp_config() cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, bd_id=vni) @classmethod - def add_del_shared_mcast_dst_load(cls, is_add): + def add_del_shared_mcast_dst_load(cls, port, is_add): """ add or del tunnels sharing the same mcast dst to test vxlan_gpe ref_count mechanism @@ -117,25 +120,30 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): vni_start = 1000 vni_end = vni_start + n_shared_dst_tunnels for vni in range(vni_start, vni_end): - r = cls.vapi.vxlan_gpe_add_del_tunnel( - local=cls.pg0.local_ip4, - remote=cls.mcast_ip4, - mcast_sw_if_index=1, - vni=vni, - is_add=is_add) - if r.sw_if_index == 0xffffffff: - raise ValueError("bad sw_if_index: ~0") + r = VppVxlanGpeTunnel(cls, + src_addr=cls.pg0.local_ip4, + dst_addr=cls.mcast_ip4, + src_port=port, + dst_port=port, + mcast_sw_if_index=1, + vni=vni) + if is_add: + r.add_vpp_config() + if r.sw_if_index == 0xffffffff: + raise ValueError("bad sw_if_index: ~0") + else: + r.remove_vpp_config() @classmethod - def add_shared_mcast_dst_load(cls): - cls.add_del_shared_mcast_dst_load(is_add=1) + def add_shared_mcast_dst_load(cls, port): + cls.add_del_shared_mcast_dst_load(port=port, is_add=1) @classmethod - def del_shared_mcast_dst_load(cls): - cls.add_del_shared_mcast_dst_load(is_add=0) + def del_shared_mcast_dst_load(cls, port): + cls.add_del_shared_mcast_dst_load(port=port, is_add=0) @classmethod - def add_del_mcast_tunnels_load(cls, is_add): + def add_del_mcast_tunnels_load(cls, port, is_add): """ add or del tunnels to test vxlan_gpe stability """ @@ -145,20 +153,25 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): for dest_ip4 in ip4_range(cls.mcast_ip4, ip_range_start, ip_range_end): vni = int(dest_ip4.split(".")[3]) - cls.vapi.vxlan_gpe_add_del_tunnel( - src_addr=cls.pg0.local_ip4, - dst_addr=dest_ip4, - mcast_sw_if_index=1, - vni=vni, - is_add=is_add) + r = VppVxlanGpeTunnel(cls, + src_addr=cls.pg0.local_ip4, + dst_addr=dest_ip4, + src_port=port, + dst_port=port, + mcast_sw_if_index=1, + vni=vni) + if is_add: + r.add_vpp_config() + else: + r.remove_vpp_config() @classmethod - def add_mcast_tunnels_load(cls): - cls.add_del_mcast_tunnels_load(is_add=1) + def add_mcast_tunnels_load(cls, port): + cls.add_del_mcast_tunnels_load(port=port, is_add=1) @classmethod - def del_mcast_tunnels_load(cls): - cls.add_del_mcast_tunnels_load(is_add=0) + def del_mcast_tunnels_load(cls, port): + cls.add_del_mcast_tunnels_load(port=port, is_add=0) # Class method to start the VXLAN-GPE test case. # Overrides setUpClass method in VppTestCase class. @@ -170,7 +183,6 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): super(TestVxlanGpe, cls).setUpClass() try: - cls.dport = 4790 cls.flags = 0x0c # Create 2 pg interfaces. @@ -187,55 +199,120 @@ class TestVxlanGpe(BridgeDomain, VppTestCase): # Our Multicast address cls.mcast_ip4 = '239.1.1.1' cls.mcast_mac = util.mcast_ip_to_mac(cls.mcast_ip4) - - # Create VXLAN-GPE VTEP on VPP pg0, and put vxlan_gpe_tunnel0 - # and pg1 into BD. - cls.single_tunnel_vni = 0xabcde - cls.single_tunnel_bd = 11 - r = cls.vapi.vxlan_gpe_add_del_tunnel( - src_addr=cls.pg0.local_ip4, - dst_addr=cls.pg0.remote_ip4, - vni=cls.single_tunnel_vni) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, - bd_id=cls.single_tunnel_bd) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg1.sw_if_index, bd_id=cls.single_tunnel_bd) - - # Setup vni 2 to test multicast flooding - cls.n_ucast_tunnels = 10 - cls.mcast_flood_bd = 12 - cls.create_vxlan_gpe_flood_test_bd(cls.mcast_flood_bd, - cls.n_ucast_tunnels) - r = cls.vapi.vxlan_gpe_add_del_tunnel( - src_addr=cls.pg0.local_ip4, - dst_addr=cls.mcast_ip4, - mcast_sw_if_index=1, - vni=cls.mcast_flood_bd) - cls.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, - bd_id=cls.mcast_flood_bd) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg2.sw_if_index, bd_id=cls.mcast_flood_bd) - - # Add and delete mcast tunnels to check stability - cls.add_shared_mcast_dst_load() - cls.add_mcast_tunnels_load() - cls.del_shared_mcast_dst_load() - cls.del_mcast_tunnels_load() - - # Setup vni 3 to test unicast flooding - cls.ucast_flood_bd = 13 - cls.create_vxlan_gpe_flood_test_bd(cls.ucast_flood_bd, - cls.n_ucast_tunnels) - cls.vapi.sw_interface_set_l2_bridge( - rx_sw_if_index=cls.pg3.sw_if_index, bd_id=cls.ucast_flood_bd) except Exception: - super(TestVxlanGpe, cls).tearDownClass() + cls.tearDownClass() raise @classmethod def tearDownClass(cls): super(TestVxlanGpe, cls).tearDownClass() + def setUp(self): + super(TestVxlanGpe, self).setUp() + + def createVxLANInterfaces(self, port=4790): + # Create VXLAN-GPE VTEP on VPP pg0, and put vxlan_gpe_tunnel0 + # and pg1 into BD. + self.dport = port + + self.single_tunnel_vni = 0xabcde + self.single_tunnel_bd = 11 + r = VppVxlanGpeTunnel(self, + src_addr=self.pg0.local_ip4, + dst_addr=self.pg0.remote_ip4, + src_port=port, + dst_port=port, + vni=self.single_tunnel_vni) + r.add_vpp_config() + self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, + bd_id=self.single_tunnel_bd) + self.vapi.sw_interface_set_l2_bridge( + rx_sw_if_index=self.pg1.sw_if_index, bd_id=self.single_tunnel_bd) + + # Setup vni 2 to test multicast flooding + self.n_ucast_tunnels = 10 + self.mcast_flood_bd = 12 + self.create_vxlan_gpe_flood_test_bd(self.mcast_flood_bd, + self.n_ucast_tunnels, + self.dport) + r = VppVxlanGpeTunnel(self, + src_addr=self.pg0.local_ip4, + dst_addr=self.mcast_ip4, + src_port=port, + dst_port=port, + mcast_sw_if_index=1, + vni=self.mcast_flood_bd) + r.add_vpp_config() + self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=r.sw_if_index, + bd_id=self.mcast_flood_bd) + self.vapi.sw_interface_set_l2_bridge( + rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.mcast_flood_bd) + + # Add and delete mcast tunnels to check stability + self.add_shared_mcast_dst_load(self.dport) + self.add_mcast_tunnels_load(self.dport) + self.del_shared_mcast_dst_load(self.dport) + self.del_mcast_tunnels_load(self.dport) + + # Setup vni 3 to test unicast flooding + self.ucast_flood_bd = 13 + self.create_vxlan_gpe_flood_test_bd(self.ucast_flood_bd, + self.n_ucast_tunnels, + self.dport) + self.vapi.sw_interface_set_l2_bridge( + rx_sw_if_index=self.pg3.sw_if_index, bd_id=self.ucast_flood_bd) + + # Set scapy listen custom port for VxLAN + bind_layers(UDP, VXLAN, dport=self.dport) + + """ + Tests with default port (4790) + """ + def test_decap(self): + """ Decapsulation test + from BridgeDoman + """ + self.createVxLANInterfaces() + super(TestVxlanGpe, self).test_decap() + + def test_encap(self): + """ Encapsulation test + from BridgeDoman + """ + self.createVxLANInterfaces() + super(TestVxlanGpe, self).test_encap() + + def test_ucast_flood(self): + """ Unicast flood test + from BridgeDoman + """ + self.createVxLANInterfaces() + super(TestVxlanGpe, self).test_ucast_flood() + + """ + Tests with custom port (1112) + """ + def test_decap_custom_port(self): + """ Decapsulation test custom port + from BridgeDoman + """ + self.createVxLANInterfaces(1112) + super(TestVxlanGpe, self).test_decap() + + def test_encap_custom_port(self): + """ Encapsulation test custom port + from BridgeDoman + """ + self.createVxLANInterfaces(1112) + super(TestVxlanGpe, self).test_encap() + + def test_ucast_flood_custom_port(self): + """ Unicast flood test custom port + from BridgeDoman + """ + self.createVxLANInterfaces(1112) + super(TestVxlanGpe, self).test_ucast_flood() + @unittest.skip("test disabled for vxlan-gpe") def test_mcast_flood(self): """ inherited from BridgeDomain """ diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 7e87b2c5cd3..0d521455abf 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -93,8 +93,6 @@ defaultmapping = { 'vxlan_add_del_tunnel': {'mcast_sw_if_index': 4294967295, 'is_add': 1, 'decap_next_index': 4294967295, 'instance': 4294967295, }, - 'vxlan_gpe_add_del_tunnel': {'mcast_sw_if_index': 4294967295, 'is_add': 1, - 'protocol': 3, }, 'want_bfd_events': {'enable_disable': 1, }, 'want_igmp_events': {'enable': 1, }, 'want_interface_events': {'enable_disable': 1, }, @@ -654,41 +652,6 @@ class VppPapiProvider(object): 'is_ip6': is_ip6 }}) - def vxlan_gpe_add_del_tunnel( - self, - src_addr, - dst_addr, - mcast_sw_if_index=0xFFFFFFFF, - is_add=1, - is_ipv6=0, - encap_vrf_id=0, - decap_vrf_id=0, - protocol=3, - vni=0): - """ - - :param local: - :param remote: - :param is_add: (Default value = 1) - :param is_ipv6: (Default value = 0) - :param encap_vrf_id: (Default value = 0) - :param decap_vrf_id: (Default value = 0) - :param mcast_sw_if_index: (Default value = 0xFFFFFFFF) - :param protocol: (Default value = 3) - :param vni: (Default value = 0) - - """ - return self.api(self.papi.vxlan_gpe_add_del_tunnel, - {'is_add': is_add, - 'is_ipv6': is_ipv6, - 'local': src_addr, - 'remote': dst_addr, - 'mcast_sw_if_index': mcast_sw_if_index, - 'encap_vrf_id': encap_vrf_id, - 'decap_vrf_id': decap_vrf_id, - 'protocol': protocol, - 'vni': vni}) - def vxlan_gbp_tunnel_dump(self, sw_if_index=0xffffffff): return self.api(self.papi.vxlan_gbp_tunnel_dump, {'sw_if_index': sw_if_index}) diff --git a/test/vpp_vxlan_gpe_tunnel.py b/test/vpp_vxlan_gpe_tunnel.py new file mode 100644 index 00000000000..cff5e456aee --- /dev/null +++ b/test/vpp_vxlan_gpe_tunnel.py @@ -0,0 +1,83 @@ +from vpp_interface import VppInterface +from vpp_papi import VppEnum + + +INDEX_INVALID = 0xffffffff +DEFAULT_PORT = 4790 +UNDEFINED_PORT = 0 + + +def find_vxlan_gpe_tunnel(test, src, dst, s_port, d_port, vni): + ts = test.vapi.vxlan_gpe_tunnel_v2_dump(INDEX_INVALID) + + src_port = DEFAULT_PORT + if s_port != UNDEFINED_PORT: + src_port = s_port + + dst_port = DEFAULT_PORT + if d_port != UNDEFINED_PORT: + dst_port = d_port + + for t in ts: + if src == str(t.local) and \ + dst == str(t.remote) and \ + src_port == t.local_port and \ + dst_port == t.remote_port and \ + t.vni == vni: + return t.sw_if_index + return INDEX_INVALID + + +class VppVxlanGpeTunnel(VppInterface): + """ + VPP VXLAN GPE interface + """ + + def __init__(self, test, src_addr, dst_addr, vni, + src_port=UNDEFINED_PORT, dst_port=UNDEFINED_PORT, + mcast_sw_if_index=INDEX_INVALID, + encap_vrf_id=None, + decap_vrf_id=None, protocol=3): + """ Create VXLAN GPE Tunnel interface """ + super(VppVxlanGpeTunnel, self).__init__(test) + self.src = src_addr + self.dst = dst_addr + self.vni = vni + self.src_port = src_port + self.dst_port = dst_port + self.mcast_sw_if_index = mcast_sw_if_index + self.encap_vrf_id = encap_vrf_id + self.decap_vrf_id = decap_vrf_id + self.protocol = 3 + + def add_vpp_config(self): + reply = self.test.vapi.vxlan_gpe_add_del_tunnel_v2( + is_add=1, local=self.src, remote=self.dst, vni=self.vni, + local_port=self.src_port, remote_port=self.dst_port, + mcast_sw_if_index=self.mcast_sw_if_index, + encap_vrf_id=self.encap_vrf_id, + decap_vrf_id=self.decap_vrf_id, + protocol=self.protocol) + self.set_sw_if_index(reply.sw_if_index) + self._test.registry.register(self, self._test.logger) + + def remove_vpp_config(self): + self.test.vapi.vxlan_gpe_add_del_tunnel_v2( + is_add=0, local=self.src, remote=self.dst, vni=self.vni, + local_port=self.src_port, remote_port=self.dst_port, + mcast_sw_if_index=self.mcast_sw_if_index, + encap_vrf_id=self.encap_vrf_id, + decap_vrf_id=self.decap_vrf_id, + protocol=self.protocol) + + def query_vpp_config(self): + return (INDEX_INVALID != find_vxlan_gpe_tunnel(self._test, + self.src, + self.dst, + self.src_port, + self.dst_port, + self.vni)) + + def object_id(self): + return "vxlan-%d-%d-%s-%s" % (self.sw_if_index, self.vni, + self.src, self.dst) -- 2.16.6