diff options
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/vxlan-gpe/decap.c | 435 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.api | 59 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.c | 61 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe.h | 24 | ||||
-rw-r--r-- | src/vnet/vxlan-gpe/vxlan_gpe_api.c | 147 |
5 files changed, 446 insertions, 280 deletions
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 <vxlan-gpe/vxlan_gpe.api.c> static clib_error_t * |