FD.io VPP  v17.07.01-10-g3be13f0
Vector Packet Processing
nat64_db.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 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 NAT64 DB
18  */
19 #include <snat/nat64_db.h>
20 
21 int
23 {
24  u32 bib_buckets = 1024;
25  u32 bib_memory_size = 128 << 20;
26  u32 st_buckets = 2048;
27  u32 st_memory_size = 256 << 20;
28 
29  clib_bihash_init_24_8 (&db->bib.in2out, "bib-in2out", bib_buckets,
30  bib_memory_size);
31 
32  clib_bihash_init_24_8 (&db->bib.out2in, "bib-out2in", bib_buckets,
33  bib_memory_size);
34 
35  clib_bihash_init_48_8 (&db->st.in2out, "st-in2out", st_buckets,
36  st_memory_size);
37 
38  clib_bihash_init_48_8 (&db->st.out2in, "st-out2in", st_buckets,
39  st_memory_size);
40 
41  return 0;
42 }
43 
44 nat64_db_bib_entry_t *
46  ip4_address_t * out_addr, u16 in_port,
47  u16 out_port, u32 fib_index, snat_protocol_t proto,
48  u8 is_static)
49 {
50  nat64_db_bib_entry_t *bibe;
51  nat64_db_bib_entry_key_t bibe_key;
53 
54  /* create pool entry */
55  switch (proto)
56  {
57 /* *INDENT-OFF* */
58 #define _(N, i, n, s) \
59  case SNAT_PROTOCOL_##N: \
60  pool_get (db->bib._##n##_bib, bibe); \
61  kv.value = bibe - db->bib._##n##_bib; \
62  break;
64 #undef _
65 /* *INDENT-ON* */
66  default:
67  clib_warning ("unknown protocol %u", proto);
68  return 0;
69  }
70  memset (bibe, 0, sizeof (*bibe));
71  bibe->in_addr.as_u64[0] = in_addr->as_u64[0];
72  bibe->in_addr.as_u64[1] = in_addr->as_u64[1];
73  bibe->in_port = in_port;
74  bibe->out_addr.as_u32 = out_addr->as_u32;
75  bibe->out_port = out_port;
76  bibe->fib_index = fib_index;
77  bibe->proto = proto;
78  bibe->is_static = is_static;
79 
80  /* create hash lookup */
81  bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
82  bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
83  bibe_key.fib_index = bibe->fib_index;
84  bibe_key.port = bibe->in_port;
85  bibe_key.proto = bibe->proto;
86  bibe_key.rsvd = 0;
87  kv.key[0] = bibe_key.as_u64[0];
88  kv.key[1] = bibe_key.as_u64[1];
89  kv.key[2] = bibe_key.as_u64[2];
90  clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 1);
91 
92  memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
93  bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
94  bibe_key.fib_index = 0;
95  bibe_key.port = bibe->out_port;
96  kv.key[0] = bibe_key.as_u64[0];
97  kv.key[1] = bibe_key.as_u64[1];
98  kv.key[2] = bibe_key.as_u64[2];
99  clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 1);
100 
101  return bibe;
102 }
103 
104 void
105 nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe)
106 {
107  nat64_db_bib_entry_key_t bibe_key;
109  nat64_db_bib_entry_t *bib;
110  u32 *ste_to_be_free = 0, *ste_index, bibe_index;
111  nat64_db_st_entry_t *st, *ste;
112 
113  switch (bibe->proto)
114  {
115 /* *INDENT-OFF* */
116 #define _(N, i, n, s) \
117  case SNAT_PROTOCOL_##N: \
118  bib = db->bib._##n##_bib; \
119  st = db->st._##n##_st; \
120  break;
122 #undef _
123 /* *INDENT-ON* */
124  default:
125  clib_warning ("unknown protocol %u", bibe->proto);
126  return;
127  }
128 
129  bibe_index = bibe - bib;
130 
131  /* delete ST entries for static BIB entry */
132  if (bibe->is_static)
133  {
134  pool_foreach (ste, st, (
135  {
136  if (ste->bibe_index == bibe_index)
137  vec_add1 (ste_to_be_free, ste - st);}
138  ));
139  vec_foreach (ste_index, ste_to_be_free)
140  nat64_db_st_entry_free (db, pool_elt_at_index (st, ste_index[0]));
141  vec_free (ste_to_be_free);
142  }
143 
144  /* delete hash lookup */
145  bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
146  bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
147  bibe_key.fib_index = bibe->fib_index;
148  bibe_key.port = bibe->in_port;
149  bibe_key.proto = bibe->proto;
150  bibe_key.rsvd = 0;
151  kv.key[0] = bibe_key.as_u64[0];
152  kv.key[1] = bibe_key.as_u64[1];
153  kv.key[2] = bibe_key.as_u64[2];
154  clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 0);
155 
156  memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
157  bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
158  bibe_key.fib_index = 0;
159  bibe_key.port = bibe->out_port;
160  kv.key[0] = bibe_key.as_u64[0];
161  kv.key[1] = bibe_key.as_u64[1];
162  kv.key[2] = bibe_key.as_u64[2];
163  clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 0);
164 
165  /* delete from pool */
166  pool_put (bib, bibe);
167 
168 }
169 
170 nat64_db_bib_entry_t *
171 nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port,
172  snat_protocol_t proto, u32 fib_index, u8 is_ip6)
173 {
174  nat64_db_bib_entry_t *bibe = 0;
175  nat64_db_bib_entry_key_t bibe_key;
176  clib_bihash_kv_24_8_t kv, value;
177  nat64_db_bib_entry_t *bib;
178 
179  switch (proto)
180  {
181 /* *INDENT-OFF* */
182 #define _(N, i, n, s) \
183  case SNAT_PROTOCOL_##N: \
184  bib = db->bib._##n##_bib; \
185  break;
187 #undef _
188 /* *INDENT-ON* */
189  default:
190  clib_warning ("unknown protocol %u", proto);
191  return 0;
192  }
193 
194  bibe_key.addr.as_u64[0] = addr->as_u64[0];
195  bibe_key.addr.as_u64[1] = addr->as_u64[1];
196  bibe_key.fib_index = fib_index;
197  bibe_key.port = port;
198  bibe_key.proto = proto;
199  bibe_key.rsvd = 0;
200 
201  kv.key[0] = bibe_key.as_u64[0];
202  kv.key[1] = bibe_key.as_u64[1];
203  kv.key[2] = bibe_key.as_u64[2];
204 
205  if (!clib_bihash_search_24_8
206  (is_ip6 ? &db->bib.in2out : &db->bib.out2in, &kv, &value))
207  bibe = pool_elt_at_index (bib, value.value);
208 
209  return bibe;
210 }
211 
212 void
214  nat64_db_bib_walk_fn_t fn, void *ctx)
215 {
216  nat64_db_bib_entry_t *bib, *bibe;
217 
218  switch (proto)
219  {
220 /* *INDENT-OFF* */
221 #define _(N, i, n, s) \
222  case SNAT_PROTOCOL_##N: \
223  bib = db->bib._##n##_bib; \
224  break;
226 #undef _
227 /* *INDENT-ON* */
228  default:
229  clib_warning ("unknown protocol");
230  return;
231  }
232 
233  /* *INDENT-OFF* */
234  pool_foreach (bibe, bib,
235  ({
236  if (fn (bibe, ctx))
237  return;
238  }));
239  /* *INDENT-ON* */
240 }
241 
242 nat64_db_bib_entry_t *
244  u32 bibe_index)
245 {
246  nat64_db_bib_entry_t *bib;
247 
248  switch (proto)
249  {
250 /* *INDENT-OFF* */
251 #define _(N, i, n, s) \
252  case SNAT_PROTOCOL_##N: \
253  bib = db->bib._##n##_bib; \
254  break;
256 #undef _
257 /* *INDENT-ON* */
258  default:
259  clib_warning ("unknown protocol %u", proto);
260  return 0;
261  }
262 
263  return pool_elt_at_index (bib, bibe_index);
264 }
265 
266 void
268  nat64_db_st_walk_fn_t fn, void *ctx)
269 {
270  nat64_db_st_entry_t *st, *ste;
271 
272  switch (proto)
273  {
274 /* *INDENT-OFF* */
275 #define _(N, i, n, s) \
276  case SNAT_PROTOCOL_##N: \
277  st = db->st._##n##_st; \
278  break;
280 #undef _
281 /* *INDENT-ON* */
282  default:
283  clib_warning ("unknown protocol");
284  return;
285  }
286 
287  /* *INDENT-OFF* */
288  pool_foreach (ste, st,
289  ({
290  if (fn (ste, ctx))
291  return;
292  }));
293  /* *INDENT-ON* */
294 }
295 
296 nat64_db_st_entry_t *
297 nat64_db_st_entry_create (nat64_db_t * db, nat64_db_bib_entry_t * bibe,
298  ip6_address_t * in_r_addr,
299  ip4_address_t * out_r_addr, u16 r_port)
300 {
301  nat64_db_st_entry_t *ste;
302  nat64_db_bib_entry_t *bib;
303  nat64_db_st_entry_key_t ste_key;
305 
306  /* create pool entry */
307  switch (bibe->proto)
308  {
309 /* *INDENT-OFF* */
310 #define _(N, i, n, s) \
311  case SNAT_PROTOCOL_##N: \
312  pool_get (db->st._##n##_st, ste); \
313  kv.value = ste - db->st._##n##_st; \
314  bib = db->bib._##n##_bib; \
315  break;
317 #undef _
318 /* *INDENT-ON* */
319  default:
320  clib_warning ("unknown protocol %u", bibe->proto);
321  return 0;
322  }
323  memset (ste, 0, sizeof (*ste));
324  ste->in_r_addr.as_u64[0] = in_r_addr->as_u64[0];
325  ste->in_r_addr.as_u64[1] = in_r_addr->as_u64[1];
326  ste->out_r_addr.as_u32 = out_r_addr->as_u32;
327  ste->r_port = r_port;
328  ste->bibe_index = bibe - bib;
329  ste->proto = bibe->proto;
330 
331  /* increment session number for BIB entry */
332  bibe->ses_num++;
333 
334  /* create hash lookup */
335  memset (&ste_key, 0, sizeof (ste_key));
336  ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
337  ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
338  ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
339  ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
340  ste_key.fib_index = bibe->fib_index;
341  ste_key.l_port = bibe->in_port;
342  ste_key.r_port = ste->r_port;
343  ste_key.proto = ste->proto;
344  kv.key[0] = ste_key.as_u64[0];
345  kv.key[1] = ste_key.as_u64[1];
346  kv.key[2] = ste_key.as_u64[2];
347  kv.key[3] = ste_key.as_u64[3];
348  kv.key[4] = ste_key.as_u64[4];
349  kv.key[5] = ste_key.as_u64[5];
350  clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 1);
351 
352  memset (&ste_key, 0, sizeof (ste_key));
353  ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
354  ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
355  ste_key.l_port = bibe->out_port;
356  ste_key.r_port = ste->r_port;
357  ste_key.proto = ste->proto;
358  kv.key[0] = ste_key.as_u64[0];
359  kv.key[1] = ste_key.as_u64[1];
360  kv.key[2] = ste_key.as_u64[2];
361  kv.key[3] = ste_key.as_u64[3];
362  kv.key[4] = ste_key.as_u64[4];
363  kv.key[5] = ste_key.as_u64[5];
364  clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 1);
365 
366  return ste;
367 }
368 
369 void
370 nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste)
371 {
372  nat64_db_st_entry_t *st;
373  nat64_db_bib_entry_t *bib, *bibe;
374  nat64_db_st_entry_key_t ste_key;
376 
377  switch (ste->proto)
378  {
379 /* *INDENT-OFF* */
380 #define _(N, i, n, s) \
381  case SNAT_PROTOCOL_##N: \
382  st = db->st._##n##_st; \
383  bib = db->bib._##n##_bib; \
384  break;
386 #undef _
387 /* *INDENT-ON* */
388  default:
389  clib_warning ("unknown protocol %u", ste->proto);
390  return;
391  }
392 
393  bibe = pool_elt_at_index (bib, ste->bibe_index);
394 
395  /* delete hash lookup */
396  memset (&ste_key, 0, sizeof (ste_key));
397  ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
398  ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
399  ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
400  ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
401  ste_key.fib_index = bibe->fib_index;
402  ste_key.l_port = bibe->in_port;
403  ste_key.r_port = ste->r_port;
404  ste_key.proto = ste->proto;
405  kv.key[0] = ste_key.as_u64[0];
406  kv.key[1] = ste_key.as_u64[1];
407  kv.key[2] = ste_key.as_u64[2];
408  kv.key[3] = ste_key.as_u64[3];
409  kv.key[4] = ste_key.as_u64[4];
410  kv.key[5] = ste_key.as_u64[5];
411  clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 0);
412 
413  memset (&ste_key, 0, sizeof (ste_key));
414  ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
415  ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
416  ste_key.l_port = bibe->out_port;
417  ste_key.r_port = ste->r_port;
418  ste_key.proto = ste->proto;
419  kv.key[0] = ste_key.as_u64[0];
420  kv.key[1] = ste_key.as_u64[1];
421  kv.key[2] = ste_key.as_u64[2];
422  kv.key[3] = ste_key.as_u64[3];
423  kv.key[4] = ste_key.as_u64[4];
424  kv.key[5] = ste_key.as_u64[5];
425  clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 0);
426 
427  /* delete from pool */
428  pool_put (st, ste);
429 
430  /* decrement session number for BIB entry */
431  bibe->ses_num--;
432 
433  /* delete BIB entry if last session and dynamic */
434  if (!bibe->is_static && !bibe->ses_num)
435  nat64_db_bib_entry_free (db, bibe);
436 }
437 
438 nat64_db_st_entry_t *
439 nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr,
440  ip46_address_t * r_addr, u16 l_port, u16 r_port,
441  snat_protocol_t proto, u32 fib_index, u8 is_ip6)
442 {
443  nat64_db_st_entry_t *ste = 0;
444  nat64_db_st_entry_t *st;
445  nat64_db_st_entry_key_t ste_key;
446  clib_bihash_kv_48_8_t kv, value;
447 
448  switch (proto)
449  {
450 /* *INDENT-OFF* */
451 #define _(N, i, n, s) \
452  case SNAT_PROTOCOL_##N: \
453  st = db->st._##n##_st; \
454  break;
456 #undef _
457 /* *INDENT-ON* */
458  default:
459  clib_warning ("unknown protocol %u", proto);
460  return ste;
461  }
462 
463  memset (&ste_key, 0, sizeof (ste_key));
464  ste_key.l_addr.as_u64[0] = l_addr->as_u64[0];
465  ste_key.l_addr.as_u64[1] = l_addr->as_u64[1];
466  ste_key.r_addr.as_u64[0] = r_addr->as_u64[0];
467  ste_key.r_addr.as_u64[1] = r_addr->as_u64[1];
468  ste_key.fib_index = fib_index;
469  ste_key.l_port = l_port;
470  ste_key.r_port = r_port;
471  ste_key.proto = proto;
472  kv.key[0] = ste_key.as_u64[0];
473  kv.key[1] = ste_key.as_u64[1];
474  kv.key[2] = ste_key.as_u64[2];
475  kv.key[3] = ste_key.as_u64[3];
476  kv.key[4] = ste_key.as_u64[4];
477  kv.key[5] = ste_key.as_u64[5];
478 
479  if (!clib_bihash_search_48_8
480  (is_ip6 ? &db->st.in2out : &db->st.out2in, &kv, &value))
481  ste = pool_elt_at_index (st, value.value);
482 
483  return ste;
484 }
485 
486 void
488 {
489  u32 *ste_to_be_free = 0, *ste_index;
490  nat64_db_st_entry_t *st, *ste;
491 
492 /* *INDENT-OFF* */
493 #define _(N, i, n, s) \
494  st = db->st._##n##_st; \
495  pool_foreach (ste, st, ({\
496  if (i == SNAT_PROTOCOL_TCP && !ste->tcp_state) \
497  continue; \
498  if (ste->expire < now) \
499  vec_add1 (ste_to_be_free, ste - st); \
500  })); \
501  vec_foreach (ste_index, ste_to_be_free) \
502  nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
503  vec_free (ste_to_be_free); \
504  ste_to_be_free = 0;
506 #undef _
507 /* *INDENT-ON* */
508 }
509 
510 /*
511  * fd.io coding-style-patch-verification: ON
512  *
513  * Local Variables:
514  * eval: (c-set-style "gnu")
515  * End:
516  */
Definition: nat64_db.h:72
nat64_db_bib_t bib
Definition: nat64_db.h:120
u16 l_port
Definition: nat64_db.h:81
void nat64_db_st_walk(nat64_db_t *db, snat_protocol_t proto, nat64_db_st_walk_fn_t fn, void *ctx)
Walk NAT64 session table.
Definition: nat64_db.c:267
nat64_db_bib_entry_t * nat64_db_bib_entry_create(nat64_db_t *db, ip6_address_t *in_addr, ip4_address_t *out_addr, u16 in_port, u16 out_port, u32 fib_index, snat_protocol_t proto, u8 is_static)
Create new NAT64 BIB entry.
Definition: nat64_db.c:45
u64 as_u64[2]
Definition: ip6_packet.h:51
nat64_db_st_entry_t * nat64_db_st_entry_create(nat64_db_t *db, nat64_db_bib_entry_t *bibe, ip6_address_t *in_r_addr, ip4_address_t *out_r_addr, u16 r_port)
Create new NAT64 session table entry.
Definition: nat64_db.c:297
Definition: nat64_db.h:27
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
u32 fib_index
Definition: nat64_db.h:80
int(* nat64_db_bib_walk_fn_t)(nat64_db_bib_entry_t *bibe, void *ctx)
Call back function when walking NAT64 BIB, non-zero return value stop walk.
Definition: nat64_db.h:167
ip46_address_t l_addr
Definition: nat64_db.h:78
nat64_db_st_entry_t * nat64_db_st_entry_find(nat64_db_t *db, ip46_address_t *l_addr, ip46_address_t *r_addr, u16 l_port, u16 r_port, snat_protocol_t proto, u32 fib_index, u8 is_ip6)
Find NAT64 session table entry.
Definition: nat64_db.c:439
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
foreach_snat_protocol clib_bihash_48_8_t in2out
Definition: nat64_db.h:114
nat64_db_bib_entry_t * nat64_db_bib_entry_find(nat64_db_t *db, ip46_address_t *addr, u16 port, snat_protocol_t proto, u32 fib_index, u8 is_ip6)
Find NAT64 BIB entry.
Definition: nat64_db.c:171
u16 r_port
Definition: nat64_db.h:82
u16 port
Definition: nat64_db.h:35
u64 as_u64[6]
Definition: nat64_db.h:86
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:397
void nad64_db_st_free_expired(nat64_db_t *db, u32 now)
Free expired session entries in session tables.
Definition: nat64_db.c:487
void nat64_db_bib_walk(nat64_db_t *db, snat_protocol_t proto, nat64_db_bib_walk_fn_t fn, void *ctx)
Walk NAT64 BIB.
Definition: nat64_db.c:213
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:241
void nat64_db_bib_entry_free(nat64_db_t *db, nat64_db_bib_entry_t *bibe)
Free NAT64 BIB entry.
Definition: nat64_db.c:105
foreach_snat_protocol clib_bihash_24_8_t in2out
Definition: nat64_db.h:68
nat64_db_bib_entry_t * nat64_db_bib_entry_by_index(nat64_db_t *db, snat_protocol_t proto, u32 bibe_index)
Get BIB entry by index and protocol.
Definition: nat64_db.c:243
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
ip46_address_t addr
Definition: nat64_db.h:33
#define clib_warning(format, args...)
Definition: error.h:59
snat_protocol_t
Definition: snat.h:98
u8 proto
Definition: nat64_db.h:83
unsigned int u32
Definition: types.h:88
u32 fib_index
Definition: nat64_db.h:34
u8 proto
Definition: nat64_db.h:36
unsigned short u16
Definition: types.h:57
clib_bihash_24_8_t out2in
Definition: nat64_db.h:69
unsigned char u8
Definition: types.h:56
void nat64_db_st_entry_free(nat64_db_t *db, nat64_db_st_entry_t *ste)
Free NAT64 session table entry.
Definition: nat64_db.c:370
int(* nat64_db_st_walk_fn_t)(nat64_db_st_entry_t *ste, void *ctx)
Call back function when walking NAT64 session table, non-zero return value stop walk.
Definition: nat64_db.h:260
NAT64 DB.
#define vec_foreach(var, vec)
Vector iterator.
nat64_db_st_t st
Definition: nat64_db.h:121
vhost_vring_addr_t addr
Definition: vhost-user.h:82
u8 rsvd
Definition: nat64_db.h:37
int nat64_db_init(nat64_db_t *db)
Initialize NAT64 DB.
Definition: nat64_db.c:22
u64 as_u64[3]
Definition: nat64_db.h:39
ip46_address_t r_addr
Definition: nat64_db.h:79
clib_bihash_48_8_t out2in
Definition: nat64_db.h:115