nat: simplify per-protocol code by using an array 46/36946/5
authorJon Loeliger <jdl@netgate.com>
Wed, 17 Aug 2022 17:08:31 +0000 (12:08 -0500)
committerJon Loeliger <jdl@netgate.com>
Fri, 19 Aug 2022 15:44:26 +0000 (10:44 -0500)
rather than using obfuscated macro hacery, simplify
the per-protocol data management by directly using
an array of NAT protocol types.

Type: refactor

Signed-off-by: Jon Loeliger <jdl@netgate.com>
Change-Id: I6fe987556ac9f402f8d490da0740e2b91440304c

src/plugins/nat/lib/nat_proto.h
src/plugins/nat/nat44-ei/nat44_ei.c
src/plugins/nat/nat44-ei/nat44_ei.h
src/plugins/nat/nat44-ei/nat44_ei_cli.c

index 9b20d9a..4b57b99 100644 (file)
@@ -28,6 +28,7 @@ typedef enum
 #define _(N, i, n, s) NAT_PROTOCOL_##N = i,
   foreach_nat_protocol
 #undef _
+    NAT_N_PROTOCOLS
 } nat_protocol_t;
 
 always_inline nat_protocol_t
index 8446011..448566d 100644 (file)
@@ -185,67 +185,26 @@ static int nat44_ei_del_static_mapping_internal (
   ip4_address_t l_addr, ip4_address_t e_addr, u16 l_port, u16 e_port,
   nat_protocol_t proto, u32 vrf_id, u32 sw_if_index, u32 flags);
 
+always_inline bool
+nat44_ei_port_is_used (nat44_ei_address_t *a, u8 proto, u16 port)
+{
+  return clib_bitmap_get (a->busy_port_bitmap[proto], port);
+}
+
 always_inline void
 nat44_ei_port_get (nat44_ei_address_t *a, u8 proto, u16 port)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
-
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    a->busy_##n##_port_bitmap =                                               \
-      clib_bitmap_set (a->busy_##n##_port_bitmap, port, 1);                   \
-    break;
-
-  switch (proto)
-    {
-      foreach_nat_protocol;
-    default:
-      nat_elog_info (nm, "unknown protocol");
-    }
-
-#undef _
+  ASSERT (!nat44_ei_port_is_used (a, proto, port));
+  a->busy_port_bitmap[proto] =
+    clib_bitmap_set (a->busy_port_bitmap[proto], port, 1);
 }
 
 always_inline void
 nat44_ei_port_put (nat44_ei_address_t *a, u8 proto, u16 port)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
-
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    a->busy_##n##_port_bitmap =                                               \
-      clib_bitmap_set (a->busy_##n##_port_bitmap, port, 0);                   \
-    break;
-
-  switch (proto)
-    {
-      foreach_nat_protocol;
-    default:
-      nat_elog_info (nm, "unknown protocol");
-    }
-
-#undef _
-}
-
-always_inline bool
-nat44_ei_port_is_used (nat44_ei_address_t *a, u8 proto, u16 port)
-{
-  nat44_ei_main_t *nm = &nat44_ei_main;
-
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    return clib_bitmap_get (a->busy_##n##_port_bitmap, port);
-
-  switch (proto)
-    {
-      foreach_nat_protocol;
-    default:
-      nat_elog_info (nm, "unknown protocol");
-    }
-
-#undef _
-
-  return 0;
+  ASSERT (nat44_ei_port_is_used (a, proto, port));
+  a->busy_port_bitmap[proto] =
+    clib_bitmap_set (a->busy_port_bitmap[proto], port, 0);
 }
 
 static u8 *
@@ -1304,7 +1263,6 @@ nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
                                       u32 thread_index, ip4_address_t addr,
                                       u16 port, nat_protocol_t protocol)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   nat44_ei_address_t *a = 0;
   u32 address_index;
   u16 port_host_byte_order = clib_net_to_host_u16 (port);
@@ -1315,21 +1273,13 @@ nat44_ei_set_outside_address_and_port (nat44_ei_address_t *addresses,
        continue;
 
       a = addresses + address_index;
-      switch (protocol)
-       {
-#define _(N, j, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    if (nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, port_host_byte_order))    \
-      return VNET_API_ERROR_INSTANCE_IN_USE;                                  \
-    nat44_ei_port_get (a, NAT_PROTOCOL_##N, port_host_byte_order);            \
-    a->busy_##n##_ports_per_thread[thread_index]++;                           \
-    a->busy_##n##_ports++;                                                    \
-    return 0;
-         foreach_nat_protocol
-#undef _
-           default : nat_elog_info (nm, "unknown protocol");
-         return 1;
-       }
+      if (nat44_ei_port_is_used (a, protocol, port_host_byte_order))
+       return VNET_API_ERROR_INSTANCE_IN_USE;
+
+      nat44_ei_port_get (a, protocol, port_host_byte_order);
+      a->busy_ports_per_thread[protocol][thread_index]++;
+      a->busy_ports[protocol]++;
+      return 0;
     }
 
   return VNET_API_ERROR_NO_SUCH_ENTRY;
@@ -1364,7 +1314,6 @@ nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
                                        u32 thread_index, ip4_address_t *addr,
                                        u16 port, nat_protocol_t protocol)
 {
-  nat44_ei_main_t *nm = &nat44_ei_main;
   nat44_ei_address_t *a;
   u32 address_index;
   u16 port_host_byte_order = clib_net_to_host_u16 (port);
@@ -1378,22 +1327,9 @@ nat44_ei_free_outside_address_and_port (nat44_ei_address_t *addresses,
   ASSERT (address_index < vec_len (addresses));
 
   a = addresses + address_index;
-
-  switch (protocol)
-    {
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    ASSERT (                                                                  \
-      nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, port_host_byte_order));     \
-    nat44_ei_port_put (a, NAT_PROTOCOL_##N, port_host_byte_order);            \
-    a->busy_##n##_ports--;                                                    \
-    a->busy_##n##_ports_per_thread[thread_index]--;                           \
-    break;
-      foreach_nat_protocol
-#undef _
-       default : nat_elog_info (nm, "unknown protocol");
-      return;
-    }
+  nat44_ei_port_put (a, protocol, port_host_byte_order);
+  a->busy_ports[protocol]--;
+  a->busy_ports_per_thread[protocol][thread_index]--;
 }
 
 void
@@ -1858,75 +1794,95 @@ nat44_ei_alloc_default_cb (nat44_ei_address_t *addresses, u32 fib_index,
 
   if (vec_len (addresses) > 0)
     {
-
       int s_addr_offset = s_addr.as_u32 % vec_len (addresses);
 
       for (i = s_addr_offset; i < vec_len (addresses); ++i)
        {
          a = addresses + i;
-         switch (proto)
+
+         if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
            {
-#define _(N, j, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread)       \
-      {                                                                       \
-       if (a->fib_index == fib_index)                                        \
-         {                                                                   \
-           while (1)                                                         \
-             {                                                               \
-               portnum = (port_per_thread * snat_thread_index) +             \
-                         nat_random_port (&nm->random_seed, 0,               \
-                                          port_per_thread - 1) +             \
-                         1024;                                               \
-               if (nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, portnum))     \
-                 continue;                                                   \
-               nat44_ei_port_get (a, NAT_PROTOCOL_##N, portnum);             \
-               a->busy_##n##_ports_per_thread[thread_index]++;               \
-               a->busy_##n##_ports++;                                        \
-               *addr = a->addr;                                              \
-               *port = clib_host_to_net_u16 (portnum);                       \
-               return 0;                                                     \
-             }                                                               \
-         }                                                                   \
-       else if (a->fib_index == ~0)                                          \
-         {                                                                   \
-           ga = a;                                                           \
-         }                                                                   \
-      }                                                                       \
-    break;
-             foreach_nat_protocol;
-           default:
-             nat_elog_info (nm, "unknown protocol");
-             return 1;
+             if (a->fib_index == fib_index)
+               {
+                 while (1)
+                   {
+                     portnum = (port_per_thread * snat_thread_index) +
+                               nat_random_port (&nm->random_seed, 0,
+                                                port_per_thread - 1) +
+                               1024;
+                     if (nat44_ei_port_is_used (a, proto, portnum))
+                       continue;
+                     nat44_ei_port_get (a, proto, portnum);
+                     a->busy_ports_per_thread[proto][thread_index]++;
+                     a->busy_ports[proto]++;
+                     *addr = a->addr;
+                     *port = clib_host_to_net_u16 (portnum);
+                     return 0;
+                   }
+               }
+             else if (a->fib_index == ~0)
+               {
+                 ga = a;
+               }
            }
        }
 
       for (i = 0; i < s_addr_offset; ++i)
        {
          a = addresses + i;
-         switch (proto)
+         if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
            {
-             foreach_nat_protocol;
-           default:
-             nat_elog_info (nm, "unknown protocol");
-             return 1;
+             if (a->fib_index == fib_index)
+               {
+                 while (1)
+                   {
+                     portnum = (port_per_thread * snat_thread_index) +
+                               nat_random_port (&nm->random_seed, 0,
+                                                port_per_thread - 1) +
+                               1024;
+                     if (nat44_ei_port_is_used (a, proto, portnum))
+                       continue;
+                     nat44_ei_port_get (a, proto, portnum);
+                     a->busy_ports_per_thread[proto][thread_index]++;
+                     a->busy_ports[proto]++;
+                     *addr = a->addr;
+                     *port = clib_host_to_net_u16 (portnum);
+                     return 0;
+                   }
+               }
+             else if (a->fib_index == ~0)
+               {
+                 ga = a;
+               }
            }
        }
-  if (ga)
-    {
-      a = ga;
-      // fake fib index to reuse macro
-      fib_index = ~0;
-      switch (proto)
+
+      if (ga)
        {
-         foreach_nat_protocol;
-           default : nat_elog_info (nm, "unknown protocol");
-         return 1;
+         a = ga;
+         if (a->busy_ports_per_thread[proto][thread_index] < port_per_thread)
+           {
+             if (a->fib_index == ~0)
+               {
+                 while (1)
+                   {
+                     portnum = (port_per_thread * snat_thread_index) +
+                               nat_random_port (&nm->random_seed, 0,
+                                                port_per_thread - 1) +
+                               1024;
+                     if (nat44_ei_port_is_used (a, proto, portnum))
+                       continue;
+                     nat44_ei_port_get (a, proto, portnum);
+                     a->busy_ports_per_thread[proto][thread_index]++;
+                     a->busy_ports[proto]++;
+                     *addr = a->addr;
+                     *port = clib_host_to_net_u16 (portnum);
+                     return 0;
+                   }
+               }
+           }
        }
     }
-    }
-
-#undef _
 
   /* Totally out of translations to use... */
   nat_ipfix_logging_addresses_exhausted (thread_index, 0);
@@ -1948,30 +1904,20 @@ nat44_ei_alloc_range_cb (nat44_ei_address_t *addresses, u32 fib_index,
   if (!vec_len (addresses))
     goto exhausted;
 
-  switch (proto)
-    {
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    if (a->busy_##n##_ports < ports)                                          \
-      {                                                                       \
-       while (1)                                                             \
-         {                                                                   \
-           portnum = nat_random_port (&nm->random_seed, nm->start_port,      \
-                                      nm->end_port);                         \
-           if (nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, portnum))         \
-             continue;                                                       \
-           nat44_ei_port_get (a, NAT_PROTOCOL_##N, portnum);                 \
-           a->busy_##n##_ports++;                                            \
-           *addr = a->addr;                                                  \
-           *port = clib_host_to_net_u16 (portnum);                           \
-           return 0;                                                         \
-         }                                                                   \
-      }                                                                       \
-    break;
-      foreach_nat_protocol
-#undef _
-       default : nat_elog_info (nm, "unknown protocol");
-      return 1;
+  if (a->busy_ports[proto] < ports)
+    {
+      while (1)
+       {
+         portnum =
+           nat_random_port (&nm->random_seed, nm->start_port, nm->end_port);
+         if (nat44_ei_port_is_used (a, proto, portnum))
+           continue;
+         nat44_ei_port_get (a, proto, portnum);
+         a->busy_ports[proto]++;
+         *addr = a->addr;
+         *port = clib_host_to_net_u16 (portnum);
+         return 0;
+       }
     }
 
 exhausted:
@@ -1995,32 +1941,22 @@ nat44_ei_alloc_mape_cb (nat44_ei_address_t *addresses, u32 fib_index,
   if (!vec_len (addresses))
     goto exhausted;
 
-  switch (proto)
-    {
-#define _(N, i, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    if (a->busy_##n##_ports < ports)                                          \
-      {                                                                       \
-       while (1)                                                             \
-         {                                                                   \
-           A = nat_random_port (&nm->random_seed, 1,                         \
-                                pow2_mask (nm->psid_offset));                \
-           j = nat_random_port (&nm->random_seed, 0, pow2_mask (m));         \
-           portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m));    \
-           if (nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, portnum))         \
-             continue;                                                       \
-           nat44_ei_port_get (a, NAT_PROTOCOL_##N, portnum);                 \
-           a->busy_##n##_ports++;                                            \
-           *addr = a->addr;                                                  \
-           *port = clib_host_to_net_u16 (portnum);                           \
-           return 0;                                                         \
-         }                                                                   \
-      }                                                                       \
-    break;
-      foreach_nat_protocol
-#undef _
-       default : nat_elog_info (nm, "unknown protocol");
-      return 1;
+  if (a->busy_ports[proto] < ports)
+    {
+      while (1)
+       {
+         A =
+           nat_random_port (&nm->random_seed, 1, pow2_mask (nm->psid_offset));
+         j = nat_random_port (&nm->random_seed, 0, pow2_mask (m));
+         portnum = A | (nm->psid << nm->psid_offset) | (j << (16 - m));
+         if (nat44_ei_port_is_used (a, proto, portnum))
+           continue;
+         nat44_ei_port_get (a, proto, portnum);
+         a->busy_ports[proto]++;
+         *addr = a->addr;
+         *port = clib_host_to_net_u16 (portnum);
+         return 0;
+       }
     }
 
 exhausted:
@@ -2171,29 +2107,18 @@ nat44_ei_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
       if (a->addr.as_u32 != addr.as_u32)
        continue;
 
-      switch (proto)
-       {
-#define _(N, j, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    if (nat44_ei_port_is_used (a, NAT_PROTOCOL_##N, port))                    \
-      continue;                                                               \
-    nat44_ei_port_get (a, NAT_PROTOCOL_##N, port);                            \
-    if (port > 1024)                                                          \
-      {                                                                       \
-       a->busy_##n##_ports++;                                                \
-       a->busy_##n##_ports_per_thread[ti]++;                                 \
-      }                                                                       \
-    break;
-         foreach_nat_protocol
-#undef _
-           default : nat_elog_info (nm, "unknown protocol");
-         goto done;
-       }
+      if (nat44_ei_port_is_used (a, proto, port))
+       continue;
 
+      nat44_ei_port_get (a, proto, port);
+      if (port > 1024)
+       {
+         a->busy_ports[proto]++;
+         a->busy_ports_per_thread[proto][ti]++;
+       }
       return 0;
     }
 
-done:
   return 1;
 }
 
@@ -2212,27 +2137,15 @@ nat44_ei_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
       if (a->addr.as_u32 != addr.as_u32)
        continue;
 
-      switch (proto)
-       {
-#define _(N, j, n, s)                                                         \
-  case NAT_PROTOCOL_##N:                                                      \
-    nat44_ei_port_put (a, NAT_PROTOCOL_##N, port);                            \
-    if (port > 1024)                                                          \
-      {                                                                       \
-       a->busy_##n##_ports--;                                                \
-       a->busy_##n##_ports_per_thread[ti]--;                                 \
-      }                                                                       \
-    break;
-         foreach_nat_protocol
-#undef _
-           default : nat_elog_info (nm, "unknown protocol");
-         goto done;
+      nat44_ei_port_put (a, proto, port);
+      if (port > 1024)
+       {
+         a->busy_ports[proto]--;
+         a->busy_ports_per_thread[proto][ti]--;
        }
-
       return 0;
     }
 
-done:
   return 1;
 }
 
@@ -3053,14 +2966,15 @@ nat44_ei_add_address (ip4_address_t *addr, u32 vrf_id)
        FIB_PROTOCOL_IP4, vrf_id, nm->fib_src_low);
     }
 
-#define _(N, i, n, s)                                                         \
-  ap->busy_##n##_port_bitmap = 0;                                             \
-  ap->busy_##n##_ports = 0;                                                   \
-  ap->busy_##n##_ports_per_thread = 0;                                        \
-  vec_validate_init_empty (ap->busy_##n##_ports_per_thread,                   \
-                          tm->n_vlib_mains - 1, 0);
-  foreach_nat_protocol
-#undef _
+  nat_protocol_t proto;
+  for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
+    {
+      ap->busy_port_bitmap[proto] = 0;
+      ap->busy_ports[proto] = 0;
+      ap->busy_ports_per_thread[proto] = 0;
+      vec_validate_init_empty (ap->busy_ports_per_thread[proto],
+                              tm->n_vlib_mains - 1, 0);
+    }
 
     nat44_ei_add_del_addr_to_fib_foreach_out_if (addr, 1);
 
@@ -3116,7 +3030,8 @@ nat44_ei_del_address (ip4_address_t addr, u8 delete_sm)
     }
 
   /* Delete sessions using address */
-  if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
+  if (a->busy_ports[NAT_PROTOCOL_TCP] || a->busy_ports[NAT_PROTOCOL_UDP] ||
+      a->busy_ports[NAT_PROTOCOL_ICMP])
     {
       vec_foreach (tnm, nm->per_thread_data)
        {
@@ -3145,11 +3060,13 @@ nat44_ei_del_address (ip4_address_t addr, u8 delete_sm)
       fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nm->fib_src_low);
     }
 
-#define _(N, i, n, s) vec_free (a->busy_##n##_ports_per_thread);
-  foreach_nat_protocol
-#undef _
+  nat_protocol_t proto;
+  for (proto = 0; proto < NAT_N_PROTOCOLS; ++proto)
+    {
+      vec_free (a->busy_ports_per_thread[proto]);
+    }
 
-    vec_del1 (nm->addresses, j);
+  vec_del1 (nm->addresses, j);
   return 0;
 }
 
index c79cbfe..b4aa0f2 100644 (file)
@@ -71,12 +71,9 @@ typedef struct
 {
   ip4_address_t addr;
   u32 fib_index;
-#define _(N, i, n, s)                                                         \
-  u32 busy_##n##_ports;                                                       \
-  u32 *busy_##n##_ports_per_thread;                                           \
-  uword *busy_##n##_port_bitmap;
-  foreach_nat_protocol
-#undef _
+  u32 busy_ports[NAT_N_PROTOCOLS];
+  u32 *busy_ports_per_thread[NAT_N_PROTOCOLS];
+  uword *busy_port_bitmap[NAT_N_PROTOCOLS];
 } nat44_ei_address_t;
 
 clib_error_t *nat44_ei_api_hookup (vlib_main_t *vm);
index 2fe01b0..75c9517 100644 (file)
@@ -841,7 +841,7 @@ nat44_ei_show_addresses_command_fn (vlib_main_t *vm, unformat_input_t *input,
       else
        vlib_cli_output (vm, "  tenant VRF independent");
 #define _(N, i, n, s)                                                         \
-  vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
+  vlib_cli_output (vm, "  %d busy %s ports", ap->busy_ports[i], s);
       foreach_nat_protocol
 #undef _
     }