LCOV - code coverage report
Current view: top level - plugins/nat/lib - alloc.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 31 64 48.4 %
Date: 2023-10-26 01:39:38 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /**
      16             :  * @file
      17             :  * @brief NAT port/address allocation lib
      18             :  */
      19             : 
      20             : #include <nat/lib/lib.h>
      21             : #include <nat/lib/alloc.h>
      22             : 
      23             : static_always_inline void
      24           1 : nat_ip4_addr_increment (ip4_address_t * addr)
      25             : {
      26             :   u32 v;
      27           1 :   v = clib_net_to_host_u32 (addr->as_u32) + 1;
      28           1 :   addr->as_u32 = clib_host_to_net_u32 (v);
      29           1 : }
      30             : 
      31             : int
      32           1 : nat_add_del_ip4_pool_addr (nat_ip4_pool_t * pool, ip4_address_t addr,
      33             :                            u8 is_add)
      34             : {
      35             :   int i;
      36           1 :   nat_ip4_pool_addr_t *a = 0;
      37           1 :   vlib_thread_main_t *tm = vlib_get_thread_main ();
      38             : 
      39             :   // lookup for the address
      40           1 :   for (i = 0; i < vec_len (pool->pool_addr); i++)
      41             :     {
      42           0 :       if (pool->pool_addr[i].addr.as_u32 == addr.as_u32)
      43             :         {
      44           0 :           a = pool->pool_addr + 1;
      45           0 :           break;
      46             :         }
      47             :     }
      48           1 :   if (is_add)
      49             :     {
      50           1 :       if (a)
      51           0 :         return NAT_ERROR_VALUE_EXIST;
      52           1 :       vec_add2 (pool->pool_addr, a, 1);
      53           1 :       a->addr = addr;
      54             : #define _(N, i, n, s) \
      55             :       clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535); \
      56             :       a->busy_##n##_ports = 0; \
      57             :       vec_validate_init_empty (a->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
      58           5 :       foreach_nat_protocol
      59             : #undef _
      60             :     }
      61             :   else
      62             :     {
      63           0 :       if (!a)
      64           0 :         return NAT_ERROR_NO_SUCH_ENTRY;
      65             : #define _(N, id, n, s) \
      66             :       clib_bitmap_free (a->busy_##n##_port_bitmap); \
      67             :       vec_free (a->busy_##n##_ports_per_thread);
      68           0 :       foreach_nat_protocol
      69             : #undef _
      70           0 :         vec_del1 (pool->pool_addr, i);
      71             :     }
      72           1 :   return 0;
      73             : }
      74             : 
      75             : int
      76           1 : nat_add_del_ip4_pool_addrs (nat_ip4_pool_t * pool,
      77             :                             ip4_address_t addr, u32 count, u8 is_add,
      78             :                             void *opaque)
      79             : {
      80             :   int i, rv;
      81             : 
      82           2 :   for (i = 0; i < count; i++)
      83             :     {
      84             :       // TODO:
      85             :       // a) consider if we could benefit from pre and post cb
      86             :       // b) consider if we could benefit from add/del cb separation
      87             : 
      88             :       // pre call:
      89             :       // pool->add_del_pool_addr_pre_cb (&addr, is_add, opaque);
      90             : 
      91           1 :       if ((rv = nat_add_del_ip4_pool_addr (pool, addr, is_add)) != 0)
      92           0 :         return rv;
      93             : 
      94             :       // post call:
      95             :       // pool->add_del_pool_addr_post_cb (&addr, is_add, opaque);
      96             : 
      97           1 :       pool->add_del_pool_addr_cb (addr, is_add, opaque);
      98           1 :       nat_ip4_addr_increment (&addr);
      99             :     }
     100             : 
     101           1 :   return 0;
     102             : }
     103             : 
     104             : static_always_inline u16
     105           3 : nat_random_port (u32 * random_seed, u16 min, u16 max)
     106             : {
     107           3 :   return min + random_u32 (random_seed) /
     108           3 :     (random_u32_max () / (max - min + 1) + 1);
     109             : }
     110             : 
     111             : int
     112           3 : nat_alloc_ip4_addr_and_port_cb_default (nat_ip4_pool_t * pool,
     113             :                                         u32 fib_index,
     114             :                                         u32 thread_index,
     115             :                                         u32 nat_thread_index,
     116             :                                         u16 port_per_thread,
     117             :                                         u16 protocol,
     118             :                                         nat_ip4_addr_port_t * out)
     119             : {
     120           3 :   nat_ip4_pool_addr_t *a, *ga = 0;
     121             :   u32 i;
     122             :   u32 portnum;
     123             : 
     124           3 :   for (i = 0; i < vec_len (pool->pool_addr); i++)
     125             :     {
     126           3 :       a = pool->pool_addr + i;
     127           3 :       switch (protocol)
     128             :         {
     129             : #define _(N, j, n, s) \
     130             :         case NAT_PROTOCOL_##N: \
     131             :           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
     132             :             { \
     133             :               if (a->fib_index == fib_index) \
     134             :                 { \
     135             :                   while (1) \
     136             :                     { \
     137             :                       portnum = (port_per_thread * \
     138             :                         nat_thread_index) + \
     139             :                         nat_random_port(&pool->random_seed, 1, port_per_thread) + 1024; \
     140             :                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
     141             :                         continue; \
     142             :                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
     143             :                       a->busy_##n##_ports_per_thread[thread_index]++; \
     144             :                       a->busy_##n##_ports++; \
     145             :                       out->addr = a->addr; \
     146             :                       out->port = clib_host_to_net_u16(portnum); \
     147             :                       return 0; \
     148             :                     } \
     149             :                 } \
     150             :               else if (a->fib_index == ~0) \
     151             :                 { \
     152             :                   ga = a; \
     153             :                 } \
     154             :             } \
     155             :           break;
     156           3 :           foreach_nat_protocol
     157             : #undef _
     158           0 :         default:
     159           0 :           return NAT_ERROR_UNKNOWN_PROTOCOL;
     160             :         }
     161             : 
     162             :     }
     163           0 :   if (ga)
     164             :     {
     165           0 :       a = ga;
     166           0 :       switch (protocol)
     167             :         {
     168             : #define _(N, j, n, s) \
     169             :         case NAT_PROTOCOL_##N: \
     170             :           while (1) \
     171             :             { \
     172             :               portnum = (port_per_thread * \
     173             :                 nat_thread_index) + \
     174             :                 nat_random_port(&pool->random_seed, 1, port_per_thread) + 1024; \
     175             :               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
     176             :                 continue; \
     177             :               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
     178             :               a->busy_##n##_ports_per_thread[thread_index]++; \
     179             :               a->busy_##n##_ports++; \
     180             :               out->addr = a->addr; \
     181             :               out->port = clib_host_to_net_u16(portnum); \
     182             :               return 0; \
     183             :             }
     184             :           break;
     185           0 :           foreach_nat_protocol
     186             : #undef _
     187           0 :         default:
     188           0 :           return NAT_ERROR_UNKNOWN_PROTOCOL;
     189             :         }
     190           0 :     }
     191           0 :   return NAT_ERROR_OUT_OF_TRANSLATIONS;
     192             : }
     193             : 
     194             : int
     195           3 : nat_alloc_ip4_addr_and_port (nat_ip4_pool_t * pool,
     196             :                              u32 fib_index,
     197             :                              u32 thread_index,
     198             :                              u32 nat_thread_index,
     199             :                              u16 port_per_thread,
     200             :                              u16 protocol, nat_ip4_addr_port_t * out)
     201             : {
     202           3 :   return pool->alloc_addr_and_port_cb (pool,
     203             :                                        fib_index,
     204             :                                        thread_index,
     205             :                                        nat_thread_index,
     206             :                                        port_per_thread, protocol, out);
     207             : }
     208             : 
     209             : // TODO: consider using standard u16 port and ip4_address_t as input ?
     210             : int
     211           0 : nat_free_ip4_addr_and_port (nat_ip4_pool_t * pool,
     212             :                             u32 thread_index,
     213             :                             u16 protocol, nat_ip4_addr_port_t * addr_port)
     214             : {
     215           0 :   nat_ip4_pool_addr_t *a = 0;
     216             :   u32 i;
     217           0 :   u16 port = clib_net_to_host_u16 (addr_port->port);
     218             : 
     219           0 :   for (i = 0; i < vec_len (pool->pool_addr); i++)
     220             :     {
     221           0 :       if (pool->pool_addr[i].addr.as_u32 == addr_port->addr.as_u32)
     222             :         {
     223           0 :           a = pool->pool_addr + i;
     224           0 :           break;
     225             :         }
     226             :     }
     227             : 
     228           0 :   if (!a)
     229             :     {
     230           0 :       return NAT_ERROR_NO_SUCH_ENTRY;
     231             :     }
     232             : 
     233           0 :   switch (protocol)
     234             :     {
     235             : #define _(N, i, n, s) \
     236             :     case NAT_PROTOCOL_##N: \
     237             :       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
     238             :         port) == 1); \
     239             :       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
     240             :         port, 0); \
     241             :       a->busy_##n##_ports--; \
     242             :       a->busy_##n##_ports_per_thread[thread_index]--; \
     243             :       break;
     244           0 :       foreach_nat_protocol
     245             : #undef _
     246           0 :     default:
     247           0 :       return NAT_ERROR_UNKNOWN_PROTOCOL;
     248             :     }
     249           0 :   return 0;
     250             : }
     251             : 
     252             : /*
     253             :  * fd.io coding-style-patch-verification: ON
     254             :  *
     255             :  * Local Variables:
     256             :  * eval: (c-set-style "gnu")
     257             :  * End:
     258             :  */

Generated by: LCOV version 1.14