FD.io VPP  v20.05-21-gb1500e9ff
Vector Packet Processing
alloc.c
Go to the documentation of this file.
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 
25 {
26  u32 v;
27  v = clib_net_to_host_u32 (addr->as_u32) + 1;
28  addr->as_u32 = clib_host_to_net_u32 (v);
29 }
30 
31 int
33  u8 is_add)
34 {
35  int i;
38 
39  // lookup for the address
40  for (i = 0; i < vec_len (pool->pool_addr); i++)
41  {
42  if (pool->pool_addr[i].addr.as_u32 == addr.as_u32)
43  {
44  a = pool->pool_addr + 1;
45  break;
46  }
47  }
48  if (is_add)
49  {
50  if (a)
51  return NAT_ERROR_VALUE_EXIST;
52  vec_add2 (pool->pool_addr, a, 1);
53  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);
59 #undef _
60  }
61  else
62  {
63  if (!a)
64  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);
69 #undef _
70  vec_del1 (pool->pool_addr, i);
71  }
72  return 0;
73 }
74 
75 int
77  ip4_address_t addr, u32 count, u8 is_add,
78  void *opaque)
79 {
80  int i, rv;
81 
82  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  if ((rv = nat_add_del_ip4_pool_addr (pool, addr, is_add)) != 0)
92  return rv;
93 
94  // post call:
95  // pool->add_del_pool_addr_post_cb (&addr, is_add, opaque);
96 
97  pool->add_del_pool_addr_cb (addr, is_add, opaque);
98  nat_ip4_addr_increment (&addr);
99  }
100 
101  return 0;
102 }
103 
105 nat_random_port (u32 random_seed, u16 min, u16 max)
106 {
107  return min + random_u32 (&random_seed) /
108  (random_u32_max () / (max - min + 1) + 1);
109 }
110 
111 int
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  nat_ip4_pool_addr_t *a, *ga = 0;
121  u32 i;
122  u32 portnum;
123 
124  for (i = 0; i < vec_len (pool->pool_addr); i++)
125  {
126  a = pool->pool_addr + i;
127  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;
157 #undef _
158  default:
159  return NAT_ERROR_UNKNOWN_PROTOCOL;
160  }
161 
162  }
163  if (ga)
164  {
165  a = ga;
166  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;
186 #undef _
187  default:
188  return NAT_ERROR_UNKNOWN_PROTOCOL;
189  }
190  }
191  return NAT_ERROR_OUT_OF_TRANSLATIONS;
192 }
193 
194 int
196  u32 fib_index,
197  u32 thread_index,
198  u32 nat_thread_index,
199  u16 port_per_thread,
201 {
202  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
212  u32 thread_index,
213  u16 protocol, nat_ip4_addr_port_t * addr_port)
214 {
215  nat_ip4_pool_addr_t *a = 0;
216  u32 i;
217  u16 port = clib_net_to_host_u16 (addr_port->port);
218 
219  for (i = 0; i < vec_len (pool->pool_addr); i++)
220  {
221  if (pool->pool_addr[i].addr.as_u32 == addr_port->addr.as_u32)
222  {
223  a = pool->pool_addr + i;
224  break;
225  }
226  }
227 
228  if (!a)
229  {
230  return NAT_ERROR_NO_SUCH_ENTRY;
231  }
232 
233  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;
245 #undef _
246  default:
247  return NAT_ERROR_UNKNOWN_PROTOCOL;
248  }
249  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  */
u8 count
Definition: dhcp.api:208
int nat_alloc_ip4_addr_and_port_cb_default(nat_ip4_pool_t *pool, u32 fib_index, u32 thread_index, u32 nat_thread_index, u16 port_per_thread, u16 protocol, nat_ip4_addr_port_t *out)
Definition: alloc.c:112
a
Definition: bitmap.h:538
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:628
ip4_address_t addr
Definition: alloc.h:56
NAT port/address allocation lib.
vhost_vring_addr_t addr
Definition: vhost_user.h:254
unsigned char u8
Definition: types.h:56
static_always_inline void nat_ip4_addr_increment(ip4_address_t *addr)
Definition: alloc.c:24
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
#define static_always_inline
Definition: clib.h:106
nat_alloc_ip4_addr_and_port_cb_t * alloc_addr_and_port_cb
Definition: alloc.h:63
unsigned int u32
Definition: types.h:88
unsigned short u16
Definition: types.h:57
#define vec_del1(v, i)
Delete the element at index I.
Definition: vec.h:873
int nat_add_del_ip4_pool_addr(nat_ip4_pool_t *pool, ip4_address_t addr, u8 is_add)
Definition: alloc.c:32
nat_add_del_ip4_pool_addr_cb_t * add_del_pool_addr_cb
Definition: alloc.h:62
nat_ip4_pool_addr_t * pool_addr
Definition: alloc.h:64
NAT port/address allocation lib.
static u32 random_u32_max(void)
Maximum value returned by random_u32()
Definition: random.h:80
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
int nat_alloc_ip4_addr_and_port(nat_ip4_pool_t *pool, u32 fib_index, u32 thread_index, u32 nat_thread_index, u16 port_per_thread, u16 protocol, nat_ip4_addr_port_t *out)
Definition: alloc.c:195
static_always_inline u16 nat_random_port(u32 random_seed, u16 min, u16 max)
Definition: alloc.c:105
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u16 port
Definition: lb_types.api:72
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
ip4_address_t addr
Definition: alloc.h:42
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
int nat_add_del_ip4_pool_addrs(nat_ip4_pool_t *pool, ip4_address_t addr, u32 count, u8 is_add, void *opaque)
Definition: alloc.c:76
int nat_free_ip4_addr_and_port(nat_ip4_pool_t *pool, u32 thread_index, u16 protocol, nat_ip4_addr_port_t *addr_port)
Definition: alloc.c:211