diff options
Diffstat (limited to 'src/vnet/vxlan-gpe')
-rw-r--r-- | src/vnet/vxlan-gpe/decap.c | 443 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/encap.c | 51 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.api | 59 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.c | 141 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.h | 34 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe_api.c | 155 |
6 files changed, 504 insertions, 379 deletions
diff --git a/src/vnet/vxlan-gpe/decap.c b/src/vnet/vxlan-gpe/decap.c index 035e8a3fd6a..d4c7424630d 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); @@ -728,7 +622,6 @@ static char *vxlan_gpe_error_strings[] = { #undef _ }; -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vxlan4_gpe_input_node) = { .name = "vxlan4-gpe-input", /* Takes a vector of packets. */ @@ -748,9 +641,7 @@ VLIB_REGISTER_NODE (vxlan4_gpe_input_node) = { .format_trace = format_vxlan_gpe_rx_trace, // $$$$ .unformat_buffer = unformat_vxlan_gpe_header, }; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vxlan6_gpe_input_node) = { .name = "vxlan6-gpe-input", /* Takes a vector of packets. */ @@ -770,7 +661,6 @@ VLIB_REGISTER_NODE (vxlan6_gpe_input_node) = { .format_trace = format_vxlan_gpe_rx_trace, // $$$$ .unformat_buffer = unformat_vxlan_gpe_header, }; -/* *INDENT-ON* */ typedef enum { @@ -794,6 +684,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 +697,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 +717,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 +776,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 +867,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 +964,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 +996,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 */ @@ -1172,7 +1101,6 @@ VLIB_NODE_FN (ip4_vxlan_gpe_bypass_node) (vlib_main_t * vm, return ip_vxlan_gpe_bypass_inline (vm, node, frame, /* is_ip4 */ 1); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip4_vxlan_gpe_bypass_node) = { .name = "ip4-vxlan-gpe-bypass", .vector_size = sizeof (u32), @@ -1186,7 +1114,6 @@ VLIB_REGISTER_NODE (ip4_vxlan_gpe_bypass_node) = { .format_buffer = format_ip4_header, .format_trace = format_ip4_forward_next_trace, }; -/* *INDENT-ON* */ #ifndef CLIB_MARCH_VARIANT /* Dummy init function to get us linked in. */ @@ -1206,7 +1133,6 @@ VLIB_NODE_FN (ip6_vxlan_gpe_bypass_node) (vlib_main_t * vm, return ip_vxlan_gpe_bypass_inline (vm, node, frame, /* is_ip4 */ 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ip6_vxlan_gpe_bypass_node) = { .name = "ip6-vxlan-gpe-bypass", .vector_size = sizeof (u32), @@ -1220,7 +1146,6 @@ VLIB_REGISTER_NODE (ip6_vxlan_gpe_bypass_node) = { .format_buffer = format_ip6_header, .format_trace = format_ip6_forward_next_trace, }; -/* *INDENT-ON* */ #ifndef CLIB_MARCH_VARIANT /* Dummy init function to get us linked in. */ diff --git a/src/vnet/vxlan-gpe/encap.c b/src/vnet/vxlan-gpe/encap.c index daa0381c4bb..a769861577d 100644 --- a/src/vnet/vxlan-gpe/encap.c +++ b/src/vnet/vxlan-gpe/encap.c @@ -88,13 +88,15 @@ format_vxlan_gpe_encap_trace (u8 * s, va_list * args) * */ always_inline void -vxlan_gpe_encap_one_inline (vxlan_gpe_main_t * ngm, vlib_buffer_t * b0, - vxlan_gpe_tunnel_t * t0, u32 * next0, u8 is_v4) +vxlan_gpe_encap_one_inline (vxlan_gpe_main_t *ngm, vlib_buffer_t *b0, + vxlan_gpe_tunnel_t *t0, u32 *next0, + ip_address_family_t af) { ASSERT (sizeof (ip4_vxlan_gpe_header_t) == 36); ASSERT (sizeof (ip6_vxlan_gpe_header_t) == 56); - ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, is_v4); + ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, af, + N_AF, UDP_ENCAP_FIXUP_NONE); next0[0] = t0->encap_next_node; } @@ -112,16 +114,18 @@ vxlan_gpe_encap_one_inline (vxlan_gpe_main_t * ngm, vlib_buffer_t * b0, * */ always_inline void -vxlan_gpe_encap_two_inline (vxlan_gpe_main_t * ngm, vlib_buffer_t * b0, - vlib_buffer_t * b1, vxlan_gpe_tunnel_t * t0, - vxlan_gpe_tunnel_t * t1, u32 * next0, - u32 * next1, u8 is_v4) +vxlan_gpe_encap_two_inline (vxlan_gpe_main_t *ngm, vlib_buffer_t *b0, + vlib_buffer_t *b1, vxlan_gpe_tunnel_t *t0, + vxlan_gpe_tunnel_t *t1, u32 *next0, u32 *next1, + ip_address_family_t af) { ASSERT (sizeof (ip4_vxlan_gpe_header_t) == 36); ASSERT (sizeof (ip6_vxlan_gpe_header_t) == 56); - ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, is_v4); - ip_udp_encap_one (ngm->vlib_main, b1, t1->rewrite, t1->rewrite_size, is_v4); + ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, t0->rewrite_size, af, + N_AF, UDP_ENCAP_FIXUP_NONE); + ip_udp_encap_one (ngm->vlib_main, b1, t1->rewrite, t1->rewrite_size, af, + N_AF, UDP_ENCAP_FIXUP_NONE); next0[0] = next1[0] = t0->encap_next_node; } @@ -170,7 +174,7 @@ vxlan_gpe_encap (vlib_main_t * vm, u32 sw_if_index0 = ~0, sw_if_index1 = ~0, len0, len1; vnet_hw_interface_t *hi0, *hi1; vxlan_gpe_tunnel_t *t0 = NULL, *t1 = NULL; - u8 is_ip4_0 = 0, is_ip4_1 = 0; + ip_address_family_t af_0 = AF_IP4, af_1 = AF_IP4; vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next); @@ -201,7 +205,7 @@ vxlan_gpe_encap (vlib_main_t * vm, n_left_to_next -= 2; n_left_from -= 2; - /* get the flag "is_ip4" */ + /* get "af_0" */ if (sw_if_index0 != vnet_buffer (b[0])->sw_if_index[VLIB_TX]) { sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; @@ -210,10 +214,10 @@ vxlan_gpe_encap (vlib_main_t * vm, vnet_buffer (b[0])->sw_if_index [VLIB_TX]); t0 = pool_elt_at_index (ngm->tunnels, hi0->dev_instance); - is_ip4_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4); + af_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4 ? AF_IP4 : AF_IP6); } - /* get the flag "is_ip4" */ + /* get "af_1" */ if (sw_if_index1 != vnet_buffer (b[1])->sw_if_index[VLIB_TX]) { if (sw_if_index0 == vnet_buffer (b[1])->sw_if_index[VLIB_TX]) @@ -221,7 +225,7 @@ vxlan_gpe_encap (vlib_main_t * vm, sw_if_index1 = sw_if_index0; hi1 = hi0; t1 = t0; - is_ip4_1 = is_ip4_0; + af_1 = af_0; } else { @@ -231,19 +235,20 @@ vxlan_gpe_encap (vlib_main_t * vm, vnet_buffer (b[1])->sw_if_index [VLIB_TX]); t1 = pool_elt_at_index (ngm->tunnels, hi1->dev_instance); - is_ip4_1 = (t1->flags & VXLAN_GPE_TUNNEL_IS_IPV4); + af_1 = + (t1->flags & VXLAN_GPE_TUNNEL_IS_IPV4 ? AF_IP4 : AF_IP6); } } - if (PREDICT_TRUE (is_ip4_0 == is_ip4_1)) + if (PREDICT_TRUE (af_0 == af_1)) { vxlan_gpe_encap_two_inline (ngm, b[0], b[1], t0, t1, &next0, - &next1, is_ip4_0); + &next1, af_0); } else { - vxlan_gpe_encap_one_inline (ngm, b[0], t0, &next0, is_ip4_0); - vxlan_gpe_encap_one_inline (ngm, b[1], t1, &next1, is_ip4_1); + vxlan_gpe_encap_one_inline (ngm, b[0], t0, &next0, af_0); + vxlan_gpe_encap_one_inline (ngm, b[1], t1, &next1, af_1); } /* Reset to look up tunnel partner in the configured FIB */ @@ -325,7 +330,7 @@ vxlan_gpe_encap (vlib_main_t * vm, n_left_from -= 1; n_left_to_next -= 1; - /* get the flag "is_ip4" */ + /* get "af_0" */ if (sw_if_index0 != vnet_buffer (b[0])->sw_if_index[VLIB_TX]) { sw_if_index0 = vnet_buffer (b[0])->sw_if_index[VLIB_TX]; @@ -336,10 +341,10 @@ vxlan_gpe_encap (vlib_main_t * vm, t0 = pool_elt_at_index (ngm->tunnels, hi0->dev_instance); - is_ip4_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4); + af_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4 ? AF_IP4 : AF_IP6); } - vxlan_gpe_encap_one_inline (ngm, b[0], t0, &next0, is_ip4_0); + vxlan_gpe_encap_one_inline (ngm, b[0], t0, &next0, af_0); /* Reset to look up tunnel partner in the configured FIB */ vnet_buffer (b[0])->sw_if_index[VLIB_TX] = t0->encap_fib_index; @@ -399,7 +404,6 @@ vxlan_gpe_encap (vlib_main_t * vm, return from_frame->n_vectors; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (vxlan_gpe_encap_node) = { .function = vxlan_gpe_encap, .name = "vxlan-gpe-encap", @@ -418,7 +422,6 @@ VLIB_REGISTER_NODE (vxlan_gpe_encap_node) = { [VXLAN_GPE_ENCAP_NEXT_DROP] = "error-drop", }, }; -/* *INDENT-ON* */ /* 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 e5ca4ec769e..5a5262ea9db 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 */ @@ -143,14 +144,12 @@ vxlan_gpe_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, return 0; } -/* *INDENT-OFF* */ VNET_DEVICE_CLASS (vxlan_gpe_device_class,static) = { .name = "VXLAN_GPE", .format_device_name = format_vxlan_gpe_name, .format_tx_trace = format_vxlan_gpe_encap_trace, .admin_up_down_function = vxlan_gpe_interface_admin_up_down, }; -/* *INDENT-ON* */ /** @@ -170,13 +169,11 @@ format_vxlan_gpe_header_with_length (u8 * s, va_list * args) return s; } -/* *INDENT-OFF* */ VNET_HW_INTERFACE_CLASS (vxlan_gpe_hw_class) = { .name = "VXLAN_GPE", .format_header = format_vxlan_gpe_header_with_length, .build_rewrite = default_build_rewrite, }; -/* *INDENT-ON* */ static void vxlan_gpe_tunnel_restack_dpo (vxlan_gpe_tunnel_t * t) @@ -248,12 +245,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 +303,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 +362,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; @@ -385,7 +384,6 @@ vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size, return (0); } -/* *INDENT-OFF* */ typedef CLIB_PACKED(union { struct { fib_node_index_t mfib_entry_index; @@ -393,7 +391,6 @@ typedef CLIB_PACKED(union { }; u64 as_u64; }) mcast_shared_t; -/* *INDENT-ON* */ static inline mcast_shared_t mcast_shared_get (ip46_address_t * ip) @@ -453,12 +450,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 +473,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); } @@ -485,7 +490,6 @@ int vnet_vxlan_gpe_add_del_tunnel clib_memset (t, 0, sizeof (*t)); /* copy from arg structure */ -/* *INDENT-OFF* */ #define _(x) t->x = a->x; foreach_gpe_copy_field; if (!a->is_ip6) @@ -493,7 +497,6 @@ int vnet_vxlan_gpe_add_del_tunnel else foreach_copy_ipv6 #undef _ -/* *INDENT-ON* */ if (!a->is_ip6) t->flags |= VXLAN_GPE_TUNNEL_IS_IPV4; @@ -533,7 +536,7 @@ int vnet_vxlan_gpe_add_del_tunnel vnet_interface_main_t *im = &vnm->interface_main; hw_if_index = ngm->free_vxlan_gpe_tunnel_hw_if_indices [vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) - 1]; - _vec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices) -= 1; + vec_dec_len (ngm->free_vxlan_gpe_tunnel_hw_if_indices, 1); hi = vnet_get_hw_interface (vnm, hw_if_index); hi->dev_instance = t - ngm->tunnels; @@ -583,7 +586,8 @@ int vnet_vxlan_gpe_add_del_tunnel fib_prefix_t tun_remote_pfx; vnet_flood_class_t flood_class = VNET_FLOOD_CLASS_TUNNEL_NORMAL; - fib_prefix_from_ip46_addr (&t->remote, &tun_remote_pfx); + fib_protocol_t fp = fib_ip_proto (is_ip6); + fib_prefix_from_ip46_addr (fp, &t->remote, &tun_remote_pfx); if (!ip46_address_is_multicast (&t->remote)) { /* Unicast tunnel - @@ -607,8 +611,6 @@ int vnet_vxlan_gpe_add_del_tunnel * with different VNIs, create the output fib adjacency only if * it does not already exist */ - fib_protocol_t fp = fib_ip_proto (is_ip6); - if (vtep_addr_ref (&ngm->vtep_table, t->encap_fib_index, &t->remote) == 1) { @@ -634,17 +636,16 @@ int vnet_vxlan_gpe_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_GPE, &path); + mfib_table_entry_path_update (t->encap_fib_index, &mpfx, + MFIB_SOURCE_VXLAN_GPE, + 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_GPE, - &path); + mfei = mfib_table_entry_path_update ( + t->encap_fib_index, &mpfx, MFIB_SOURCE_VXLAN_GPE, + MFIB_ENTRY_FLAG_NONE, &path); /* * Create the mcast adjacency to send traffic to the group @@ -719,12 +720,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 +750,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 +836,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")) @@ -903,7 +910,6 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, a->is_add = is_add; a->is_ip6 = ipv6_set; -/* *INDENT-OFF* */ #define _(x) a->x = x; foreach_gpe_copy_field; if (ipv4_set) @@ -911,7 +917,6 @@ vxlan_gpe_add_del_tunnel_command_fn (vlib_main_t * vm, else foreach_copy_ipv6 #undef _ -/* *INDENT-ON* */ rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index); @@ -964,7 +969,6 @@ done: * Example of how to delete a VXLAN-GPE Tunnel: * @cliexcmd{create vxlan-gpe tunnel local 10.0.3.1 remote 10.0.3.3 vni 13 del} ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = { .path = "create vxlan-gpe tunnel", .short_help = @@ -974,7 +978,6 @@ VLIB_CLI_COMMAND (create_vxlan_gpe_tunnel_command, static) = { " [encap-vrf-id <nn>] [decap-vrf-id <nn>] [del]\n", .function = vxlan_gpe_add_del_tunnel_command_fn, }; -/* *INDENT-ON* */ /** * @brief CLI function for showing VXLAN GPE tunnels @@ -997,12 +1000,10 @@ show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm, if (pool_elts (ngm->tunnels) == 0) vlib_cli_output (vm, "No vxlan-gpe tunnels configured."); - /* *INDENT-OFF* */ pool_foreach (t, ngm->tunnels) { vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t); } - /* *INDENT-ON* */ return 0; } @@ -1016,12 +1017,10 @@ show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm, * [0] local 10.0.3.1 remote 10.0.3.3 vni 13 encap_fib_index 0 sw_if_index 5 decap_next l2 * @cliexend ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_vxlan_gpe_tunnel_command, static) = { .path = "show vxlan-gpe", .function = show_vxlan_gpe_tunnel_command_fn, }; -/* *INDENT-ON* */ void vnet_int_vxlan_gpe_bypass_mode (u32 sw_if_index, u8 is_ip6, u8 is_enable) @@ -1087,11 +1086,12 @@ set_ip4_vxlan_gpe_bypass (vlib_main_t * vm, } /*? - * This command adds the 'ip4-vxlan-gpe-bypass' graph node for a given interface. - * By adding the IPv4 vxlan-gpe-bypass graph node to an interface, the node checks - * for and validate input vxlan_gpe packet and bypass ip4-lookup, ip4-local, - * ip4-udp-lookup nodes to speedup vxlan_gpe packet forwarding. This node will - * cause extra overhead to for non-vxlan_gpe packets which is kept at a minimum. + * This command adds the 'ip4-vxlan-gpe-bypass' graph node for a given + * interface. By adding the IPv4 vxlan-gpe-bypass graph node to an interface, + * the node checks for and validate input vxlan_gpe packet and bypass + * ip4-lookup, ip4-local, ip4-udp-lookup nodes to speedup vxlan_gpe packet + * forwarding. This node will cause extra overhead to for non-vxlan_gpe + * packets which is kept at a minimum. * * @cliexpar * @parblock @@ -1108,10 +1108,10 @@ set_ip4_vxlan_gpe_bypass (vlib_main_t * vm, * * Example of graph node after ip4-vxlan-gpe-bypass is enabled: * @cliexstart{show vlib graph ip4-vxlan-gpe-bypass} - * Name Next Previous - * ip4-vxlan-gpe-bypass error-drop [0] ip4-input - * vxlan4-gpe-input [1] ip4-input-no-checksum - * ip4-lookup [2] + * Name Next Previous + * ip4-vxlan-gpe-bypass error-drop [0] ip4-input + * vxlan4-gpe-input [1] ip4-input-no-checksum + * ip4-lookup [2] * @cliexend * * Example of how to display the feature enabled on an interface: @@ -1128,13 +1128,11 @@ set_ip4_vxlan_gpe_bypass (vlib_main_t * vm, * @cliexcmd{set interface ip vxlan-gpe-bypass GigabitEthernet2/0/0 del} * @endparblock ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_interface_ip_vxlan_gpe_bypass_command, static) = { .path = "set interface ip vxlan-gpe-bypass", .function = set_ip4_vxlan_gpe_bypass, .short_help = "set interface ip vxlan-gpe-bypass <interface> [del]", }; -/* *INDENT-ON* */ static clib_error_t * set_ip6_vxlan_gpe_bypass (vlib_main_t * vm, @@ -1144,11 +1142,12 @@ set_ip6_vxlan_gpe_bypass (vlib_main_t * vm, } /*? - * This command adds the 'ip6-vxlan-gpe-bypass' graph node for a given interface. - * By adding the IPv6 vxlan-gpe-bypass graph node to an interface, the node checks - * for and validate input vxlan_gpe packet and bypass ip6-lookup, ip6-local, - * ip6-udp-lookup nodes to speedup vxlan_gpe packet forwarding. This node will - * cause extra overhead to for non-vxlan_gpe packets which is kept at a minimum. + * This command adds the 'ip6-vxlan-gpe-bypass' graph node for a given + * interface. By adding the IPv6 vxlan-gpe-bypass graph node to an interface, + * the node checks for and validate input vxlan_gpe packet and bypass + * ip6-lookup, ip6-local, ip6-udp-lookup nodes to speedup vxlan_gpe packet + * forwarding. This node will cause extra overhead to for non-vxlan_gpe packets + * which is kept at a minimum. * * @cliexpar * @parblock @@ -1165,10 +1164,10 @@ set_ip6_vxlan_gpe_bypass (vlib_main_t * vm, * * Example of graph node after ip6-vxlan-gpe-bypass is enabled: * @cliexstart{show vlib graph ip6-vxlan-gpe-bypass} - * Name Next Previous - * ip6-vxlan-gpe-bypass error-drop [0] ip6-input - * vxlan6-gpe-input [1] ip4-input-no-checksum - * ip6-lookup [2] + * Name Next Previous + * ip6-vxlan-gpe-bypass error-drop [0] ip6-input + * vxlan6-gpe-input [1] ip4-input-no-checksum + * ip6-lookup [2] * @cliexend * * Example of how to display the feature enabled on an interface: @@ -1185,15 +1184,12 @@ set_ip6_vxlan_gpe_bypass (vlib_main_t * vm, * @cliexcmd{set interface ip6 vxlan-gpe-bypass GigabitEthernet2/0/0 del} * @endparblock ?*/ -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_interface_ip6_vxlan_gpe_bypass_command, static) = { .path = "set interface ip6 vxlan-gpe-bypass", .function = set_ip6_vxlan_gpe_bypass, .short_help = "set interface ip6 vxlan-gpe-bypass <interface> [del]", }; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ VNET_FEATURE_INIT (ip4_vxlan_gpe_bypass, static) = { .arc_name = "ip4-unicast", @@ -1207,7 +1203,6 @@ VNET_FEATURE_INIT (ip6_vxlan_gpe_bypass, static) = .node_name = "ip6-vxlan-gpe-bypass", .runs_before = VNET_FEATURES ("ip6-lookup"), }; -/* *INDENT-ON* */ /** * @brief Feature init function for VXLAN GPE diff --git a/src/vnet/vxlan-gpe/vxlan_gpe.h b/src/vnet/vxlan-gpe/vxlan_gpe.h index 0f8250a1788..aabaafeee6f 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe.h +++ b/src/vnet/vxlan-gpe/vxlan_gpe.h @@ -40,7 +40,6 @@ * @brief VXLAN GPE header struct * */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { /** 20 bytes */ ip4_header_t ip4; @@ -49,9 +48,7 @@ typedef CLIB_PACKED (struct { /** 8 bytes */ vxlan_gpe_header_t vxlan; }) ip4_vxlan_gpe_header_t; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { /** 40 bytes */ ip6_header_t ip6; @@ -60,15 +57,13 @@ typedef CLIB_PACKED (struct { /** 8 bytes */ vxlan_gpe_header_t vxlan; }) ip6_vxlan_gpe_header_t; -/* *INDENT-ON* */ /** * @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 */ -/* *INDENT-OFF* */ typedef CLIB_PACKED(struct { union { struct { @@ -76,26 +71,35 @@ typedef CLIB_PACKED(struct { u32 remote; u32 vni; - u32 pad; + u32 port; }; u64 as_u64[2]; }; }) vxlan4_gpe_tunnel_key_t; -/* *INDENT-ON* */ /** * @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 */ -/* *INDENT-OFF* */ 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 +121,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; @@ -221,9 +229,7 @@ typedef struct vnet_main_t *vnet_main; /* cache for last 8 vxlan_gpe tunnel */ -#ifdef CLIB_HAVE_VEC512 vtep4_cache_t vtep4_u512; -#endif /** List of next nodes for the decap indexed on protocol */ uword decap_next_node_list[VXLAN_GPE_PROTOCOL_MAX]; @@ -248,6 +254,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..cc74e1f58d4 100644 --- a/src/vnet/vxlan-gpe/vxlan_gpe_api.c +++ b/src/vnet/vxlan-gpe/vxlan_gpe_api.c @@ -114,12 +114,77 @@ static void rv = vnet_vxlan_gpe_add_del_tunnel (a, &sw_if_index); out: - /* *INDENT-OFF* */ REPLY_MACRO2(VL_API_VXLAN_GPE_ADD_DEL_TUNNEL_REPLY, ({ rmp->sw_if_index = ntohl (sw_if_index); })); - /* *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 @@ -175,12 +240,10 @@ static void vl_api_vxlan_gpe_tunnel_dump_t_handler if (~0 == sw_if_index) { - /* *INDENT-OFF* */ pool_foreach (t, vgm->tunnels) - { - send_vxlan_gpe_tunnel_details(t, reg, mp->context); - } - /* *INDENT-ON* */ + { + send_vxlan_gpe_tunnel_details (t, reg, mp->context); + } } else { @@ -194,6 +257,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 <vxlan-gpe/vxlan_gpe.api.c> static clib_error_t * @@ -201,8 +338,8 @@ vxlan_gpe_api_hookup (vlib_main_t * vm) { api_main_t *am = vlibapi_get_main (); - am->api_trace_cfg[VL_API_VXLAN_GPE_ADD_DEL_TUNNEL].size += - 17 * sizeof (u32); + vl_api_increase_msg_trace_size (am, VL_API_VXLAN_GPE_ADD_DEL_TUNNEL, + 17 * sizeof (u32)); /* * Set up the (msg_name, crc, message-id) table |