aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/vxlan-gpe
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/vxlan-gpe')
-rw-r--r--src/vnet/vxlan-gpe/decap.c435
-rw-r--r--src/vnet/vxlan-gpe/vxlan_gpe.api59
-rw-r--r--src/vnet/vxlan-gpe/vxlan_gpe.c61
-rw-r--r--src/vnet/vxlan-gpe/vxlan_gpe.h24
-rw-r--r--src/vnet/vxlan-gpe/vxlan_gpe_api.c147
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 *