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)
25 clib_bihash_init_24_8 (&db->bib.in2out, "bib-in2out", bib_buckets,
28 clib_bihash_init_24_8 (&db->bib.out2in, "bib-out2in", bib_buckets,
31 clib_bihash_init_48_8 (&db->st.in2out, "st-in2out", st_buckets,
34 clib_bihash_init_48_8 (&db->st.out2in, "st-out2in", st_buckets,
40 nat64_db_bib_entry_t *
41 nat64_db_bib_entry_create (nat64_db_t * db, ip6_address_t * in_addr,
42 ip4_address_t * out_addr, u16 in_port,
43 u16 out_port, u32 fib_index, u8 proto,
46 nat64_db_bib_entry_t *bibe;
47 nat64_db_bib_entry_key_t bibe_key;
48 clib_bihash_kv_24_8_t kv;
50 /* create pool entry */
51 switch (ip_proto_to_snat_proto (proto))
54 #define _(N, i, n, s) \
55 case SNAT_PROTOCOL_##N: \
56 pool_get (db->bib._##n##_bib, bibe); \
57 kv.value = bibe - db->bib._##n##_bib; \
63 pool_get (db->bib._unk_proto_bib, bibe);
64 kv.value = bibe - db->bib._unk_proto_bib;
67 memset (bibe, 0, sizeof (*bibe));
68 bibe->in_addr.as_u64[0] = in_addr->as_u64[0];
69 bibe->in_addr.as_u64[1] = in_addr->as_u64[1];
70 bibe->in_port = in_port;
71 bibe->out_addr.as_u32 = out_addr->as_u32;
72 bibe->out_port = out_port;
73 bibe->fib_index = fib_index;
75 bibe->is_static = is_static;
77 /* create hash lookup */
78 bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
79 bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
80 bibe_key.fib_index = bibe->fib_index;
81 bibe_key.port = bibe->in_port;
82 bibe_key.proto = bibe->proto;
84 kv.key[0] = bibe_key.as_u64[0];
85 kv.key[1] = bibe_key.as_u64[1];
86 kv.key[2] = bibe_key.as_u64[2];
87 clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 1);
89 memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
90 bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
91 bibe_key.fib_index = 0;
92 bibe_key.port = bibe->out_port;
93 kv.key[0] = bibe_key.as_u64[0];
94 kv.key[1] = bibe_key.as_u64[1];
95 kv.key[2] = bibe_key.as_u64[2];
96 clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 1);
102 nat64_db_bib_entry_free (nat64_db_t * db, nat64_db_bib_entry_t * bibe)
104 nat64_db_bib_entry_key_t bibe_key;
105 clib_bihash_kv_24_8_t kv;
106 nat64_db_bib_entry_t *bib;
107 u32 *ste_to_be_free = 0, *ste_index, bibe_index;
108 nat64_db_st_entry_t *st, *ste;
110 switch (ip_proto_to_snat_proto (bibe->proto))
113 #define _(N, i, n, s) \
114 case SNAT_PROTOCOL_##N: \
115 bib = db->bib._##n##_bib; \
116 st = db->st._##n##_st; \
118 foreach_snat_protocol
122 bib = db->bib._unk_proto_bib;
123 st = db->st._unk_proto_st;
127 bibe_index = bibe - bib;
129 /* delete ST entries for static BIB entry */
132 pool_foreach (ste, st, (
134 if (ste->bibe_index == bibe_index)
135 vec_add1 (ste_to_be_free, ste - st);}
137 vec_foreach (ste_index, ste_to_be_free)
138 nat64_db_st_entry_free (db, pool_elt_at_index (st, ste_index[0]));
139 vec_free (ste_to_be_free);
142 /* delete hash lookup */
143 bibe_key.addr.as_u64[0] = bibe->in_addr.as_u64[0];
144 bibe_key.addr.as_u64[1] = bibe->in_addr.as_u64[1];
145 bibe_key.fib_index = bibe->fib_index;
146 bibe_key.port = bibe->in_port;
147 bibe_key.proto = bibe->proto;
149 kv.key[0] = bibe_key.as_u64[0];
150 kv.key[1] = bibe_key.as_u64[1];
151 kv.key[2] = bibe_key.as_u64[2];
152 clib_bihash_add_del_24_8 (&db->bib.in2out, &kv, 0);
154 memset (&bibe_key.addr, 0, sizeof (bibe_key.addr));
155 bibe_key.addr.ip4.as_u32 = bibe->out_addr.as_u32;
156 bibe_key.fib_index = 0;
157 bibe_key.port = bibe->out_port;
158 kv.key[0] = bibe_key.as_u64[0];
159 kv.key[1] = bibe_key.as_u64[1];
160 kv.key[2] = bibe_key.as_u64[2];
161 clib_bihash_add_del_24_8 (&db->bib.out2in, &kv, 0);
163 /* delete from pool */
164 pool_put (bib, bibe);
168 nat64_db_bib_entry_t *
169 nat64_db_bib_entry_find (nat64_db_t * db, ip46_address_t * addr, u16 port,
170 u8 proto, u32 fib_index, u8 is_ip6)
172 nat64_db_bib_entry_t *bibe = 0;
173 nat64_db_bib_entry_key_t bibe_key;
174 clib_bihash_kv_24_8_t kv, value;
175 nat64_db_bib_entry_t *bib;
177 switch (ip_proto_to_snat_proto (proto))
180 #define _(N, i, n, s) \
181 case SNAT_PROTOCOL_##N: \
182 bib = db->bib._##n##_bib; \
184 foreach_snat_protocol
188 bib = db->bib._unk_proto_bib;
192 bibe_key.addr.as_u64[0] = addr->as_u64[0];
193 bibe_key.addr.as_u64[1] = addr->as_u64[1];
194 bibe_key.fib_index = fib_index;
195 bibe_key.port = port;
196 bibe_key.proto = proto;
199 kv.key[0] = bibe_key.as_u64[0];
200 kv.key[1] = bibe_key.as_u64[1];
201 kv.key[2] = bibe_key.as_u64[2];
203 if (!clib_bihash_search_24_8
204 (is_ip6 ? &db->bib.in2out : &db->bib.out2in, &kv, &value))
205 bibe = pool_elt_at_index (bib, value.value);
211 nat64_db_bib_walk (nat64_db_t * db, u8 proto,
212 nat64_db_bib_walk_fn_t fn, void *ctx)
214 nat64_db_bib_entry_t *bib, *bibe;
219 #define _(N, i, n, s) \
220 bib = db->bib._##n##_bib; \
221 pool_foreach (bibe, bib, ({ \
222 if (fn (bibe, ctx)) \
225 foreach_snat_protocol
227 bib = db->bib._unk_proto_bib;
228 pool_foreach (bibe, bib, ({
236 switch (ip_proto_to_snat_proto (proto))
239 #define _(N, i, n, s) \
240 case SNAT_PROTOCOL_##N: \
241 bib = db->bib._##n##_bib; \
243 foreach_snat_protocol
247 bib = db->bib._unk_proto_bib;
252 pool_foreach (bibe, bib,
261 nat64_db_bib_entry_t *
262 nat64_db_bib_entry_by_index (nat64_db_t * db, u8 proto, u32 bibe_index)
264 nat64_db_bib_entry_t *bib;
266 switch (ip_proto_to_snat_proto (proto))
269 #define _(N, i, n, s) \
270 case SNAT_PROTOCOL_##N: \
271 bib = db->bib._##n##_bib; \
273 foreach_snat_protocol
277 bib = db->bib._unk_proto_bib;
281 return pool_elt_at_index (bib, bibe_index);
285 nat64_db_st_walk (nat64_db_t * db, u8 proto,
286 nat64_db_st_walk_fn_t fn, void *ctx)
288 nat64_db_st_entry_t *st, *ste;
293 #define _(N, i, n, s) \
294 st = db->st._##n##_st; \
295 pool_foreach (ste, st, ({ \
299 foreach_snat_protocol
301 st = db->st._unk_proto_st;
302 pool_foreach (ste, st, ({
310 switch (ip_proto_to_snat_proto (proto))
313 #define _(N, i, n, s) \
314 case SNAT_PROTOCOL_##N: \
315 st = db->st._##n##_st; \
317 foreach_snat_protocol
321 st = db->st._unk_proto_st;
326 pool_foreach (ste, st,
335 nat64_db_st_entry_t *
336 nat64_db_st_entry_create (nat64_db_t * db, nat64_db_bib_entry_t * bibe,
337 ip6_address_t * in_r_addr,
338 ip4_address_t * out_r_addr, u16 r_port)
340 nat64_db_st_entry_t *ste;
341 nat64_db_bib_entry_t *bib;
342 nat64_db_st_entry_key_t ste_key;
343 clib_bihash_kv_48_8_t kv;
345 /* create pool entry */
346 switch (ip_proto_to_snat_proto (bibe->proto))
349 #define _(N, i, n, s) \
350 case SNAT_PROTOCOL_##N: \
351 pool_get (db->st._##n##_st, ste); \
352 kv.value = ste - db->st._##n##_st; \
353 bib = db->bib._##n##_bib; \
355 foreach_snat_protocol
359 pool_get (db->st._unk_proto_st, ste);
360 kv.value = ste - db->st._unk_proto_st;
361 bib = db->bib._unk_proto_bib;
364 memset (ste, 0, sizeof (*ste));
365 ste->in_r_addr.as_u64[0] = in_r_addr->as_u64[0];
366 ste->in_r_addr.as_u64[1] = in_r_addr->as_u64[1];
367 ste->out_r_addr.as_u32 = out_r_addr->as_u32;
368 ste->r_port = r_port;
369 ste->bibe_index = bibe - bib;
370 ste->proto = bibe->proto;
372 /* increment session number for BIB entry */
375 /* create hash lookup */
376 memset (&ste_key, 0, sizeof (ste_key));
377 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
378 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
379 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
380 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
381 ste_key.fib_index = bibe->fib_index;
382 ste_key.l_port = bibe->in_port;
383 ste_key.r_port = ste->r_port;
384 ste_key.proto = ste->proto;
385 kv.key[0] = ste_key.as_u64[0];
386 kv.key[1] = ste_key.as_u64[1];
387 kv.key[2] = ste_key.as_u64[2];
388 kv.key[3] = ste_key.as_u64[3];
389 kv.key[4] = ste_key.as_u64[4];
390 kv.key[5] = ste_key.as_u64[5];
391 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 1);
393 memset (&ste_key, 0, sizeof (ste_key));
394 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
395 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
396 ste_key.l_port = bibe->out_port;
397 ste_key.r_port = ste->r_port;
398 ste_key.proto = ste->proto;
399 kv.key[0] = ste_key.as_u64[0];
400 kv.key[1] = ste_key.as_u64[1];
401 kv.key[2] = ste_key.as_u64[2];
402 kv.key[3] = ste_key.as_u64[3];
403 kv.key[4] = ste_key.as_u64[4];
404 kv.key[5] = ste_key.as_u64[5];
405 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 1);
411 nat64_db_st_entry_free (nat64_db_t * db, nat64_db_st_entry_t * ste)
413 nat64_db_st_entry_t *st;
414 nat64_db_bib_entry_t *bib, *bibe;
415 nat64_db_st_entry_key_t ste_key;
416 clib_bihash_kv_48_8_t kv;
418 switch (ip_proto_to_snat_proto (ste->proto))
421 #define _(N, i, n, s) \
422 case SNAT_PROTOCOL_##N: \
423 st = db->st._##n##_st; \
424 bib = db->bib._##n##_bib; \
426 foreach_snat_protocol
430 st = db->st._unk_proto_st;
431 bib = db->bib._unk_proto_bib;
435 bibe = pool_elt_at_index (bib, ste->bibe_index);
437 /* delete hash lookup */
438 memset (&ste_key, 0, sizeof (ste_key));
439 ste_key.l_addr.as_u64[0] = bibe->in_addr.as_u64[0];
440 ste_key.l_addr.as_u64[1] = bibe->in_addr.as_u64[1];
441 ste_key.r_addr.as_u64[0] = ste->in_r_addr.as_u64[0];
442 ste_key.r_addr.as_u64[1] = ste->in_r_addr.as_u64[1];
443 ste_key.fib_index = bibe->fib_index;
444 ste_key.l_port = bibe->in_port;
445 ste_key.r_port = ste->r_port;
446 ste_key.proto = ste->proto;
447 kv.key[0] = ste_key.as_u64[0];
448 kv.key[1] = ste_key.as_u64[1];
449 kv.key[2] = ste_key.as_u64[2];
450 kv.key[3] = ste_key.as_u64[3];
451 kv.key[4] = ste_key.as_u64[4];
452 kv.key[5] = ste_key.as_u64[5];
453 clib_bihash_add_del_48_8 (&db->st.in2out, &kv, 0);
455 memset (&ste_key, 0, sizeof (ste_key));
456 ste_key.l_addr.ip4.as_u32 = bibe->out_addr.as_u32;
457 ste_key.r_addr.ip4.as_u32 = ste->out_r_addr.as_u32;
458 ste_key.l_port = bibe->out_port;
459 ste_key.r_port = ste->r_port;
460 ste_key.proto = ste->proto;
461 kv.key[0] = ste_key.as_u64[0];
462 kv.key[1] = ste_key.as_u64[1];
463 kv.key[2] = ste_key.as_u64[2];
464 kv.key[3] = ste_key.as_u64[3];
465 kv.key[4] = ste_key.as_u64[4];
466 kv.key[5] = ste_key.as_u64[5];
467 clib_bihash_add_del_48_8 (&db->st.out2in, &kv, 0);
469 /* delete from pool */
472 /* decrement session number for BIB entry */
475 /* delete BIB entry if last session and dynamic */
476 if (!bibe->is_static && !bibe->ses_num)
477 nat64_db_bib_entry_free (db, bibe);
480 nat64_db_st_entry_t *
481 nat64_db_st_entry_find (nat64_db_t * db, ip46_address_t * l_addr,
482 ip46_address_t * r_addr, u16 l_port, u16 r_port,
483 u8 proto, u32 fib_index, u8 is_ip6)
485 nat64_db_st_entry_t *ste = 0;
486 nat64_db_st_entry_t *st;
487 nat64_db_st_entry_key_t ste_key;
488 clib_bihash_kv_48_8_t kv, value;
490 switch (ip_proto_to_snat_proto (proto))
493 #define _(N, i, n, s) \
494 case SNAT_PROTOCOL_##N: \
495 st = db->st._##n##_st; \
497 foreach_snat_protocol
501 st = db->st._unk_proto_st;
505 memset (&ste_key, 0, sizeof (ste_key));
506 ste_key.l_addr.as_u64[0] = l_addr->as_u64[0];
507 ste_key.l_addr.as_u64[1] = l_addr->as_u64[1];
508 ste_key.r_addr.as_u64[0] = r_addr->as_u64[0];
509 ste_key.r_addr.as_u64[1] = r_addr->as_u64[1];
510 ste_key.fib_index = fib_index;
511 ste_key.l_port = l_port;
512 ste_key.r_port = r_port;
513 ste_key.proto = proto;
514 kv.key[0] = ste_key.as_u64[0];
515 kv.key[1] = ste_key.as_u64[1];
516 kv.key[2] = ste_key.as_u64[2];
517 kv.key[3] = ste_key.as_u64[3];
518 kv.key[4] = ste_key.as_u64[4];
519 kv.key[5] = ste_key.as_u64[5];
521 if (!clib_bihash_search_48_8
522 (is_ip6 ? &db->st.in2out : &db->st.out2in, &kv, &value))
523 ste = pool_elt_at_index (st, value.value);
529 nat64_db_st_entry_get_index (nat64_db_t * db, nat64_db_st_entry_t * ste)
531 nat64_db_st_entry_t *st;
533 switch (ip_proto_to_snat_proto (ste->proto))
536 #define _(N, i, n, s) \
537 case SNAT_PROTOCOL_##N: \
538 st = db->st._##n##_st; \
540 foreach_snat_protocol
544 st = db->st._unk_proto_st;
551 nat64_db_st_entry_t *
552 nat64_db_st_entry_by_index (nat64_db_t * db, u8 proto, u32 ste_index)
554 nat64_db_st_entry_t *st;
556 switch (ip_proto_to_snat_proto (proto))
559 #define _(N, i, n, s) \
560 case SNAT_PROTOCOL_##N: \
561 st = db->st._##n##_st; \
563 foreach_snat_protocol
567 st = db->st._unk_proto_st;
571 return pool_elt_at_index (st, ste_index);
575 nad64_db_st_free_expired (nat64_db_t * db, u32 now)
577 u32 *ste_to_be_free = 0, *ste_index;
578 nat64_db_st_entry_t *st, *ste;
581 #define _(N, i, n, s) \
582 st = db->st._##n##_st; \
583 pool_foreach (ste, st, ({\
584 if (i == SNAT_PROTOCOL_TCP && !ste->tcp_state) \
586 if (ste->expire < now) \
587 vec_add1 (ste_to_be_free, ste - st); \
589 vec_foreach (ste_index, ste_to_be_free) \
590 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
591 vec_free (ste_to_be_free); \
593 foreach_snat_protocol
595 st = db->st._unk_proto_st;
596 pool_foreach (ste, st, ({
597 if (ste->expire < now)
598 vec_add1 (ste_to_be_free, ste - st);
600 vec_foreach (ste_index, ste_to_be_free)
601 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
602 vec_free (ste_to_be_free);
607 nat64_db_free_out_addr (nat64_db_t * db, ip4_address_t * out_addr)
609 u32 *ste_to_be_free = 0, *ste_index;
610 nat64_db_st_entry_t *st, *ste;
611 nat64_db_bib_entry_t *bibe;
614 #define _(N, i, n, s) \
615 st = db->st._##n##_st; \
616 pool_foreach (ste, st, ({ \
617 bibe = pool_elt_at_index (db->bib._##n##_bib, ste->bibe_index); \
618 if (bibe->out_addr.as_u32 == out_addr->as_u32) \
619 vec_add1 (ste_to_be_free, ste - st); \
621 vec_foreach (ste_index, ste_to_be_free) \
622 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0])); \
623 vec_free (ste_to_be_free); \
625 foreach_snat_protocol
627 st = db->st._unk_proto_st;
628 pool_foreach (ste, st, ({
629 bibe = pool_elt_at_index (db->bib._unk_proto_bib, ste->bibe_index);
630 if (bibe->out_addr.as_u32 == out_addr->as_u32)
631 vec_add1 (ste_to_be_free, ste - st);
633 vec_foreach (ste_index, ste_to_be_free)
634 nat64_db_st_entry_free (db, pool_elt_at_index(st, ste_index[0]));
635 vec_free (ste_to_be_free);
640 * fd.io coding-style-patch-verification: ON
643 * eval: (c-set-style "gnu")