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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <nat/nat64_db.h>
22 nat64_db_init (nat64_db_t * db, u32 bib_buckets, u32 bib_memory_size,
23 u32 st_buckets, u32 st_memory_size,
24 nat64_db_free_addr_port_function_t free_addr_port_cb)
26 clib_bihash_init_24_8 (&db->bib.in2out, "bib-in2out", bib_buckets,
29 clib_bihash_init_24_8 (&db->bib.out2in, "bib-out2in", bib_buckets,
32 clib_bihash_init_48_8 (&db->st.in2out, "st-in2out", st_buckets,
35 clib_bihash_init_48_8 (&db->st.out2in, "st-out2in", st_buckets,
38 db->free_addr_port_cb = free_addr_port_cb;
42 nat64_db_bib_entry_t *
43 nat64_db_bib_entry_create (nat64_db_t * db, ip6_address_t * in_addr,
44 ip4_address_t * out_addr, u16 in_port,
45 u16 out_port, u32 fib_index, u8 proto,
48 nat64_db_bib_entry_t *bibe;
49 nat64_db_bib_entry_key_t bibe_key;
50 clib_bihash_kv_24_8_t kv;
52 /* create pool entry */
53 switch (ip_proto_to_snat_proto (proto))
56 #define _(N, i, n, s) \
57 case SNAT_PROTOCOL_##N: \
58 pool_get (db->bib._##n##_bib, bibe); \
59 kv.value = bibe - db->bib._##n##_bib; \
65 pool_get (db->bib._unk_proto_bib, bibe);
66 kv.value = bibe - db->bib._unk_proto_bib;
69 memset (bibe, 0, sizeof (*bibe));
70 bibe->in_addr.as_u64[0] = in_addr->as_u64[0];
71 bibe->in_addr.as_u64[1] = in_addr->as_u64[1];
72 bibe->in_port = in_port;
73 bibe->out_addr.as_u32 = out_addr->as_u32;
74 bibe->out_port = out_port;
75 bibe->fib_index = fib_index;
77 bibe->is_static = is_static;
79 /* create hash lookup */
80 bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
81 bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
82 bibe_key.fib_index = bibe->fib_index;
83 bibe_key.port = bibe->in_port;
84 bibe_key.proto = bibe->proto;
86 kv.key[0] = bibe_key.as_u64[0];
87 kv.key[1] = bibe_key.as_u64[1];
88 kv.key[2] = bibe_key.as_u64[2];
89 clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 1);
91 memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
92 bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
93 bibe_key.fib_index = 0;
94 bibe_key.port = bibe->out_port;
95 kv.key[0] = bibe_key.as_u64[0];
96 kv.key[1] = bibe_key.as_u64[1];
97 kv.key[2] = bibe_key.as_u64[2];
98 clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 1);
104 nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe)
106 nat64_db_bib_entry_key_t bibe_key;
107 clib_bihash_kv_24_8_t kv;
108 nat64_db_bib_entry_t *bib;
109 u32 *ste_to_be_free = 0, *ste_index, bibe_index;
110 nat64_db_st_entry_t *st, *ste;
112 switch (ip_proto_to_snat_proto (bibe->proto))
115 #define _(N, i, n, s) \
116 case SNAT_PROTOCOL_##N: \
117 bib = db->bib._##n##_bib; \
118 st = db->st._##n##_st; \
120 foreach_snat_protocol
124 bib = db->bib._unk_proto_bib;
125 st = db->st._unk_proto_st;
129 bibe_index = bibe - bib;
131 /* delete ST entries for static BIB entry */
134 pool_foreach (ste, st, (
136 if (ste->bibe_index == bibe_index)
137 vec_add1 (ste_to_be_free, ste - st);}
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);
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;
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);
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);
165 db->free_addr_port_cb (db, &bibe->out_addr, bibe->out_port, bibe->proto);
166 /* delete from pool */
167 pool_put (bib, bibe);
171 nat64_db_bib_entry_t *
172 nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port,
173 u8 proto, u32 fib_index, u8 is_ip6)
175 nat64_db_bib_entry_t *bibe = 0;
176 nat64_db_bib_entry_key_t bibe_key;
177 clib_bihash_kv_24_8_t kv, value;
178 nat64_db_bib_entry_t *bib;
180 switch (ip_proto_to_snat_proto (proto))
183 #define _(N, i, n, s) \
184 case SNAT_PROTOCOL_##N: \
185 bib = db->bib._##n##_bib; \
187 foreach_snat_protocol
191 bib = db->bib._unk_proto_bib;
195 bibe_key.addr.as_u64[0] = addr->as_u64[0];
196 bibe_key.addr.as_u64[1] = addr->as_u64[1];
197 bibe_key.fib_index = fib_index;
198 bibe_key.port = port;
199 bibe_key.proto = proto;
202 kv.key[0] = bibe_key.as_u64[0];
203 kv.key[1] = bibe_key.as_u64[1];
204 kv.key[2] = bibe_key.as_u64[2];
206 if (!clib_bihash_search_24_8
207 (is_ip6 ? &db->bib.in2out : &db->bib.out2in, &kv, &value))
208 bibe = pool_elt_at_index (bib, value.value);
214 nat64_db_bib_walk (nat64_db_t * db, u8 proto,
215 nat64_db_bib_walk_fn_t fn, void *ctx)
217 nat64_db_bib_entry_t *bib, *bibe;
222 #define _(N, i, n, s) \
223 bib = db->bib._##n##_bib; \
224 pool_foreach (bibe, bib, ({ \
225 if (fn (bibe, ctx)) \
228 foreach_snat_protocol
230 bib = db->bib._unk_proto_bib;
231 pool_foreach (bibe, bib, ({
239 switch (ip_proto_to_snat_proto (proto))
242 #define _(N, i, n, s) \
243 case SNAT_PROTOCOL_##N: \
244 bib = db->bib._##n##_bib; \
246 foreach_snat_protocol
250 bib = db->bib._unk_proto_bib;
255 pool_foreach (bibe, bib,
264 nat64_db_bib_entry_t *
265 nat64_db_bib_entry_by_index (nat64_db_t * db, u8 proto, u32 bibe_index)
267 nat64_db_bib_entry_t *bib;
269 switch (ip_proto_to_snat_proto (proto))
272 #define _(N, i, n, s) \
273 case SNAT_PROTOCOL_##N: \
274 bib = db->bib._##n##_bib; \
276 foreach_snat_protocol
280 bib = db->bib._unk_proto_bib;
284 return pool_elt_at_index (bib, bibe_index);
288 nat64_db_st_walk (nat64_db_t * db, u8 proto,
289 nat64_db_st_walk_fn_t fn, void *ctx)
291 nat64_db_st_entry_t *st, *ste;
296 #define _(N, i, n, s) \
297 st = db->st._##n##_st; \
298 pool_foreach (ste, st, ({ \
302 foreach_snat_protocol
304 st = db->st._unk_proto_st;
305 pool_foreach (ste, st, ({
313 switch (ip_proto_to_snat_proto (proto))
316 #define _(N, i, n, s) \
317 case SNAT_PROTOCOL_##N: \
318 st = db->st._##n##_st; \
320 foreach_snat_protocol
324 st = db->st._unk_proto_st;
329 pool_foreach (ste, st,
338 nat64_db_st_entry_t *
339 nat64_db_st_entry_create (nat64_db_t * db, nat64_db_bib_entry_t * bibe,
340 ip6_address_t * in_r_addr,
341 ip4_address_t * out_r_addr, u16 r_port)
343 nat64_db_st_entry_t *ste;
344 nat64_db_bib_entry_t *bib;
345 nat64_db_st_entry_key_t ste_key;
346 clib_bihash_kv_48_8_t kv;
348 /* create pool entry */
349 switch (ip_proto_to_snat_proto (bibe->proto))
352 #define _(N, i, n, s) \
353 case SNAT_PROTOCOL_##N: \
354 pool_get (db->st._##n##_st, ste); \
355 kv.value = ste - db->st._##n##_st; \
356 bib = db->bib._##n##_bib; \
358 foreach_snat_protocol
362 pool_get (db->st._unk_proto_st, ste);
363 kv.value = ste - db->st._unk_proto_st;
364 bib = db->bib._unk_proto_bib;
367 memset (ste, 0, sizeof (*ste));
368 ste->in_r_addr.as_u64[0] = in_r_addr->as_u64[0];
369 ste->in_r_addr.as_u64[1] = in_r_addr->as_u64[1];
370 ste->out_r_addr.as_u32 = out_r_addr->as_u32;
371 ste->r_port = r_port;
372 ste->bibe_index = bibe - bib;
373 ste->proto = bibe->proto;
375 /* increment session number for BIB entry */
378 /* create hash lookup */
379 memset (&ste_key, 0, sizeof (ste_key));
380 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
381 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
382 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
383 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
384 ste_key.fib_index = bibe->fib_index;
385 ste_key.l_port = bibe->in_port;
386 ste_key.r_port = ste->r_port;
387 ste_key.proto = ste->proto;
388 kv.key[0] = ste_key.as_u64[0];
389 kv.key[1] = ste_key.as_u64[1];
390 kv.key[2] = ste_key.as_u64[2];
391 kv.key[3] = ste_key.as_u64[3];
392 kv.key[4] = ste_key.as_u64[4];
393 kv.key[5] = ste_key.as_u64[5];
394 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 1);
396 memset (&ste_key, 0, sizeof (ste_key));
397 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
398 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
399 ste_key.l_port = bibe->out_port;
400 ste_key.r_port = ste->r_port;
401 ste_key.proto = ste->proto;
402 kv.key[0] = ste_key.as_u64[0];
403 kv.key[1] = ste_key.as_u64[1];
404 kv.key[2] = ste_key.as_u64[2];
405 kv.key[3] = ste_key.as_u64[3];
406 kv.key[4] = ste_key.as_u64[4];
407 kv.key[5] = ste_key.as_u64[5];
408 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 1);
414 nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste)
416 nat64_db_st_entry_t *st;
417 nat64_db_bib_entry_t *bib, *bibe;
418 nat64_db_st_entry_key_t ste_key;
419 clib_bihash_kv_48_8_t kv;
421 switch (ip_proto_to_snat_proto (ste->proto))
424 #define _(N, i, n, s) \
425 case SNAT_PROTOCOL_##N: \
426 st = db->st._##n##_st; \
427 bib = db->bib._##n##_bib; \
429 foreach_snat_protocol
433 st = db->st._unk_proto_st;
434 bib = db->bib._unk_proto_bib;
438 bibe = pool_elt_at_index (bib, ste->bibe_index);
440 /* delete hash lookup */
441 memset (&ste_key, 0, sizeof (ste_key));
442 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
443 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
444 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
445 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
446 ste_key.fib_index = bibe->fib_index;
447 ste_key.l_port = bibe->in_port;
448 ste_key.r_port = ste->r_port;
449 ste_key.proto = ste->proto;
450 kv.key[0] = ste_key.as_u64[0];
451 kv.key[1] = ste_key.as_u64[1];
452 kv.key[2] = ste_key.as_u64[2];
453 kv.key[3] = ste_key.as_u64[3];
454 kv.key[4] = ste_key.as_u64[4];
455 kv.key[5] = ste_key.as_u64[5];
456 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 0);
458 memset (&ste_key, 0, sizeof (ste_key));
459 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
460 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
461 ste_key.l_port = bibe->out_port;
462 ste_key.r_port = ste->r_port;
463 ste_key.proto = ste->proto;
464 kv.key[0] = ste_key.as_u64[0];
465 kv.key[1] = ste_key.as_u64[1];
466 kv.key[2] = ste_key.as_u64[2];
467 kv.key[3] = ste_key.as_u64[3];
468 kv.key[4] = ste_key.as_u64[4];
469 kv.key[5] = ste_key.as_u64[5];
470 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 0);
472 /* delete from pool */
475 /* decrement session number for BIB entry */
478 /* delete BIB entry if last session and dynamic */
479 if (!bibe->is_static && !bibe->ses_num)
480 nat64_db_bib_entry_free (db, bibe);
483 nat64_db_st_entry_t *
484 nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr,
485 ip46_address_t * r_addr, u16 l_port, u16 r_port,
486 u8 proto, u32 fib_index, u8 is_ip6)
488 nat64_db_st_entry_t *ste = 0;
489 nat64_db_st_entry_t *st;
490 nat64_db_st_entry_key_t ste_key;
491 clib_bihash_kv_48_8_t kv, value;
493 switch (ip_proto_to_snat_proto (proto))
496 #define _(N, i, n, s) \
497 case SNAT_PROTOCOL_##N: \
498 st = db->st._##n##_st; \
500 foreach_snat_protocol
504 st = db->st._unk_proto_st;
508 memset (&ste_key, 0, sizeof (ste_key));
509 ste_key.l_addr.as_u64[0] = l_addr->as_u64[0];
510 ste_key.l_addr.as_u64[1] = l_addr->as_u64[1];
511 ste_key.r_addr.as_u64[0] = r_addr->as_u64[0];
512 ste_key.r_addr.as_u64[1] = r_addr->as_u64[1];
513 ste_key.fib_index = fib_index;
514 ste_key.l_port = l_port;
515 ste_key.r_port = r_port;
516 ste_key.proto = proto;
517 kv.key[0] = ste_key.as_u64[0];
518 kv.key[1] = ste_key.as_u64[1];
519 kv.key[2] = ste_key.as_u64[2];
520 kv.key[3] = ste_key.as_u64[3];
521 kv.key[4] = ste_key.as_u64[4];
522 kv.key[5] = ste_key.as_u64[5];
524 if (!clib_bihash_search_48_8
525 (is_ip6 ? &db->st.in2out : &db->st.out2in, &kv, &value))
526 ste = pool_elt_at_index (st, value.value);
532 nat64_db_st_entry_get_index (nat64_db_t * db, nat64_db_st_entry_t * ste)
534 nat64_db_st_entry_t *st;
536 switch (ip_proto_to_snat_proto (ste->proto))
539 #define _(N, i, n, s) \
540 case SNAT_PROTOCOL_##N: \
541 st = db->st._##n##_st; \
543 foreach_snat_protocol
547 st = db->st._unk_proto_st;
554 nat64_db_st_entry_t *
555 nat64_db_st_entry_by_index (nat64_db_t * db, u8 proto, u32 ste_index)
557 nat64_db_st_entry_t *st;
559 switch (ip_proto_to_snat_proto (proto))
562 #define _(N, i, n, s) \
563 case SNAT_PROTOCOL_##N: \
564 st = db->st._##n##_st; \
566 foreach_snat_protocol
570 st = db->st._unk_proto_st;
574 return pool_elt_at_index (st, ste_index);
578 nad64_db_st_free_expired (nat64_db_t * db, u32 now)
580 u32 *ste_to_be_free = 0, *ste_index;
581 nat64_db_st_entry_t *st, *ste;
584 #define _(N, i, n, s) \
585 st = db->st._##n##_st; \
586 pool_foreach (ste, st, ({\
587 if (i == SNAT_PROTOCOL_TCP && !ste->tcp_state) \
589 if (ste->expire < now) \
590 vec_add1 (ste_to_be_free, ste - st); \
592 vec_foreach (ste_index, ste_to_be_free) \
593 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
594 vec_free (ste_to_be_free); \
596 foreach_snat_protocol
598 st = db->st._unk_proto_st;
599 pool_foreach (ste, st, ({
600 if (ste->expire < now)
601 vec_add1 (ste_to_be_free, ste - st);
603 vec_foreach (ste_index, ste_to_be_free)
604 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
605 vec_free (ste_to_be_free);
610 nat64_db_free_out_addr (nat64_db_t * db, ip4_address_t * out_addr)
612 u32 *ste_to_be_free = 0, *ste_index;
613 nat64_db_st_entry_t *st, *ste;
614 nat64_db_bib_entry_t *bibe;
617 #define _(N, i, n, s) \
618 st = db->st._##n##_st; \
619 pool_foreach (ste, st, ({ \
620 bibe = pool_elt_at_index (db->bib._##n##_bib, ste->bibe_index); \
621 if (bibe->out_addr.as_u32 == out_addr->as_u32) \
622 vec_add1 (ste_to_be_free, ste - st); \
624 vec_foreach (ste_index, ste_to_be_free) \
625 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
626 vec_free (ste_to_be_free); \
628 foreach_snat_protocol
630 st = db->st._unk_proto_st;
631 pool_foreach (ste, st, ({
632 bibe = pool_elt_at_index (db->bib._unk_proto_bib, ste->bibe_index);
633 if (bibe->out_addr.as_u32 == out_addr->as_u32)
634 vec_add1 (ste_to_be_free, ste - st);
636 vec_foreach (ste_index, ste_to_be_free)
637 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
638 vec_free (ste_to_be_free);
643 * fd.io coding-style-patch-verification: ON
646 * eval: (c-set-style "gnu")