vxlan-gpe: add udp-port configuration support
[vpp.git] / src / vnet / vxlan-gpe / vxlan_gpe.c
index 86157c0..17ffcad 100644 (file)
@@ -26,6 +26,7 @@
 #include <vnet/mfib/mfib_table.h>
 #include <vnet/adj/adj_mcast.h>
 #include <vnet/interface.h>
+#include <vnet/udp/udp_local.h>
 #include <vlib/vlib.h>
 
 /**
@@ -86,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 */
@@ -247,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)                           \
@@ -303,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;
@@ -362,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;
@@ -384,35 +388,6 @@ vxlan6_gpe_rewrite (vxlan_gpe_tunnel_t * t, u32 extension_size,
   return (0);
 }
 
-static uword
-vtep_addr_ref (ip46_address_t * ip)
-{
-  uword *vtep = ip46_address_is_ip4 (ip) ?
-    hash_get (vxlan_gpe_main.vtep4, ip->ip4.as_u32) :
-    hash_get_mem (vxlan_gpe_main.vtep6, &ip->ip6);
-  if (vtep)
-    return ++(*vtep);
-  ip46_address_is_ip4 (ip) ?
-    hash_set (vxlan_gpe_main.vtep4, ip->ip4.as_u32, 1) :
-    hash_set_mem_alloc (&vxlan_gpe_main.vtep6, &ip->ip6, 1);
-  return 1;
-}
-
-static uword
-vtep_addr_unref (ip46_address_t * ip)
-{
-  uword *vtep = ip46_address_is_ip4 (ip) ?
-    hash_get (vxlan_gpe_main.vtep4, ip->ip4.as_u32) :
-    hash_get_mem (vxlan_gpe_main.vtep6, &ip->ip6);
-  ASSERT (vtep);
-  if (--(*vtep) != 0)
-    return *vtep;
-  ip46_address_is_ip4 (ip) ?
-    hash_unset (vxlan_gpe_main.vtep4, ip->ip4.as_u32) :
-    hash_unset_mem_free (&vxlan_gpe_main.vtep6, &ip->ip6);
-  return 0;
-}
-
 /* *INDENT-OFF* */
 typedef CLIB_PACKED(union {
   struct {
@@ -428,7 +403,7 @@ mcast_shared_get (ip46_address_t * ip)
 {
   ASSERT (ip46_address_is_multicast (ip));
   uword *p = hash_get_mem (vxlan_gpe_main.mcast_shared, ip);
-  ASSERT (p);
+  ALWAYS_ASSERT (p);
   return (mcast_shared_t)
   {
   .as_u64 = *p};
@@ -481,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);
     }
@@ -497,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);
     }
@@ -620,7 +603,7 @@ int vnet_vxlan_gpe_add_del_tunnel
           * when the forwarding for the entry updates, and the tunnel can
           * re-stack accordingly
           */
-         vtep_addr_ref (&t->local);
+         vtep_addr_ref (&ngm->vtep_table, t->encap_fib_index, &t->local);
          t->fib_entry_index = fib_entry_track (t->encap_fib_index,
                                                &tun_remote_pfx,
                                                FIB_NODE_TYPE_VXLAN_GPE_TUNNEL,
@@ -637,7 +620,8 @@ int vnet_vxlan_gpe_add_del_tunnel
           */
          fib_protocol_t fp = fib_ip_proto (is_ip6);
 
-         if (vtep_addr_ref (&t->remote) == 1)
+         if (vtep_addr_ref (&ngm->vtep_table,
+                            t->encap_fib_index, &t->remote) == 1)
            {
              fib_node_index_t mfei;
              adj_index_t ai;
@@ -726,10 +710,11 @@ int vnet_vxlan_gpe_add_del_tunnel
 
       if (!ip46_address_is_multicast (&t->remote))
        {
-         vtep_addr_unref (&t->local);
+         vtep_addr_unref (&ngm->vtep_table, t->encap_fib_index, &t->local);
          fib_entry_untrack (t->fib_entry_index, t->sibling_index);
        }
-      else if (vtep_addr_unref (&t->remote) == 0)
+      else if (vtep_addr_unref (&ngm->vtep_table,
+                               t->encap_fib_index, &t->remote) == 0)
        {
          mcast_shared_remove (&t->remote);
        }
@@ -745,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;
@@ -775,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;
@@ -859,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"))
@@ -1024,10 +1015,10 @@ show_vxlan_gpe_tunnel_command_fn (vlib_main_t * vm,
     vlib_cli_output (vm, "No vxlan-gpe tunnels configured.");
 
   /* *INDENT-OFF* */
-  pool_foreach (t, ngm->tunnels,
-  ({
+  pool_foreach (t, ngm->tunnels)
+   {
     vlib_cli_output (vm, "%U", format_vxlan_gpe_tunnel, t);
-  }));
+  }
   /* *INDENT-ON* */
 
   return 0;
@@ -1113,11 +1104,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
@@ -1134,10 +1126,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:
@@ -1170,11 +1162,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
@@ -1191,10 +1184,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:
@@ -1261,7 +1254,7 @@ vxlan_gpe_init (vlib_main_t * vm)
   ngm->mcast_shared = hash_create_mem (0,
                                       sizeof (ip46_address_t),
                                       sizeof (mcast_shared_t));
-  ngm->vtep6 = hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
+  ngm->vtep_table = vtep_table_create ();
 
   /* Register the list of standard decap protocols supported */
   vxlan_gpe_register_decap_protocol (VXLAN_GPE_PROTOCOL_IP4,