vxlan:use bihash_16_8 for ipv4 lookup 79/13379/5
authorEyal Bari <ebari@cisco.com>
Sun, 8 Jul 2018 05:15:56 +0000 (08:15 +0300)
committerJohn Lo <loj@cisco.com>
Mon, 9 Jul 2018 21:08:54 +0000 (21:08 +0000)
Change-Id: I0d4630c88d6caacffcd073ebaa12766dfc893f70
Signed-off-by: Eyal Bari <ebari@cisco.com>
src/vnet/vxlan/decap.c
src/vnet/vxlan/vxlan.c
src/vnet/vxlan/vxlan.h
test/test_vxlan6.py

index 79d6361..f911801 100644 (file)
@@ -62,11 +62,7 @@ buf_fib_index (vlib_buffer_t *b, u32 is_ip4)
   return vec_elt (fib_index_by_sw_if_index, sw_if_index);
 }
 
-typedef struct
-{
-  vxlan4_tunnel_key_t key4;
-  u32 tunnel_index;
-}last_tunnel_cache4;
+typedef vxlan4_tunnel_key_t last_tunnel_cache4;
 
 always_inline vxlan_tunnel_t *
 vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache,
@@ -74,24 +70,22 @@ vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache,
                     vxlan_tunnel_t ** stats_t0)
 {
   /* Make sure VXLAN tunnel exist according to packet SIP and VNI */
-  vxlan4_tunnel_key_t key4_0 = {
-    .src = ip4_0->src_address.as_u32,
-    .vni = vxlan0->vni_reserved,
+  vxlan4_tunnel_key_t key4 = {
+    .key = {
+      [0] = ip4_0->src_address.as_u32,
+      [1] = (((u64) fib_index) << 32) | vxlan0->vni_reserved,
+    }
   };
 
-  if (PREDICT_FALSE (key4_0.as_u64 != cache->key4.as_u64))
+  if (PREDICT_FALSE (clib_bihash_key_compare_16_8 (key4.key, cache->key) == 0))
   {
-    uword * p = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64);
-    if (PREDICT_FALSE (p == 0))
+    int rv = clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
+    if (PREDICT_FALSE (rv != 0))
       return 0;
 
-    cache->key4 = key4_0;
-    cache->tunnel_index = p[0];
+    *cache = key4;
   }
-  vxlan_tunnel_t * t0 = pool_elt_at_index (vxm->tunnels, cache->tunnel_index);
-
-  if (PREDICT_FALSE (fib_index != t0->encap_fib_index))
-    return 0;
+  vxlan_tunnel_t * t0 = pool_elt_at_index (vxm->tunnels, cache->value);
 
   /* Validate VXLAN tunnel SIP against packet DIP */
   if (PREDICT_TRUE (ip4_0->dst_address.as_u32 == t0->src.ip4.as_u32))
@@ -102,12 +96,13 @@ vxlan4_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache4 * cache,
     if (PREDICT_TRUE (!ip4_address_is_multicast (&ip4_0->dst_address)))
       return 0;
 
-    key4_0.src = ip4_0->dst_address.as_u32;
+    key4.key[0] = ip4_0->dst_address.as_u32;
     /* Make sure mcast VXLAN tunnel exist by packet DIP and VNI */
-    uword * p = hash_get (vxm->vxlan4_tunnel_by_key, key4_0.as_u64);
-    if (PREDICT_FALSE (p == NULL))
+    int rv = clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
+    if (PREDICT_FALSE (rv != 0))
       return 0;
-    *stats_t0 = pool_elt_at_index (vxm->tunnels, p[0]);
+
+    *stats_t0 = pool_elt_at_index (vxm->tunnels, key4.value);
   }
 
   return t0;
@@ -126,13 +121,13 @@ vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache,
     .key = {
       [0] = ip6_0->src_address.as_u64[0],
       [1] = ip6_0->src_address.as_u64[1],
-      [2] = (((u64) fib_index) << 32) | vxlan0->vni_reserved
+      [2] = (((u64) fib_index) << 32) | vxlan0->vni_reserved,
     }
   };
 
-  if (PREDICT_FALSE (BV (clib_bihash_key_compare) (key6.key, cache->key) == 0))
+  if (PREDICT_FALSE (clib_bihash_key_compare_24_8 (key6.key, cache->key) == 0))
   {
-    int rv = BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6);
+    int rv = clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
     if (PREDICT_FALSE (rv != 0))
       return 0;
 
@@ -152,7 +147,7 @@ vxlan6_find_tunnel (vxlan_main_t * vxm, last_tunnel_cache6 * cache,
     /* Make sure mcast VXLAN tunnel exist by packet DIP and VNI */
     key6.key[0] = ip6_0->dst_address.as_u64[0];
     key6.key[1] = ip6_0->dst_address.as_u64[1];
-    int rv = BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6);
+    int rv = clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
     if (PREDICT_FALSE (rv != 0))
       return 0;
 
@@ -173,13 +168,13 @@ vxlan_input (vlib_main_t * vm,
   vnet_interface_main_t * im = &vnm->interface_main;
   vlib_combined_counter_main_t * rx_counter = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX;
   vlib_combined_counter_main_t * drop_counter = im->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP;
-  last_tunnel_cache4 last4 = { .tunnel_index = ~0 };
+  last_tunnel_cache4 last4;
   last_tunnel_cache6 last6;
   u32 pkts_decapsulated = 0;
   u32 thread_index = vlib_get_thread_index();
 
   if (is_ip4)
-    last4.key4.as_u64 = ~0;
+    memset (&last4, 0xff, sizeof last4);
   else
     memset (&last6, 0xff, sizeof last6);
 
index d593861..e1ee348 100644 (file)
@@ -369,17 +369,21 @@ int vnet_vxlan_add_del_tunnel
   vxlan_main_t *vxm = &vxlan_main;
   vxlan_tunnel_t *t = 0;
   vnet_main_t *vnm = vxm->vnet_main;
-  uword *p;
+  u64 *p;
   u32 sw_if_index = ~0;
   vxlan4_tunnel_key_t key4;
   vxlan6_tunnel_key_t key6;
   u32 is_ip6 = a->is_ip6;
 
+  int not_found;
   if (!is_ip6)
     {
-      key4.src = a->dst.ip4.as_u32;    /* decap src in key is encap dst in config */
-      key4.vni = clib_host_to_net_u32 (a->vni << 8);
-      p = hash_get (vxm->vxlan4_tunnel_by_key, key4.as_u64);
+      key4.key[0] = a->dst.ip4.as_u32;
+      key4.key[1] = (((u64) a->encap_fib_index) << 32)
+       | clib_host_to_net_u32 (a->vni << 8);
+      not_found =
+       clib_bihash_search_inline_16_8 (&vxm->vxlan4_tunnel_by_key, &key4);
+      p = &key4.value;
     }
   else
     {
@@ -387,14 +391,14 @@ int vnet_vxlan_add_del_tunnel
       key6.key[1] = a->dst.ip6.as_u64[1];
       key6.key[2] = (((u64) a->encap_fib_index) << 32)
        | clib_host_to_net_u32 (a->vni << 8);
-      int rv =
-       BV (clib_bihash_search_inline) (&vxm->vxlan6_tunnel_by_key, &key6);
-      if (PREDICT_FALSE (rv != 0))
-       p = 0;
-      else
-       p = &key6.value;
+      not_found =
+       clib_bihash_search_inline_24_8 (&vxm->vxlan6_tunnel_by_key, &key6);
+      p = &key6.value;
     }
 
+  if (not_found)
+    p = 0;
+
   if (a->is_add)
     {
       l2input_main_t *l2im = &l2input_main;
@@ -439,18 +443,25 @@ int vnet_vxlan_add_del_tunnel
       t->flow_index = ~0;
 
       /* copy the key */
+      int add_failed;
       if (is_ip6)
        {
          key6.value = (u64) dev_instance;
-         if (BV (clib_bihash_add_del) (&vxm->vxlan6_tunnel_by_key,
-                                       &key6, 1 /*add */ ))
-           {
-             pool_put (vxm->tunnels, t);
-             return VNET_API_ERROR_INVALID_REGISTRATION;
-           }
+         add_failed = clib_bihash_add_del_24_8 (&vxm->vxlan6_tunnel_by_key,
+                                                &key6, 1 /*add */ );
        }
       else
-       hash_set (vxm->vxlan4_tunnel_by_key, key4.as_u64, dev_instance);
+       {
+         key4.value = (u64) dev_instance;
+         add_failed = clib_bihash_add_del_16_8 (&vxm->vxlan4_tunnel_by_key,
+                                                &key4, 1 /*add */ );
+       }
+
+      if (add_failed)
+       {
+         pool_put (vxm->tunnels, t);
+         return VNET_API_ERROR_INVALID_REGISTRATION;
+       }
 
       t->hw_if_index = vnet_register_interface
        (vnm, vxlan_device_class.index, dev_instance,
@@ -587,9 +598,10 @@ int vnet_vxlan_add_del_tunnel
       vxm->tunnel_index_by_sw_if_index[sw_if_index] = ~0;
 
       if (!is_ip6)
-       hash_unset (vxm->vxlan4_tunnel_by_key, key4.as_u64);
+       clib_bihash_add_del_16_8 (&vxm->vxlan4_tunnel_by_key, &key4,
+                                 0 /*del */ );
       else
-       BV (clib_bihash_add_del) (&vxm->vxlan6_tunnel_by_key, &key6,
+       clib_bihash_add_del_24_8 (&vxm->vxlan6_tunnel_by_key, &key6,
                                  0 /*del */ );
 
       if (!ip46_address_is_multicast (&t->dst))
@@ -817,6 +829,8 @@ vxlan_add_del_tunnel_command_fn (vlib_main_t * vm,
  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 encap-vrf-id 7}
  * Example of how to create a VXLAN Tunnel with a known name, vxlan_tunnel42:
  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 instance 42}
+ * Example of how to create a multicast VXLAN Tunnel with a known name, vxlan_tunnel23:
+ * @cliexcmd{create vxlan tunnel src 10.0.3.1 group 239.1.1.1 GigabitEtherner0/8/0 instance 23}
  * Example of how to delete a VXLAN Tunnel:
  * @cliexcmd{create vxlan tunnel src 10.0.3.1 dst 10.0.3.3 vni 13 del}
  ?*/
@@ -872,9 +886,14 @@ show_vxlan_tunnel_command_fn (vlib_main_t * vm,
 /* *INDENT-ON* */
 
   if (raw)
-    vlib_cli_output (vm, "Raw IPv6 Hash Table:\n%U\n",
-                    BV (format_bihash), &vxm->vxlan6_tunnel_by_key,
-                    1 /* verbose */ );
+    {
+      vlib_cli_output (vm, "Raw IPv4 Hash Table:\n%U\n",
+                      format_bihash_16_8, &vxm->vxlan4_tunnel_by_key,
+                      1 /* verbose */ );
+      vlib_cli_output (vm, "Raw IPv6 Hash Table:\n%U\n",
+                      format_bihash_24_8, &vxm->vxlan6_tunnel_by_key,
+                      1 /* verbose */ );
+    }
 
   return 0;
 }
@@ -1198,7 +1217,9 @@ vxlan_init (vlib_main_t * vm)
                       &vxm->flow_id_start);
 
   /* initialize the ip6 hash */
-  BV (clib_bihash_init) (&vxm->vxlan6_tunnel_by_key, "vxlan6",
+  clib_bihash_init_16_8 (&vxm->vxlan4_tunnel_by_key, "vxlan4",
+                        VXLAN_HASH_NUM_BUCKETS, VXLAN_HASH_MEMORY_SIZE);
+  clib_bihash_init_24_8 (&vxm->vxlan6_tunnel_by_key, "vxlan6",
                         VXLAN_HASH_NUM_BUCKETS, VXLAN_HASH_MEMORY_SIZE);
   vxm->vtep6 = hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
   vxm->mcast_shared = hash_create_mem (0,
index 21b7650..ce410d7 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <vppinfra/error.h>
 #include <vppinfra/hash.h>
+#include <vppinfra/bihash_16_8.h>
 #include <vppinfra/bihash_24_8.h>
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
@@ -43,27 +44,20 @@ typedef CLIB_PACKED (struct {
   udp_header_t udp;    /* 8 bytes */
   vxlan_header_t vxlan;        /* 8 bytes */
 }) ip6_vxlan_header_t;
+/* *INDENT-ON* */
 
-typedef CLIB_PACKED (union {
-  /*
-  * Key fields: remote ip, vni on incoming VXLAN packet
-  * all fields in NET byte order
-  */
-  struct
-    {
-      u32 src;
-      u32 vni; /* shifted left 8 bits */
-    };
-  u64 as_u64;
-}) vxlan4_tunnel_key_t;
+/*
+* Key fields: remote ip, vni on incoming VXLAN packet
+* all fields in NET byte order
+*/
+typedef clib_bihash_kv_16_8_t vxlan4_tunnel_key_t;
 
 /*
 * Key fields: remote ip, vni and fib index on incoming VXLAN packet
 * ip, vni fields in NET byte order
 * fib index field in host byte order
 */
-typedef BVT (clib_bihash_kv)  vxlan6_tunnel_key_t;
-/* *INDENT-ON* */
+typedef clib_bihash_kv_24_8_t vxlan6_tunnel_key_t;
 
 typedef struct
 {
@@ -146,8 +140,8 @@ typedef struct
   vxlan_tunnel_t *tunnels;
 
   /* lookup tunnel by key */
-  uword *vxlan4_tunnel_by_key; /* keyed on ipv4.dst + vni */
-    BVT (clib_bihash) vxlan6_tunnel_by_key;    /* keyed on ipv6.dst + fib +  vni */
+  clib_bihash_16_8_t vxlan4_tunnel_by_key;     /* keyed on ipv4.dst + fib + vni */
+  clib_bihash_24_8_t vxlan6_tunnel_by_key;     /* keyed on ipv6.dst + fib + vni */
 
   /* local VTEP IPs ref count used by vxlan-bypass node to check if
      received VXLAN packet DIP matches any local VTEP address */
index 0457f9b..fd89f05 100644 (file)
@@ -11,8 +11,8 @@ from scapy.layers.vxlan import VXLAN
 from scapy.utils import atol
 
 
-class TestVxlan(BridgeDomain, VppTestCase):
-    """ VXLAN Test Case """
+class TestVxlan6(BridgeDomain, VppTestCase):
+    """ VXLAN over IPv6 Test Case """
 
     def __init__(self, *args):
         BridgeDomain.__init__(self)
@@ -112,7 +112,7 @@ class TestVxlan(BridgeDomain, VppTestCase):
     #  @param cls The class pointer.
     @classmethod
     def setUpClass(cls):
-        super(TestVxlan, cls).setUpClass()
+        super(TestVxlan6, cls).setUpClass()
 
         try:
             cls.dport = 4789
@@ -168,14 +168,14 @@ class TestVxlan(BridgeDomain, VppTestCase):
             cls.vapi.sw_interface_set_l2_bridge(cls.pg3.sw_if_index,
                                                 bd_id=cls.ucast_flood_bd)
         except Exception:
-            super(TestVxlan, cls).tearDownClass()
+            super(TestVxlan6, cls).tearDownClass()
             raise
 
     # Method to define VPP actions before tear down of the test case.
     #  Overrides tearDown method in VppTestCase class.
     #  @param self The object pointer.
     def tearDown(self):
-        super(TestVxlan, self).tearDown()
+        super(TestVxlan6, self).tearDown()
         if not self.vpp_dead:
             self.logger.info(self.vapi.cli("show bridge-domain 1 detail"))
             self.logger.info(self.vapi.cli("show bridge-domain 2 detail"))