vxlan: add udp-port configuration support
[vpp.git] / src / vnet / vxlan / decap.c
index e838c03..4678aa3 100644 (file)
@@ -68,12 +68,15 @@ vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache,
   if (PREDICT_FALSE (vxlan0->flags != VXLAN_FLAGS_I))
     return decap_bad_flags;
 
-  /* Make sure VXLAN tunnel exist according to packet S/D IP, VRF, and VNI */
+  /* Make sure VXLAN tunnel exist according to packet S/D IP, UDP port, VRF,
+   * and VNI */
   u32 dst = ip4_0->dst_address.as_u32;
   u32 src = ip4_0->src_address.as_u32;
+  udp_header_t *udp = ip4_next_header (ip4_0);
   vxlan4_tunnel_key_t key4 = {
     .key[0] = ((u64) dst << 32) | src,
-    .key[1] = ((u64) fib_index << 32) | vxlan0->vni_reserved,
+    .key[1] = ((u64) udp->dst_port << 48) | ((u64) fib_index << 32) |
+             vxlan0->vni_reserved,
   };
 
   if (PREDICT_TRUE
@@ -127,11 +130,14 @@ vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache,
   if (PREDICT_FALSE (vxlan0->flags != VXLAN_FLAGS_I))
     return decap_bad_flags;
 
-  /* Make sure VXLAN tunnel exist according to packet SIP and VNI */
+  /* Make sure VXLAN tunnel exist according to packet SIP, UDP port, VRF, and
+   * VNI */
+  udp_header_t *udp = ip6_next_header (ip6_0);
   vxlan6_tunnel_key_t key6 = {
     .key[0] = ip6_0->src_address.as_u64[0],
     .key[1] = ip6_0->src_address.as_u64[1],
-    .key[2] = (((u64) fib_index) << 32) | vxlan0->vni_reserved,
+    .key[2] = ((u64) udp->dst_port << 48) | ((u64) fib_index << 32) |
+             vxlan0->vni_reserved,
   };
 
   if (PREDICT_FALSE
@@ -460,6 +466,9 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
                                   matching a local VTEP address */
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
 
+  last_tunnel_cache4 last4;
+  last_tunnel_cache6 last6;
+
 #ifdef CLIB_HAVE_VEC512
   vtep4_cache_t vtep4_u512;
   clib_memset (&vtep4_u512, 0, sizeof (vtep4_u512));
@@ -475,9 +484,15 @@ ip_vxlan_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)
     {
@@ -489,11 +504,13 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
          ip4_header_t *ip40, *ip41;
          ip6_header_t *ip60, *ip61;
          udp_header_t *udp0, *udp1;
+         vxlan_header_t *vxlan0, *vxlan1;
          u32 bi0, ip_len0, udp_len0, flags0, next0;
          u32 bi1, ip_len1, udp_len1, flags1, next1;
          i32 len_diff0, len_diff1;
          u8 error0, good_udp0, proto0;
          u8 error1, good_udp1, proto1;
+         u32 stats_if0 = ~0, stats_if1 = ~0;
 
          /* Prefetch next iteration. */
          {
@@ -551,8 +568,17 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
          else
            udp0 = ip6_next_header (ip60);
 
-         if (udp0->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_vxlan))
-           goto exit0;         /* not VXLAN packet */
+         u32 fi0 = vlib_buffer_get_ip_fib_index (b0, is_ip4);
+         vxlan0 = vlib_buffer_get_current (b0) + sizeof (udp_header_t) +
+                  sizeof (ip4_header_t);
+
+         vxlan_decap_info_t di0 =
+           is_ip4 ?
+             vxlan4_find_tunnel (vxm, &last4, fi0, ip40, vxlan0, &stats_if0) :
+             vxlan6_find_tunnel (vxm, &last6, fi0, ip60, vxlan0, &stats_if0);
+
+         if (PREDICT_FALSE (di0.sw_if_index == ~0))
+           goto exit0; /* unknown interface */
 
          /* Validate DIP against VTEPs */
          if (is_ip4)
@@ -630,8 +656,17 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
          else
            udp1 = ip6_next_header (ip61);
 
-         if (udp1->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_vxlan))
-           goto exit1;         /* not VXLAN packet */
+         u32 fi1 = vlib_buffer_get_ip_fib_index (b1, is_ip4);
+         vxlan1 = vlib_buffer_get_current (b1) + sizeof (udp_header_t) +
+                  sizeof (ip4_header_t);
+
+         vxlan_decap_info_t di1 =
+           is_ip4 ?
+             vxlan4_find_tunnel (vxm, &last4, fi1, ip41, vxlan1, &stats_if1) :
+             vxlan6_find_tunnel (vxm, &last6, fi1, ip61, vxlan1, &stats_if1);
+
+         if (PREDICT_FALSE (di1.sw_if_index == ~0))
+           goto exit1; /* unknown interface */
 
          /* Validate DIP against VTEPs */
          if (is_ip4)
@@ -711,9 +746,11 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
          ip4_header_t *ip40;
          ip6_header_t *ip60;
          udp_header_t *udp0;
+         vxlan_header_t *vxlan0;
          u32 bi0, ip_len0, udp_len0, flags0, next0;
          i32 len_diff0;
          u8 error0, good_udp0, proto0;
+         u32 stats_if0 = ~0;
 
          bi0 = to_next[0] = from[0];
          from += 1;
@@ -746,8 +783,17 @@ ip_vxlan_bypass_inline (vlib_main_t * vm,
          else
            udp0 = ip6_next_header (ip60);
 
-         if (udp0->dst_port != clib_host_to_net_u16 (UDP_DST_PORT_vxlan))
-           goto exit;          /* not VXLAN packet */
+         u32 fi0 = vlib_buffer_get_ip_fib_index (b0, is_ip4);
+         vxlan0 = vlib_buffer_get_current (b0) + sizeof (udp_header_t) +
+                  sizeof (ip4_header_t);
+
+         vxlan_decap_info_t di0 =
+           is_ip4 ?
+             vxlan4_find_tunnel (vxm, &last4, fi0, ip40, vxlan0, &stats_if0) :
+             vxlan6_find_tunnel (vxm, &last6, fi0, ip60, vxlan0, &stats_if0);
+
+         if (PREDICT_FALSE (di0.sw_if_index == ~0))
+           goto exit; /* unknown interface */
 
          /* Validate DIP against VTEPs */
          if (is_ip4)