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>
20 #include <nat/nat_ipfix_logging.h>
21 #include <nat/nat_inlines.h>
22 #include <vnet/fib/fib_table.h>
25 nat64_db_init (nat64_db_t * db, u32 bib_buckets, u32 bib_memory_size,
26 u32 st_buckets, u32 st_memory_size,
27 nat64_db_free_addr_port_function_t free_addr_port_cb)
29 clib_bihash_init_24_8 (&db->bib.in2out, "bib-in2out", bib_buckets,
32 clib_bihash_init_24_8 (&db->bib.out2in, "bib-out2in", bib_buckets,
35 clib_bihash_init_48_8 (&db->st.in2out, "st-in2out", st_buckets,
38 clib_bihash_init_48_8 (&db->st.out2in, "st-out2in", st_buckets,
41 db->free_addr_port_cb = free_addr_port_cb;
42 db->bib.limit = 10 * bib_buckets;
43 db->bib.bib_entries_num = 0;
44 db->st.limit = 10 * st_buckets;
45 db->st.st_entries_num = 0;
51 nat64_db_bib_entry_t *
52 nat64_db_bib_entry_create (nat64_db_t * db, ip6_address_t * in_addr,
53 ip4_address_t * out_addr, u16 in_port,
54 u16 out_port, u32 fib_index, u8 proto,
57 nat64_db_bib_entry_t *bibe;
58 nat64_db_bib_entry_key_t bibe_key;
59 clib_bihash_kv_24_8_t kv;
62 if (db->bib.bib_entries_num >= db->bib.limit)
64 db->free_addr_port_cb (db, out_addr, out_port, proto);
65 nat_ipfix_logging_max_bibs (db->bib.limit);
69 /* create pool entry */
70 switch (ip_proto_to_snat_proto (proto))
73 #define _(N, i, n, s) \
74 case SNAT_PROTOCOL_##N: \
75 pool_get (db->bib._##n##_bib, bibe); \
76 kv.value = bibe - db->bib._##n##_bib; \
82 pool_get (db->bib._unk_proto_bib, bibe);
83 kv.value = bibe - db->bib._unk_proto_bib;
87 db->bib.bib_entries_num++;
89 memset (bibe, 0, sizeof (*bibe));
90 bibe->in_addr.as_u64[0] = in_addr->as_u64[0];
91 bibe->in_addr.as_u64[1] = in_addr->as_u64[1];
92 bibe->in_port = in_port;
93 bibe->out_addr.as_u32 = out_addr->as_u32;
94 bibe->out_port = out_port;
95 bibe->fib_index = fib_index;
97 bibe->is_static = is_static;
99 /* create hash lookup */
100 bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
101 bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
102 bibe_key.fib_index = bibe->fib_index;
103 bibe_key.port = bibe->in_port;
104 bibe_key.proto = bibe->proto;
106 kv.key[0] = bibe_key.as_u64[0];
107 kv.key[1] = bibe_key.as_u64[1];
108 kv.key[2] = bibe_key.as_u64[2];
109 clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 1);
111 memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
112 bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
113 bibe_key.fib_index = 0;
114 bibe_key.port = bibe->out_port;
115 kv.key[0] = bibe_key.as_u64[0];
116 kv.key[1] = bibe_key.as_u64[1];
117 kv.key[2] = bibe_key.as_u64[2];
118 clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 1);
120 fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
121 nat_ipfix_logging_nat64_bib (in_addr, out_addr, proto, in_port, out_port,
122 fib->ft_table_id, 1);
127 nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe)
129 nat64_db_bib_entry_key_t bibe_key;
130 clib_bihash_kv_24_8_t kv;
131 nat64_db_bib_entry_t *bib;
132 u32 *ste_to_be_free = 0, *ste_index, bibe_index;
133 nat64_db_st_entry_t *st, *ste;
136 switch (ip_proto_to_snat_proto (bibe->proto))
139 #define _(N, i, n, s) \
140 case SNAT_PROTOCOL_##N: \
141 bib = db->bib._##n##_bib; \
142 st = db->st._##n##_st; \
144 foreach_snat_protocol
148 bib = db->bib._unk_proto_bib;
149 st = db->st._unk_proto_st;
153 db->bib.bib_entries_num--;
155 bibe_index = bibe - bib;
157 /* delete ST entries for static BIB entry */
160 pool_foreach (ste, st, (
162 if (ste->bibe_index == bibe_index)
163 vec_add1 (ste_to_be_free, ste - st);}
165 vec_foreach (ste_index, ste_to_be_free)
166 nat64_db_st_entry_free (db, pool_elt_at_index (st, ste_index[0]));
167 vec_free (ste_to_be_free);
170 /* delete hash lookup */
171 bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
172 bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
173 bibe_key.fib_index = bibe->fib_index;
174 bibe_key.port = bibe->in_port;
175 bibe_key.proto = bibe->proto;
177 kv.key[0] = bibe_key.as_u64[0];
178 kv.key[1] = bibe_key.as_u64[1];
179 kv.key[2] = bibe_key.as_u64[2];
180 clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 0);
182 memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
183 bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
184 bibe_key.fib_index = 0;
185 bibe_key.port = bibe->out_port;
186 kv.key[0] = bibe_key.as_u64[0];
187 kv.key[1] = bibe_key.as_u64[1];
188 kv.key[2] = bibe_key.as_u64[2];
189 clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 0);
192 db->free_addr_port_cb (db, &bibe->out_addr, bibe->out_port, bibe->proto);
194 fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
195 nat_ipfix_logging_nat64_bib (&bibe->in_addr, &bibe->out_addr, bibe->proto,
196 bibe->in_port, bibe->out_port,
197 fib->ft_table_id, 0);
199 /* delete from pool */
200 pool_put (bib, bibe);
204 nat64_db_bib_entry_t *
205 nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port,
206 u8 proto, u32 fib_index, u8 is_ip6)
208 nat64_db_bib_entry_t *bibe = 0;
209 nat64_db_bib_entry_key_t bibe_key;
210 clib_bihash_kv_24_8_t kv, value;
211 nat64_db_bib_entry_t *bib;
213 switch (ip_proto_to_snat_proto (proto))
216 #define _(N, i, n, s) \
217 case SNAT_PROTOCOL_##N: \
218 bib = db->bib._##n##_bib; \
220 foreach_snat_protocol
224 bib = db->bib._unk_proto_bib;
228 bibe_key.addr.as_u64[0] = addr->as_u64[0];
229 bibe_key.addr.as_u64[1] = addr->as_u64[1];
230 bibe_key.fib_index = fib_index;
231 bibe_key.port = port;
232 bibe_key.proto = proto;
235 kv.key[0] = bibe_key.as_u64[0];
236 kv.key[1] = bibe_key.as_u64[1];
237 kv.key[2] = bibe_key.as_u64[2];
239 if (!clib_bihash_search_24_8
240 (is_ip6 ? &db->bib.in2out : &db->bib.out2in, &kv, &value))
241 bibe = pool_elt_at_index (bib, value.value);
247 nat64_db_bib_walk (nat64_db_t * db, u8 proto,
248 nat64_db_bib_walk_fn_t fn, void *ctx)
250 nat64_db_bib_entry_t *bib, *bibe;
255 #define _(N, i, n, s) \
256 bib = db->bib._##n##_bib; \
257 pool_foreach (bibe, bib, ({ \
258 if (fn (bibe, ctx)) \
261 foreach_snat_protocol
263 bib = db->bib._unk_proto_bib;
264 pool_foreach (bibe, bib, ({
272 switch (ip_proto_to_snat_proto (proto))
275 #define _(N, i, n, s) \
276 case SNAT_PROTOCOL_##N: \
277 bib = db->bib._##n##_bib; \
279 foreach_snat_protocol
283 bib = db->bib._unk_proto_bib;
288 pool_foreach (bibe, bib,
297 nat64_db_bib_entry_t *
298 nat64_db_bib_entry_by_index (nat64_db_t * db, u8 proto, u32 bibe_index)
300 nat64_db_bib_entry_t *bib;
302 switch (ip_proto_to_snat_proto (proto))
305 #define _(N, i, n, s) \
306 case SNAT_PROTOCOL_##N: \
307 bib = db->bib._##n##_bib; \
309 foreach_snat_protocol
313 bib = db->bib._unk_proto_bib;
317 return pool_elt_at_index (bib, bibe_index);
321 nat64_db_st_walk (nat64_db_t * db, u8 proto,
322 nat64_db_st_walk_fn_t fn, void *ctx)
324 nat64_db_st_entry_t *st, *ste;
329 #define _(N, i, n, s) \
330 st = db->st._##n##_st; \
331 pool_foreach (ste, st, ({ \
335 foreach_snat_protocol
337 st = db->st._unk_proto_st;
338 pool_foreach (ste, st, ({
346 switch (ip_proto_to_snat_proto (proto))
349 #define _(N, i, n, s) \
350 case SNAT_PROTOCOL_##N: \
351 st = db->st._##n##_st; \
353 foreach_snat_protocol
357 st = db->st._unk_proto_st;
362 pool_foreach (ste, st,
371 nat64_db_st_entry_t *
372 nat64_db_st_entry_create (nat64_db_t * db, nat64_db_bib_entry_t * bibe,
373 ip6_address_t * in_r_addr,
374 ip4_address_t * out_r_addr, u16 r_port)
376 nat64_db_st_entry_t *ste;
377 nat64_db_bib_entry_t *bib;
378 nat64_db_st_entry_key_t ste_key;
379 clib_bihash_kv_48_8_t kv;
382 if (db->st.st_entries_num >= db->st.limit)
384 nat_ipfix_logging_max_sessions (db->st.limit);
388 /* create pool entry */
389 switch (ip_proto_to_snat_proto (bibe->proto))
392 #define _(N, i, n, s) \
393 case SNAT_PROTOCOL_##N: \
394 pool_get (db->st._##n##_st, ste); \
395 kv.value = ste - db->st._##n##_st; \
396 bib = db->bib._##n##_bib; \
398 foreach_snat_protocol
402 pool_get (db->st._unk_proto_st, ste);
403 kv.value = ste - db->st._unk_proto_st;
404 bib = db->bib._unk_proto_bib;
408 db->st.st_entries_num++;
410 memset (ste, 0, sizeof (*ste));
411 ste->in_r_addr.as_u64[0] = in_r_addr->as_u64[0];
412 ste->in_r_addr.as_u64[1] = in_r_addr->as_u64[1];
413 ste->out_r_addr.as_u32 = out_r_addr->as_u32;
414 ste->r_port = r_port;
415 ste->bibe_index = bibe - bib;
416 ste->proto = bibe->proto;
418 /* increment session number for BIB entry */
421 /* create hash lookup */
422 memset (&ste_key, 0, sizeof (ste_key));
423 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
424 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
425 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
426 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
427 ste_key.fib_index = bibe->fib_index;
428 ste_key.l_port = bibe->in_port;
429 ste_key.r_port = ste->r_port;
430 ste_key.proto = ste->proto;
431 kv.key[0] = ste_key.as_u64[0];
432 kv.key[1] = ste_key.as_u64[1];
433 kv.key[2] = ste_key.as_u64[2];
434 kv.key[3] = ste_key.as_u64[3];
435 kv.key[4] = ste_key.as_u64[4];
436 kv.key[5] = ste_key.as_u64[5];
437 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 1);
439 memset (&ste_key, 0, sizeof (ste_key));
440 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
441 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
442 ste_key.l_port = bibe->out_port;
443 ste_key.r_port = ste->r_port;
444 ste_key.proto = ste->proto;
445 kv.key[0] = ste_key.as_u64[0];
446 kv.key[1] = ste_key.as_u64[1];
447 kv.key[2] = ste_key.as_u64[2];
448 kv.key[3] = ste_key.as_u64[3];
449 kv.key[4] = ste_key.as_u64[4];
450 kv.key[5] = ste_key.as_u64[5];
451 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 1);
453 fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
454 nat_ipfix_logging_nat64_session (&bibe->in_addr, &bibe->out_addr,
455 bibe->proto, bibe->in_port, bibe->out_port,
456 &ste->in_r_addr, &ste->out_r_addr,
457 ste->r_port, ste->r_port, fib->ft_table_id,
464 nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste)
466 nat64_db_st_entry_t *st;
467 nat64_db_bib_entry_t *bib, *bibe;
468 nat64_db_st_entry_key_t ste_key;
469 clib_bihash_kv_48_8_t kv;
472 switch (ip_proto_to_snat_proto (ste->proto))
475 #define _(N, i, n, s) \
476 case SNAT_PROTOCOL_##N: \
477 st = db->st._##n##_st; \
478 bib = db->bib._##n##_bib; \
480 foreach_snat_protocol
484 st = db->st._unk_proto_st;
485 bib = db->bib._unk_proto_bib;
489 bibe = pool_elt_at_index (bib, ste->bibe_index);
491 db->st.st_entries_num--;
493 /* delete hash lookup */
494 memset (&ste_key, 0, sizeof (ste_key));
495 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
496 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
497 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
498 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
499 ste_key.fib_index = bibe->fib_index;
500 ste_key.l_port = bibe->in_port;
501 ste_key.r_port = ste->r_port;
502 ste_key.proto = ste->proto;
503 kv.key[0] = ste_key.as_u64[0];
504 kv.key[1] = ste_key.as_u64[1];
505 kv.key[2] = ste_key.as_u64[2];
506 kv.key[3] = ste_key.as_u64[3];
507 kv.key[4] = ste_key.as_u64[4];
508 kv.key[5] = ste_key.as_u64[5];
509 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 0);
511 memset (&ste_key, 0, sizeof (ste_key));
512 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
513 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
514 ste_key.l_port = bibe->out_port;
515 ste_key.r_port = ste->r_port;
516 ste_key.proto = ste->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];
523 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 0);
525 fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
526 nat_ipfix_logging_nat64_session (&bibe->in_addr, &bibe->out_addr,
527 bibe->proto, bibe->in_port, bibe->out_port,
528 &ste->in_r_addr, &ste->out_r_addr,
529 ste->r_port, ste->r_port, fib->ft_table_id,
532 /* delete from pool */
535 /* decrement session number for BIB entry */
538 /* delete BIB entry if last session and dynamic */
539 if (!bibe->is_static && !bibe->ses_num)
540 nat64_db_bib_entry_free (db, bibe);
543 nat64_db_st_entry_t *
544 nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr,
545 ip46_address_t * r_addr, u16 l_port, u16 r_port,
546 u8 proto, u32 fib_index, u8 is_ip6)
548 nat64_db_st_entry_t *ste = 0;
549 nat64_db_st_entry_t *st;
550 nat64_db_st_entry_key_t ste_key;
551 clib_bihash_kv_48_8_t kv, value;
553 switch (ip_proto_to_snat_proto (proto))
556 #define _(N, i, n, s) \
557 case SNAT_PROTOCOL_##N: \
558 st = db->st._##n##_st; \
560 foreach_snat_protocol
564 st = db->st._unk_proto_st;
568 memset (&ste_key, 0, sizeof (ste_key));
569 ste_key.l_addr.as_u64[0] = l_addr->as_u64[0];
570 ste_key.l_addr.as_u64[1] = l_addr->as_u64[1];
571 ste_key.r_addr.as_u64[0] = r_addr->as_u64[0];
572 ste_key.r_addr.as_u64[1] = r_addr->as_u64[1];
573 ste_key.fib_index = fib_index;
574 ste_key.l_port = l_port;
575 ste_key.r_port = r_port;
576 ste_key.proto = proto;
577 kv.key[0] = ste_key.as_u64[0];
578 kv.key[1] = ste_key.as_u64[1];
579 kv.key[2] = ste_key.as_u64[2];
580 kv.key[3] = ste_key.as_u64[3];
581 kv.key[4] = ste_key.as_u64[4];
582 kv.key[5] = ste_key.as_u64[5];
584 if (!clib_bihash_search_48_8
585 (is_ip6 ? &db->st.in2out : &db->st.out2in, &kv, &value))
586 ste = pool_elt_at_index (st, value.value);
592 nat64_db_st_entry_get_index (nat64_db_t * db, nat64_db_st_entry_t * ste)
594 nat64_db_st_entry_t *st;
596 switch (ip_proto_to_snat_proto (ste->proto))
599 #define _(N, i, n, s) \
600 case SNAT_PROTOCOL_##N: \
601 st = db->st._##n##_st; \
603 foreach_snat_protocol
607 st = db->st._unk_proto_st;
614 nat64_db_st_entry_t *
615 nat64_db_st_entry_by_index (nat64_db_t * db, u8 proto, u32 ste_index)
617 nat64_db_st_entry_t *st;
619 switch (ip_proto_to_snat_proto (proto))
622 #define _(N, i, n, s) \
623 case SNAT_PROTOCOL_##N: \
624 st = db->st._##n##_st; \
626 foreach_snat_protocol
630 st = db->st._unk_proto_st;
634 return pool_elt_at_index (st, ste_index);
638 nad64_db_st_free_expired (nat64_db_t * db, u32 now)
640 u32 *ste_to_be_free = 0, *ste_index;
641 nat64_db_st_entry_t *st, *ste;
644 #define _(N, i, n, s) \
645 st = db->st._##n##_st; \
646 pool_foreach (ste, st, ({\
647 if (i == SNAT_PROTOCOL_TCP && !ste->tcp_state) \
649 if (ste->expire < now) \
650 vec_add1 (ste_to_be_free, ste - st); \
652 vec_foreach (ste_index, ste_to_be_free) \
653 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
654 vec_free (ste_to_be_free); \
656 foreach_snat_protocol
658 st = db->st._unk_proto_st;
659 pool_foreach (ste, st, ({
660 if (ste->expire < now)
661 vec_add1 (ste_to_be_free, ste - st);
663 vec_foreach (ste_index, ste_to_be_free)
664 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
665 vec_free (ste_to_be_free);
670 nat64_db_free_out_addr (nat64_db_t * db, ip4_address_t * out_addr)
672 u32 *ste_to_be_free = 0, *ste_index;
673 nat64_db_st_entry_t *st, *ste;
674 nat64_db_bib_entry_t *bibe;
678 #define _(N, i, n, s) \
679 st = db->st._##n##_st; \
680 pool_foreach (ste, st, ({ \
681 bibe = pool_elt_at_index (db->bib._##n##_bib, ste->bibe_index); \
682 if (bibe->out_addr.as_u32 == out_addr->as_u32) \
683 vec_add1 (ste_to_be_free, ste - st); \
685 vec_foreach (ste_index, ste_to_be_free) \
686 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
687 vec_free (ste_to_be_free); \
689 foreach_snat_protocol
691 st = db->st._unk_proto_st;
692 pool_foreach (ste, st, ({
693 bibe = pool_elt_at_index (db->bib._unk_proto_bib, ste->bibe_index);
694 if (bibe->out_addr.as_u32 == out_addr->as_u32)
695 vec_add1 (ste_to_be_free, ste - st);
697 vec_foreach (ste_index, ste_to_be_free)
698 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
699 vec_free (ste_to_be_free);
705 * fd.io coding-style-patch-verification: ON
708 * eval: (c-set-style "gnu")