vxlan: add udp-port configuration support

Type: improvement

Signed-off-by: Artem Glazychev <artem.glazychev@xored.com>
Change-Id: Ie30d51ab4df5599b52f7335f863b930cd69dbdc1
diff --git a/src/vnet/vxlan/decap.c b/src/vnet/vxlan/decap.c
index e838c03..4678aa3 100644
--- a/src/vnet/vxlan/decap.c
+++ b/src/vnet/vxlan/decap.c
@@ -68,12 +68,15 @@
   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 @@
   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 @@
 				   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 @@
     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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	  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 @@
 	  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)