2 * snat.c - simple nat plugin
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/nat_ipfix_logging.h>
25 #include <nat/nat_det.h>
26 #include <nat/nat64.h>
27 #include <nat/nat66.h>
28 #include <nat/nat_inlines.h>
29 #include <nat/nat44/inlines.h>
30 #include <nat/nat_affinity.h>
31 #include <nat/nat_syslog.h>
32 #include <nat/nat_ha.h>
33 #include <vnet/fib/fib_table.h>
34 #include <vnet/fib/ip4_fib.h>
35 #include <vnet/ip/reass/ip4_sv_reass.h>
36 #include <vppinfra/bihash_16_8.h>
38 #include <vpp/app/version.h>
40 snat_main_t snat_main;
42 fib_source_t nat_fib_src_hi;
43 fib_source_t nat_fib_src_low;
46 /* Hook up input features */
47 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
48 .arc_name = "ip4-unicast",
49 .node_name = "nat-pre-in2out",
50 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
51 "ip4-sv-reassembly-feature"),
53 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
54 .arc_name = "ip4-unicast",
55 .node_name = "nat-pre-out2in",
56 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
57 "ip4-dhcp-client-detect",
58 "ip4-sv-reassembly-feature"),
60 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
61 .arc_name = "ip4-unicast",
62 .node_name = "nat44-in2out-worker-handoff",
63 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
65 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
66 .arc_name = "ip4-unicast",
67 .node_name = "nat44-out2in-worker-handoff",
68 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
69 "ip4-dhcp-client-detect"),
71 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
72 .arc_name = "ip4-unicast",
73 .node_name = "nat44-in2out",
74 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
76 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
77 .arc_name = "ip4-unicast",
78 .node_name = "nat44-out2in",
79 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
80 "ip4-dhcp-client-detect"),
82 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
83 .arc_name = "ip4-unicast",
84 .node_name = "nat44-classify",
85 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
87 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
88 .arc_name = "ip4-unicast",
89 .node_name = "nat44-det-in2out",
90 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
92 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
93 .arc_name = "ip4-unicast",
94 .node_name = "nat44-det-out2in",
95 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
96 "ip4-dhcp-client-detect"),
98 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
99 .arc_name = "ip4-unicast",
100 .node_name = "nat44-det-classify",
101 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
103 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
104 .arc_name = "ip4-unicast",
105 .node_name = "nat44-ed-in2out",
106 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
108 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
109 .arc_name = "ip4-unicast",
110 .node_name = "nat44-ed-out2in",
111 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
112 "ip4-dhcp-client-detect"),
114 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
115 .arc_name = "ip4-unicast",
116 .node_name = "nat44-ed-classify",
117 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
119 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
120 .arc_name = "ip4-unicast",
121 .node_name = "nat44-handoff-classify",
122 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
124 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
125 .arc_name = "ip4-unicast",
126 .node_name = "nat44-in2out-fast",
127 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
129 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
130 .arc_name = "ip4-unicast",
131 .node_name = "nat44-out2in-fast",
132 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
133 "ip4-dhcp-client-detect"),
135 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
136 .arc_name = "ip4-unicast",
137 .node_name = "nat44-hairpin-dst",
138 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
140 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
141 .arc_name = "ip4-unicast",
142 .node_name = "nat44-ed-hairpin-dst",
143 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
146 /* Hook up output features */
147 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
148 .arc_name = "ip4-output",
149 .node_name = "nat44-in2out-output",
150 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
152 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
153 .arc_name = "ip4-output",
154 .node_name = "nat44-in2out-output-worker-handoff",
155 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
157 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
158 .arc_name = "ip4-output",
159 .node_name = "nat44-hairpin-src",
160 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
162 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
163 .arc_name = "ip4-output",
164 .node_name = "nat44-ed-in2out-output",
165 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
166 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
168 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
169 .arc_name = "ip4-output",
170 .node_name = "nat44-ed-hairpin-src",
171 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
172 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
175 /* Hook up ip4-local features */
176 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
178 .arc_name = "ip4-local",
179 .node_name = "nat44-hairpinning",
180 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
182 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
184 .arc_name = "ip4-local",
185 .node_name = "nat44-ed-hairpinning",
186 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
190 VLIB_PLUGIN_REGISTER () = {
191 .version = VPP_BUILD_VER,
192 .description = "Network Address Translation (NAT)",
197 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
200 snat_session_key_t key;
201 clib_bihash_kv_8_8_t kv;
204 ip4_address_t *l_addr, *r_addr;
206 clib_bihash_kv_16_8_t ed_kv;
207 snat_main_per_thread_data_t *tsm =
208 vec_elt_at_index (sm->per_thread_data, thread_index);
210 if (is_fwd_bypass_session (s))
212 if (snat_is_unk_proto_session (s))
214 make_ed_kv (&s->in2out.addr, &s->ext_host_addr, s->in2out.port, 0,
215 0, 0, ~0ULL, &ed_kv);
219 proto = snat_proto_to_ip_proto (s->in2out.protocol);
220 l_port = s->in2out.port;
221 r_port = s->ext_host_port;
222 l_addr = &s->in2out.addr;
223 r_addr = &s->ext_host_addr;
224 proto = snat_proto_to_ip_proto (s->in2out.protocol);
225 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
228 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
229 nat_elog_warn ("in2out_ed key del failed");
233 /* session lookup tables */
234 if (is_ed_session (s))
236 if (is_affinity_sessions (s))
237 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
238 s->in2out.protocol, s->out2in.port);
239 l_addr = &s->out2in.addr;
240 r_addr = &s->ext_host_addr;
241 fib_index = s->out2in.fib_index;
242 if (snat_is_unk_proto_session (s))
244 proto = s->in2out.port;
250 proto = snat_proto_to_ip_proto (s->in2out.protocol);
251 l_port = s->out2in.port;
252 r_port = s->ext_host_port;
254 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
256 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
257 nat_elog_warn ("out2in_ed key del failed");
258 l_addr = &s->in2out.addr;
259 fib_index = s->in2out.fib_index;
260 if (!snat_is_unk_proto_session (s))
261 l_port = s->in2out.port;
262 if (is_twice_nat_session (s))
264 r_addr = &s->ext_host_nat_addr;
265 r_port = s->ext_host_nat_port;
267 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
269 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
270 nat_elog_warn ("in2out_ed key del failed");
273 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
274 &s->in2out.addr, s->in2out.port,
275 &s->ext_host_nat_addr, s->ext_host_nat_port,
276 &s->out2in.addr, s->out2in.port,
277 &s->ext_host_addr, s->ext_host_port,
278 s->in2out.protocol, is_twice_nat_session (s));
282 kv.key = s->in2out.as_u64;
283 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
284 nat_elog_warn ("in2out key del failed");
285 kv.key = s->out2in.as_u64;
286 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
287 nat_elog_warn ("out2in key del failed");
290 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
291 &s->in2out.addr, s->in2out.port,
292 &s->out2in.addr, s->out2in.port,
296 if (snat_is_unk_proto_session (s))
302 snat_ipfix_logging_nat44_ses_delete (thread_index,
303 s->in2out.addr.as_u32,
304 s->out2in.addr.as_u32,
308 s->in2out.fib_index);
310 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
311 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
315 /* Twice NAT address and port for external host */
316 if (is_twice_nat_session (s))
318 key.protocol = s->in2out.protocol;
319 key.port = s->ext_host_nat_port;
320 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
321 snat_free_outside_address_and_port (sm->twice_nat_addresses,
325 if (snat_is_session_static (s))
328 snat_free_outside_address_and_port (sm->addresses, thread_index,
333 nat44_set_session_limit (u32 session_limit, u32 vrf_id)
335 snat_main_t *sm = &snat_main;
336 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
337 u32 len = vec_len (sm->max_translations_per_fib);
339 if (len <= fib_index)
341 vec_validate (sm->max_translations_per_fib, fib_index + 1);
343 for (; len < vec_len (sm->max_translations_per_fib); len++)
344 sm->max_translations_per_fib[len] = sm->max_translations;
347 sm->max_translations_per_fib[fib_index] = session_limit;
352 nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
353 u32 thread_index, u8 is_ha)
355 snat_session_key_t key;
358 ip4_address_t *l_addr, *r_addr;
360 clib_bihash_kv_16_8_t ed_kv;
361 snat_main_per_thread_data_t *tsm =
362 vec_elt_at_index (sm->per_thread_data, thread_index);
364 if (is_fwd_bypass_session (s))
366 if (snat_is_unk_proto_session (s))
368 proto = s->in2out.port;
374 proto = snat_proto_to_ip_proto (s->in2out.protocol);
375 l_port = s->in2out.port;
376 r_port = s->ext_host_port;
379 l_addr = &s->in2out.addr;
380 r_addr = &s->ext_host_addr;
382 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
386 (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
387 nat_elog_warn ("in2out_ed key del failed");
391 /* session lookup tables */
392 if (is_affinity_sessions (s))
393 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
394 s->in2out.protocol, s->out2in.port);
395 l_addr = &s->out2in.addr;
396 r_addr = &s->ext_host_addr;
397 fib_index = s->out2in.fib_index;
398 if (snat_is_unk_proto_session (s))
400 proto = s->in2out.port;
406 proto = snat_proto_to_ip_proto (s->in2out.protocol);
407 l_port = s->out2in.port;
408 r_port = s->ext_host_port;
410 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
413 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
414 nat_elog_warn ("out2in_ed key del failed");
416 l_addr = &s->in2out.addr;
417 fib_index = s->in2out.fib_index;
419 if (!snat_is_unk_proto_session (s))
420 l_port = s->in2out.port;
422 if (is_twice_nat_session (s))
424 r_addr = &s->ext_host_nat_addr;
425 r_port = s->ext_host_nat_port;
427 make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
430 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
431 nat_elog_warn ("in2out_ed key del failed");
435 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
436 &s->in2out.addr, s->in2out.port,
437 &s->ext_host_nat_addr, s->ext_host_nat_port,
438 &s->out2in.addr, s->out2in.port,
439 &s->ext_host_addr, s->ext_host_port,
440 s->in2out.protocol, is_twice_nat_session (s));
443 if (snat_is_unk_proto_session (s))
449 snat_ipfix_logging_nat44_ses_delete (thread_index,
450 s->in2out.addr.as_u32,
451 s->out2in.addr.as_u32,
455 s->in2out.fib_index);
456 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
457 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
461 /* Twice NAT address and port for external host */
462 if (is_twice_nat_session (s))
464 key.protocol = s->in2out.protocol;
465 key.port = s->ext_host_nat_port;
466 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
467 snat_free_outside_address_and_port (sm->twice_nat_addresses,
471 if (snat_is_session_static (s))
474 // should be called for every dynamic session
475 snat_free_outside_address_and_port (sm->addresses, thread_index,
481 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
485 snat_user_key_t user_key;
486 clib_bihash_kv_8_8_t kv, value;
487 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
488 dlist_elt_t *per_user_list_head_elt;
490 user_key.addr.as_u32 = addr->as_u32;
491 user_key.fib_index = fib_index;
492 kv.key = user_key.as_u64;
494 /* Ever heard of the "user" = src ip4 address before? */
495 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
497 /* no, make a new one */
498 pool_get (tsm->users, u);
499 clib_memset (u, 0, sizeof (*u));
501 u->addr.as_u32 = addr->as_u32;
502 u->fib_index = fib_index;
504 pool_get (tsm->list_pool, per_user_list_head_elt);
506 u->sessions_per_user_list_head_index = per_user_list_head_elt -
509 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
511 kv.value = u - tsm->users;
514 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
516 nat_elog_warn ("user_hash key add failed");
517 nat44_delete_user_with_no_session (sm, u, thread_index);
521 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
522 pool_elts (tsm->users));
526 u = pool_elt_at_index (tsm->users, value.value);
533 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
534 u32 thread_index, f64 now)
537 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
538 u32 oldest_per_user_translation_list_index, session_index;
539 dlist_elt_t *oldest_per_user_translation_list_elt;
540 dlist_elt_t *per_user_translation_list_elt;
542 /* Over quota? Recycle the least recently used translation */
543 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
545 oldest_per_user_translation_list_index =
546 clib_dlist_remove_head (tsm->list_pool,
547 u->sessions_per_user_list_head_index);
549 ASSERT (oldest_per_user_translation_list_index != ~0);
551 /* Add it back to the end of the LRU list */
552 clib_dlist_addtail (tsm->list_pool,
553 u->sessions_per_user_list_head_index,
554 oldest_per_user_translation_list_index);
555 /* Get the list element */
556 oldest_per_user_translation_list_elt =
557 pool_elt_at_index (tsm->list_pool,
558 oldest_per_user_translation_list_index);
560 /* Get the session index from the list element */
561 session_index = oldest_per_user_translation_list_elt->value;
563 /* Get the session */
564 s = pool_elt_at_index (tsm->sessions, session_index);
565 nat_free_session_data (sm, s, thread_index, 0);
566 if (snat_is_session_static (s))
567 u->nstaticsessions--;
574 s->ext_host_addr.as_u32 = 0;
575 s->ext_host_port = 0;
576 s->ext_host_nat_addr.as_u32 = 0;
577 s->ext_host_nat_port = 0;
581 pool_get (tsm->sessions, s);
582 clib_memset (s, 0, sizeof (*s));
584 /* Create list elts */
585 pool_get (tsm->list_pool, per_user_translation_list_elt);
586 clib_dlist_init (tsm->list_pool,
587 per_user_translation_list_elt - tsm->list_pool);
589 per_user_translation_list_elt->value = s - tsm->sessions;
590 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
591 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
593 clib_dlist_addtail (tsm->list_pool,
594 s->per_user_list_head_index,
595 per_user_translation_list_elt - tsm->list_pool);
597 dlist_elt_t *global_lru_list_elt;
598 pool_get (tsm->global_lru_pool, global_lru_list_elt);
599 global_lru_list_elt->value = s - tsm->sessions;
600 s->global_lru_index = global_lru_list_elt - tsm->global_lru_pool;
601 clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
602 s->global_lru_index);
603 s->last_lru_update = now;
605 s->user_index = u - tsm->users;
606 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
607 pool_elts (tsm->sessions));
610 s->ha_last_refreshed = now;
616 nat_global_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
618 snat_session_t *s = NULL;
619 dlist_elt_t *oldest_elt;
620 u64 sess_timeout_time;
622 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
623 oldest_index = clib_dlist_remove_head (tsm->global_lru_pool,
624 tsm->global_lru_head_index);
625 if (~0 != oldest_index)
627 oldest_elt = pool_elt_at_index (tsm->global_lru_pool, oldest_index);
628 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
631 s->last_heard + (f64) nat44_session_get_timeout (sm, s);
632 if (now >= sess_timeout_time
633 || (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
635 nat_free_session_data (sm, s, thread_index, 0);
636 nat44_ed_delete_session (sm, s, thread_index, 0);
641 clib_dlist_addhead (tsm->global_lru_pool,
642 tsm->global_lru_head_index, oldest_index);
649 nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now)
652 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
654 nat_global_lru_free_one (sm, thread_index, now);
656 pool_get (tsm->sessions, s);
657 clib_memset (s, 0, sizeof (*s));
659 nat44_global_lru_insert (tsm, s, now);
661 s->ha_last_refreshed = now;
662 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
663 pool_elts (tsm->sessions));
668 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
671 fib_prefix_t prefix = {
673 .fp_proto = FIB_PROTOCOL_IP4,
675 .ip4.as_u32 = addr->as_u32,
678 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
681 fib_table_entry_update_one_path (fib_index,
684 (FIB_ENTRY_FLAG_CONNECTED |
685 FIB_ENTRY_FLAG_LOCAL |
686 FIB_ENTRY_FLAG_EXCLUSIVE),
690 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
692 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
696 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
701 vlib_thread_main_t *tm = vlib_get_thread_main ();
703 if (twice_nat && !sm->endpoint_dependent)
704 return VNET_API_ERROR_FEATURE_DISABLED;
706 /* Check if address already exists */
708 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
710 if (ap->addr.as_u32 == addr->as_u32)
711 return VNET_API_ERROR_VALUE_EXIST;
716 vec_add2 (sm->twice_nat_addresses, ap, 1);
718 vec_add2 (sm->addresses, ap, 1);
723 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
727 #define _(N, i, n, s) \
728 clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
729 ap->busy_##n##_ports = 0; \
730 ap->busy_##n##_ports_per_thread = 0;\
731 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
732 foreach_snat_protocol
737 /* Add external address to FIB */
739 pool_foreach (i, sm->interfaces,
741 if (nat_interface_is_inside(i) || sm->out2in_dpo)
744 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
747 pool_foreach (i, sm->output_feature_interfaces,
749 if (nat_interface_is_inside(i) || sm->out2in_dpo)
752 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
761 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
763 snat_static_mapping_t *m;
765 pool_foreach (m, sm->static_mappings,
767 if (is_addr_only_static_mapping (m) ||
768 is_out2in_only_static_mapping (m) ||
769 is_identity_static_mapping (m))
771 if (m->external_addr.as_u32 == addr.as_u32)
780 snat_add_static_mapping_when_resolved (snat_main_t * sm,
781 ip4_address_t l_addr,
786 snat_protocol_t proto,
787 int addr_only, int is_add, u8 * tag,
788 int twice_nat, int out2in_only,
791 snat_static_map_resolve_t *rp;
793 vec_add2 (sm->to_resolve, rp, 1);
794 rp->l_addr.as_u32 = l_addr.as_u32;
796 rp->sw_if_index = sw_if_index;
800 rp->addr_only = addr_only;
802 rp->twice_nat = twice_nat;
803 rp->out2in_only = out2in_only;
804 rp->identity_nat = identity_nat;
805 rp->tag = vec_dup (tag);
809 get_thread_idx_by_port (u16 e_port)
811 snat_main_t *sm = &snat_main;
812 u32 thread_idx = sm->num_workers;
813 if (sm->num_workers > 1)
816 sm->first_worker_index +
817 sm->workers[(e_port - 1024) / sm->port_per_thread];
823 snat_static_mapping_del_sessions (snat_main_t * sm,
824 snat_main_per_thread_data_t * tsm,
825 snat_user_key_t u_key, int addr_only,
826 ip4_address_t e_addr, u16 e_port)
828 clib_bihash_kv_8_8_t kv, value;
829 kv.key = u_key.as_u64;
831 dlist_elt_t *head, *elt;
834 u32 elt_index, head_index, ses_index;
835 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
837 user_index = value.value;
838 u = pool_elt_at_index (tsm->users, user_index);
839 if (u->nstaticsessions)
841 head_index = u->sessions_per_user_list_head_index;
842 head = pool_elt_at_index (tsm->list_pool, head_index);
843 elt_index = head->next;
844 elt = pool_elt_at_index (tsm->list_pool, elt_index);
845 ses_index = elt->value;
846 while (ses_index != ~0)
848 s = pool_elt_at_index (tsm->sessions, ses_index);
849 elt = pool_elt_at_index (tsm->list_pool, elt->next);
850 ses_index = elt->value;
854 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
855 (clib_net_to_host_u16 (s->out2in.port) != e_port))
859 if (is_lb_session (s))
862 if (!snat_is_session_static (s))
865 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
866 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
876 snat_ed_static_mapping_del_sessions (snat_main_t * sm,
877 snat_main_per_thread_data_t * tsm,
878 ip4_address_t l_addr,
881 u32 fib_index, int addr_only,
882 ip4_address_t e_addr, u16 e_port)
885 u32 *indexes_to_free = NULL;
887 pool_foreach (s, tsm->sessions, {
888 if (s->in2out.fib_index != fib_index ||
889 s->in2out.addr.as_u32 != l_addr.as_u32)
895 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
896 (clib_net_to_host_u16 (s->out2in.port) != e_port) ||
897 clib_net_to_host_u16 (s->in2out.port) != l_port ||
898 s->in2out.protocol != protocol)
902 if (is_lb_session (s))
904 if (!snat_is_session_static (s))
906 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
907 vec_add1 (indexes_to_free, s - tsm->sessions);
913 vec_foreach (ses_index, indexes_to_free)
915 s = pool_elt_at_index (tsm->sessions, *ses_index);
916 nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
918 vec_free (indexes_to_free);
922 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
923 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
924 u32 sw_if_index, snat_protocol_t proto, int is_add,
925 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
928 snat_main_t *sm = &snat_main;
929 snat_static_mapping_t *m;
930 snat_session_key_t m_key;
931 clib_bihash_kv_8_8_t kv, value;
932 snat_address_t *a = 0;
934 snat_interface_t *interface;
936 snat_main_per_thread_data_t *tsm;
937 snat_user_key_t u_key;
939 dlist_elt_t *head, *elt;
940 u32 elt_index, head_index;
944 snat_static_map_resolve_t *rp, *rp_match = 0;
945 nat44_lb_addr_port_t *local;
948 if (!sm->endpoint_dependent)
950 if (twice_nat || out2in_only)
951 return VNET_API_ERROR_FEATURE_DISABLED;
954 /* If the external address is a specific interface address */
955 if (sw_if_index != ~0)
957 ip4_address_t *first_int_addr;
959 for (i = 0; i < vec_len (sm->to_resolve); i++)
961 rp = sm->to_resolve + i;
962 if (rp->sw_if_index != sw_if_index ||
963 rp->l_addr.as_u32 != l_addr.as_u32 ||
964 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
969 if ((rp->l_port != l_port && rp->e_port != e_port)
970 || rp->proto != proto)
978 /* Might be already set... */
979 first_int_addr = ip4_interface_first_address
980 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
985 return VNET_API_ERROR_VALUE_EXIST;
987 snat_add_static_mapping_when_resolved
988 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
989 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
991 /* DHCP resolution required? */
992 if (first_int_addr == 0)
998 e_addr.as_u32 = first_int_addr->as_u32;
999 /* Identity mapping? */
1000 if (l_addr.as_u32 == 0)
1001 l_addr.as_u32 = e_addr.as_u32;
1007 return VNET_API_ERROR_NO_SUCH_ENTRY;
1009 vec_del1 (sm->to_resolve, i);
1013 e_addr.as_u32 = first_int_addr->as_u32;
1014 /* Identity mapping? */
1015 if (l_addr.as_u32 == 0)
1016 l_addr.as_u32 = e_addr.as_u32;
1023 m_key.addr = e_addr;
1024 m_key.port = addr_only ? 0 : e_port;
1025 m_key.protocol = addr_only ? 0 : proto;
1026 m_key.fib_index = 0;
1027 kv.key = m_key.as_u64;
1028 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1031 m = pool_elt_at_index (sm->static_mappings, value.value);
1037 if (is_identity_static_mapping (m))
1040 pool_foreach (local, m->locals,
1042 if (local->vrf_id == vrf_id)
1043 return VNET_API_ERROR_VALUE_EXIST;
1046 pool_get (m->locals, local);
1047 local->vrf_id = vrf_id;
1049 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1051 m_key.addr = m->local_addr;
1052 m_key.port = m->local_port;
1053 m_key.protocol = m->proto;
1054 m_key.fib_index = local->fib_index;
1055 kv.key = m_key.as_u64;
1056 kv.value = m - sm->static_mappings;
1057 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1061 return VNET_API_ERROR_VALUE_EXIST;
1064 if (twice_nat && addr_only)
1065 return VNET_API_ERROR_UNSUPPORTED;
1067 /* Convert VRF id to FIB index */
1070 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1072 /* If not specified use inside VRF id from SNAT plugin startup config */
1075 fib_index = sm->inside_fib_index;
1076 vrf_id = sm->inside_vrf_id;
1077 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1080 if (!(out2in_only || identity_nat))
1082 m_key.addr = l_addr;
1083 m_key.port = addr_only ? 0 : l_port;
1084 m_key.protocol = addr_only ? 0 : proto;
1085 m_key.fib_index = fib_index;
1086 kv.key = m_key.as_u64;
1087 if (!clib_bihash_search_8_8
1088 (&sm->static_mapping_by_local, &kv, &value))
1089 return VNET_API_ERROR_VALUE_EXIST;
1092 /* Find external address in allocated addresses and reserve port for
1093 address and port pair mapping when dynamic translations enabled */
1094 if (!(addr_only || sm->static_mapping_only || out2in_only))
1096 for (i = 0; i < vec_len (sm->addresses); i++)
1098 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1100 a = sm->addresses + i;
1101 /* External port must be unused */
1104 #define _(N, j, n, s) \
1105 case SNAT_PROTOCOL_##N: \
1106 if (a->busy_##n##_port_refcounts[e_port]) \
1107 return VNET_API_ERROR_INVALID_VALUE; \
1108 ++a->busy_##n##_port_refcounts[e_port]; \
1109 if (e_port > 1024) \
1111 a->busy_##n##_ports++; \
1112 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1115 foreach_snat_protocol
1118 nat_elog_info ("unknown protocol");
1119 return VNET_API_ERROR_INVALID_VALUE_2;
1124 /* External address must be allocated */
1125 if (!a && (l_addr.as_u32 != e_addr.as_u32))
1127 if (sw_if_index != ~0)
1129 for (i = 0; i < vec_len (sm->to_resolve); i++)
1131 rp = sm->to_resolve + i;
1134 if (rp->sw_if_index != sw_if_index &&
1135 rp->l_addr.as_u32 != l_addr.as_u32 &&
1136 rp->vrf_id != vrf_id && rp->l_port != l_port &&
1137 rp->e_port != e_port && rp->proto != proto)
1140 vec_del1 (sm->to_resolve, i);
1144 return VNET_API_ERROR_NO_SUCH_ENTRY;
1148 pool_get (sm->static_mappings, m);
1149 clib_memset (m, 0, sizeof (*m));
1150 m->tag = vec_dup (tag);
1151 m->local_addr = l_addr;
1152 m->external_addr = e_addr;
1153 m->twice_nat = twice_nat;
1155 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1157 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
1160 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
1161 pool_get (m->locals, local);
1162 local->vrf_id = vrf_id;
1163 local->fib_index = fib_index;
1168 m->fib_index = fib_index;
1172 m->local_port = l_port;
1173 m->external_port = e_port;
1177 if (sm->num_workers > 1)
1180 .src_address = m->local_addr,
1182 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
1183 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1186 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1188 m_key.addr = m->local_addr;
1189 m_key.port = m->local_port;
1190 m_key.protocol = m->proto;
1191 m_key.fib_index = fib_index;
1192 kv.key = m_key.as_u64;
1193 kv.value = m - sm->static_mappings;
1195 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1197 m_key.addr = m->external_addr;
1198 m_key.port = m->external_port;
1199 m_key.fib_index = 0;
1200 kv.key = m_key.as_u64;
1201 kv.value = m - sm->static_mappings;
1202 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
1204 /* Delete dynamic sessions matching local address (+ local port) */
1205 if (!(sm->static_mapping_only))
1207 u_key.addr = m->local_addr;
1208 u_key.fib_index = m->fib_index;
1209 kv.key = u_key.as_u64;
1210 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1212 user_index = value.value;
1213 u = pool_elt_at_index (tsm->users, user_index);
1216 head_index = u->sessions_per_user_list_head_index;
1217 head = pool_elt_at_index (tsm->list_pool, head_index);
1218 elt_index = head->next;
1219 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1220 ses_index = elt->value;
1221 while (ses_index != ~0)
1223 s = pool_elt_at_index (tsm->sessions, ses_index);
1224 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1225 ses_index = elt->value;
1227 if (snat_is_session_static (s))
1231 && (clib_net_to_host_u16 (s->in2out.port) !=
1235 nat_free_session_data (sm, s,
1236 tsm - sm->per_thread_data, 0);
1237 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1239 if (!addr_only && !sm->endpoint_dependent)
1250 if (sw_if_index != ~0)
1253 return VNET_API_ERROR_NO_SUCH_ENTRY;
1259 vrf_id = sm->inside_vrf_id;
1262 pool_foreach (local, m->locals,
1264 if (local->vrf_id == vrf_id)
1265 find = local - m->locals;
1269 return VNET_API_ERROR_NO_SUCH_ENTRY;
1271 local = pool_elt_at_index (m->locals, find);
1272 fib_index = local->fib_index;
1273 pool_put (m->locals, local);
1276 fib_index = m->fib_index;
1278 /* Free external address port */
1279 if (!(addr_only || sm->static_mapping_only || out2in_only))
1281 for (i = 0; i < vec_len (sm->addresses); i++)
1283 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1285 a = sm->addresses + i;
1288 #define _(N, j, n, s) \
1289 case SNAT_PROTOCOL_##N: \
1290 --a->busy_##n##_port_refcounts[e_port]; \
1291 if (e_port > 1024) \
1293 a->busy_##n##_ports--; \
1294 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1297 foreach_snat_protocol
1300 nat_elog_info ("unknown protocol");
1301 return VNET_API_ERROR_INVALID_VALUE_2;
1308 if (sm->num_workers > 1)
1309 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1311 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1313 m_key.addr = m->local_addr;
1314 m_key.port = m->local_port;
1315 m_key.protocol = m->proto;
1316 m_key.fib_index = fib_index;
1317 kv.key = m_key.as_u64;
1319 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1321 /* Delete session(s) for static mapping if exist */
1322 if (!(sm->static_mapping_only) ||
1323 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1325 if (sm->endpoint_dependent)
1327 snat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr,
1328 m->local_port, m->proto,
1329 fib_index, addr_only,
1334 u_key.addr = m->local_addr;
1335 u_key.fib_index = fib_index;
1336 kv.key = u_key.as_u64;
1337 snat_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
1342 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1343 if (pool_elts (m->locals))
1346 m_key.addr = m->external_addr;
1347 m_key.port = m->external_port;
1348 m_key.fib_index = 0;
1349 kv.key = m_key.as_u64;
1350 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1353 vec_free (m->workers);
1354 /* Delete static mapping from pool */
1355 pool_put (sm->static_mappings, m);
1358 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1361 /* Add/delete external address to FIB */
1363 pool_foreach (interface, sm->interfaces,
1365 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1368 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1371 pool_foreach (interface, sm->output_feature_interfaces,
1373 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1376 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1385 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1386 snat_protocol_t proto,
1387 nat44_lb_addr_port_t * locals, u8 is_add,
1388 twice_nat_type_t twice_nat, u8 out2in_only,
1389 u8 * tag, u32 affinity)
1391 snat_main_t *sm = &snat_main;
1392 snat_static_mapping_t *m;
1393 snat_session_key_t m_key;
1394 clib_bihash_kv_8_8_t kv, value;
1395 snat_address_t *a = 0;
1397 nat44_lb_addr_port_t *local;
1398 snat_main_per_thread_data_t *tsm;
1402 if (!sm->endpoint_dependent)
1403 return VNET_API_ERROR_FEATURE_DISABLED;
1405 m_key.addr = e_addr;
1406 m_key.port = e_port;
1407 m_key.protocol = proto;
1408 m_key.fib_index = 0;
1409 kv.key = m_key.as_u64;
1410 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1413 m = pool_elt_at_index (sm->static_mappings, value.value);
1418 return VNET_API_ERROR_VALUE_EXIST;
1420 if (vec_len (locals) < 2)
1421 return VNET_API_ERROR_INVALID_VALUE;
1423 /* Find external address in allocated addresses and reserve port for
1424 address and port pair mapping when dynamic translations enabled */
1425 if (!(sm->static_mapping_only || out2in_only))
1427 for (i = 0; i < vec_len (sm->addresses); i++)
1429 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1431 a = sm->addresses + i;
1432 /* External port must be unused */
1435 #define _(N, j, n, s) \
1436 case SNAT_PROTOCOL_##N: \
1437 if (a->busy_##n##_port_refcounts[e_port]) \
1438 return VNET_API_ERROR_INVALID_VALUE; \
1439 ++a->busy_##n##_port_refcounts[e_port]; \
1440 if (e_port > 1024) \
1442 a->busy_##n##_ports++; \
1443 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1446 foreach_snat_protocol
1449 nat_elog_info ("unknown protocol");
1450 return VNET_API_ERROR_INVALID_VALUE_2;
1455 /* External address must be allocated */
1457 return VNET_API_ERROR_NO_SUCH_ENTRY;
1460 pool_get (sm->static_mappings, m);
1461 clib_memset (m, 0, sizeof (*m));
1462 m->tag = vec_dup (tag);
1463 m->external_addr = e_addr;
1464 m->external_port = e_port;
1466 m->twice_nat = twice_nat;
1467 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1469 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1470 m->affinity = affinity;
1473 m->affinity_per_service_list_head_index =
1474 nat_affinity_get_per_service_list_head_index ();
1476 m->affinity_per_service_list_head_index = ~0;
1478 m_key.addr = m->external_addr;
1479 m_key.port = m->external_port;
1480 m_key.protocol = m->proto;
1481 m_key.fib_index = 0;
1482 kv.key = m_key.as_u64;
1483 kv.value = m - sm->static_mappings;
1484 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1486 nat_elog_err ("static_mapping_by_external key add failed");
1487 return VNET_API_ERROR_UNSPECIFIED;
1490 m_key.fib_index = m->fib_index;
1491 for (i = 0; i < vec_len (locals); i++)
1493 locals[i].fib_index =
1494 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1497 m_key.addr = locals[i].addr;
1498 m_key.fib_index = locals[i].fib_index;
1501 m_key.port = locals[i].port;
1502 kv.key = m_key.as_u64;
1503 kv.value = m - sm->static_mappings;
1504 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1506 locals[i].prefix = (i == 0) ? locals[i].probability :
1507 (locals[i - 1].prefix + locals[i].probability);
1508 pool_get (m->locals, local);
1510 if (sm->num_workers > 1)
1513 .src_address = locals[i].addr,
1516 clib_bitmap_set (bitmap,
1517 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1522 /* Assign workers */
1523 if (sm->num_workers > 1)
1526 clib_bitmap_foreach (i, bitmap,
1528 vec_add1(m->workers, i);
1536 return VNET_API_ERROR_NO_SUCH_ENTRY;
1538 if (!is_lb_static_mapping (m))
1539 return VNET_API_ERROR_INVALID_VALUE;
1541 /* Free external address port */
1542 if (!(sm->static_mapping_only || out2in_only))
1544 for (i = 0; i < vec_len (sm->addresses); i++)
1546 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1548 a = sm->addresses + i;
1551 #define _(N, j, n, s) \
1552 case SNAT_PROTOCOL_##N: \
1553 --a->busy_##n##_port_refcounts[e_port]; \
1554 if (e_port > 1024) \
1556 a->busy_##n##_ports--; \
1557 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1560 foreach_snat_protocol
1563 nat_elog_info ("unknown protocol");
1564 return VNET_API_ERROR_INVALID_VALUE_2;
1571 m_key.addr = m->external_addr;
1572 m_key.port = m->external_port;
1573 m_key.protocol = m->proto;
1574 m_key.fib_index = 0;
1575 kv.key = m_key.as_u64;
1576 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1578 nat_elog_err ("static_mapping_by_external key del failed");
1579 return VNET_API_ERROR_UNSPECIFIED;
1583 pool_foreach (local, m->locals,
1585 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1587 m_key.addr = local->addr;
1590 m_key.port = local->port;
1591 m_key.fib_index = local->fib_index;
1592 kv.key = m_key.as_u64;
1593 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1595 nat_elog_err ("static_mapping_by_local key del failed");
1596 return VNET_API_ERROR_UNSPECIFIED;
1600 if (sm->num_workers > 1)
1603 .src_address = local->addr,
1605 tsm = vec_elt_at_index (sm->per_thread_data,
1606 sm->worker_in2out_cb (&ip, m->fib_index, 0));
1609 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1611 /* Delete sessions */
1612 pool_foreach (s, tsm->sessions, {
1613 if (!(is_lb_session (s)))
1616 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1617 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1620 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1621 nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
1626 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1627 pool_free (m->locals);
1629 vec_free (m->workers);
1631 pool_put (sm->static_mappings, m);
1638 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1639 ip4_address_t l_addr, u16 l_port,
1640 snat_protocol_t proto, u32 vrf_id,
1641 u8 probability, u8 is_add)
1643 snat_main_t *sm = &snat_main;
1644 snat_static_mapping_t *m = 0;
1645 snat_session_key_t m_key;
1646 clib_bihash_kv_8_8_t kv, value;
1647 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1648 snat_main_per_thread_data_t *tsm;
1654 if (!sm->endpoint_dependent)
1655 return VNET_API_ERROR_FEATURE_DISABLED;
1657 m_key.addr = e_addr;
1658 m_key.port = e_port;
1659 m_key.protocol = proto;
1660 m_key.fib_index = 0;
1661 kv.key = m_key.as_u64;
1662 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1663 m = pool_elt_at_index (sm->static_mappings, value.value);
1666 return VNET_API_ERROR_NO_SUCH_ENTRY;
1668 if (!is_lb_static_mapping (m))
1669 return VNET_API_ERROR_INVALID_VALUE;
1672 pool_foreach (local, m->locals,
1674 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1675 (local->vrf_id == vrf_id))
1677 match_local = local;
1686 return VNET_API_ERROR_VALUE_EXIST;
1688 pool_get (m->locals, local);
1689 clib_memset (local, 0, sizeof (*local));
1690 local->addr.as_u32 = l_addr.as_u32;
1691 local->port = l_port;
1692 local->probability = probability;
1693 local->vrf_id = vrf_id;
1695 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1698 if (!is_out2in_only_static_mapping (m))
1700 m_key.addr = l_addr;
1701 m_key.port = l_port;
1702 m_key.fib_index = local->fib_index;
1703 kv.key = m_key.as_u64;
1704 kv.value = m - sm->static_mappings;
1705 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1706 nat_elog_err ("static_mapping_by_local key add failed");
1712 return VNET_API_ERROR_NO_SUCH_ENTRY;
1714 if (pool_elts (m->locals) < 3)
1715 return VNET_API_ERROR_UNSPECIFIED;
1717 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1720 if (!is_out2in_only_static_mapping (m))
1722 m_key.addr = l_addr;
1723 m_key.port = l_port;
1724 m_key.fib_index = match_local->fib_index;
1725 kv.key = m_key.as_u64;
1726 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1727 nat_elog_err ("static_mapping_by_local key del failed");
1730 if (sm->num_workers > 1)
1733 .src_address = local->addr,
1735 tsm = vec_elt_at_index (sm->per_thread_data,
1736 sm->worker_in2out_cb (&ip, m->fib_index,
1740 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1742 /* Delete sessions */
1744 pool_foreach (s, tsm->sessions, {
1745 if (!(is_lb_session (s)))
1748 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1749 (clib_net_to_host_u16 (s->in2out.port) != match_local->port))
1752 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1753 nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
1757 pool_put (m->locals, match_local);
1760 vec_free (m->workers);
1763 pool_foreach (local, m->locals,
1765 vec_add1 (locals, local - m->locals);
1766 if (sm->num_workers > 1)
1769 ip.src_address.as_u32 = local->addr.as_u32,
1770 bitmap = clib_bitmap_set (bitmap,
1771 sm->worker_in2out_cb (&ip, local->fib_index, 0),
1777 ASSERT (vec_len (locals) > 1);
1779 local = pool_elt_at_index (m->locals, locals[0]);
1780 local->prefix = local->probability;
1781 for (i = 1; i < vec_len (locals); i++)
1783 local = pool_elt_at_index (m->locals, locals[i]);
1784 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1785 local->prefix = local->probability + prev_local->prefix;
1788 /* Assign workers */
1789 if (sm->num_workers > 1)
1792 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1800 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1803 snat_address_t *a = 0;
1804 snat_session_t *ses;
1805 u32 *ses_to_be_removed = 0, *ses_index;
1806 snat_main_per_thread_data_t *tsm;
1807 snat_static_mapping_t *m;
1808 snat_interface_t *interface;
1810 snat_address_t *addresses =
1811 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1813 /* Find SNAT address */
1814 for (i = 0; i < vec_len (addresses); i++)
1816 if (addresses[i].addr.as_u32 == addr.as_u32)
1823 return VNET_API_ERROR_NO_SUCH_ENTRY;
1828 pool_foreach (m, sm->static_mappings,
1830 if (m->external_addr.as_u32 == addr.as_u32)
1831 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1832 m->local_port, m->external_port,
1833 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1834 m->proto, 0, m->twice_nat,
1835 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1841 /* Check if address is used in some static mapping */
1842 if (is_snat_address_used_in_static_mapping (sm, addr))
1844 nat_elog_notice ("address used in static mapping");
1845 return VNET_API_ERROR_UNSPECIFIED;
1849 if (a->fib_index != ~0)
1850 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1852 /* Delete sessions using address */
1853 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1856 vec_foreach (tsm, sm->per_thread_data)
1858 pool_foreach (ses, tsm->sessions, ({
1859 if (ses->out2in.addr.as_u32 == addr.as_u32)
1861 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1862 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1866 if (sm->endpoint_dependent){
1867 vec_foreach (ses_index, ses_to_be_removed)
1869 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1870 nat44_ed_delete_session (sm, ses, tsm - sm->per_thread_data, 1);
1873 vec_foreach (ses_index, ses_to_be_removed)
1875 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1876 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1880 vec_free (ses_to_be_removed);
1885 #define _(N, i, n, s) \
1886 vec_free (a->busy_##n##_ports_per_thread);
1887 foreach_snat_protocol
1891 vec_del1 (sm->twice_nat_addresses, i);
1895 vec_del1 (sm->addresses, i);
1897 /* Delete external address from FIB */
1899 pool_foreach (interface, sm->interfaces,
1901 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1904 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1907 pool_foreach (interface, sm->output_feature_interfaces,
1909 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1912 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1921 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1923 snat_main_t *sm = &snat_main;
1924 snat_interface_t *i;
1925 const char *feature_name, *del_feature_name;
1927 snat_static_mapping_t *m;
1929 nat_outside_fib_t *outside_fib;
1930 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1933 if (sm->out2in_dpo && !is_inside)
1934 return VNET_API_ERROR_UNSUPPORTED;
1937 pool_foreach (i, sm->output_feature_interfaces,
1939 if (i->sw_if_index == sw_if_index)
1940 return VNET_API_ERROR_VALUE_EXIST;
1944 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1945 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1948 if (sm->num_workers > 1 && !sm->deterministic)
1950 is_inside ? "nat44-in2out-worker-handoff" :
1951 "nat44-out2in-worker-handoff";
1952 else if (sm->deterministic)
1953 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1954 else if (sm->endpoint_dependent)
1956 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1959 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1962 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1963 sm->fq_in2out_index =
1964 vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
1966 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1967 sm->fq_out2in_index =
1968 vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
1973 vec_foreach (outside_fib, sm->outside_fibs)
1975 if (outside_fib->fib_index == fib_index)
1979 outside_fib->refcount--;
1980 if (!outside_fib->refcount)
1981 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1984 outside_fib->refcount++;
1991 vec_add2 (sm->outside_fibs, outside_fib, 1);
1992 outside_fib->refcount = 1;
1993 outside_fib->fib_index = fib_index;
1998 pool_foreach (i, sm->interfaces,
2000 if (i->sw_if_index == sw_if_index)
2004 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
2007 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
2009 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
2011 if (sm->num_workers > 1 && !sm->deterministic)
2013 del_feature_name = "nat44-handoff-classify";
2014 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
2015 "nat44-out2in-worker-handoff";
2017 else if (sm->deterministic)
2019 del_feature_name = "nat44-det-classify";
2020 feature_name = !is_inside ? "nat44-det-in2out" :
2023 else if (sm->endpoint_dependent)
2025 del_feature_name = "nat44-ed-classify";
2026 feature_name = !is_inside ? "nat-pre-in2out" :
2031 del_feature_name = "nat44-classify";
2032 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
2035 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2038 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2039 sw_if_index, 0, 0, 0);
2040 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2041 sw_if_index, 1, 0, 0);
2044 if (sm->endpoint_dependent)
2045 vnet_feature_enable_disable ("ip4-local",
2046 "nat44-ed-hairpinning",
2047 sw_if_index, 1, 0, 0);
2048 else if (!sm->deterministic)
2049 vnet_feature_enable_disable ("ip4-local",
2050 "nat44-hairpinning",
2051 sw_if_index, 1, 0, 0);
2056 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2059 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2060 sw_if_index, 0, 0, 0);
2061 pool_put (sm->interfaces, i);
2064 if (sm->endpoint_dependent)
2065 vnet_feature_enable_disable ("ip4-local",
2066 "nat44-ed-hairpinning",
2067 sw_if_index, 0, 0, 0);
2068 else if (!sm->deterministic)
2069 vnet_feature_enable_disable ("ip4-local",
2070 "nat44-hairpinning",
2071 sw_if_index, 0, 0, 0);
2077 if ((nat_interface_is_inside(i) && is_inside) ||
2078 (nat_interface_is_outside(i) && !is_inside))
2081 if (sm->num_workers > 1 && !sm->deterministic)
2083 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
2084 "nat44-out2in-worker-handoff";
2085 feature_name = "nat44-handoff-classify";
2087 else if (sm->deterministic)
2089 del_feature_name = !is_inside ? "nat44-det-in2out" :
2091 feature_name = "nat44-det-classify";
2093 else if (sm->endpoint_dependent)
2095 del_feature_name = !is_inside ? "nat-pre-in2out" :
2098 feature_name = "nat44-ed-classify";
2102 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
2103 feature_name = "nat44-classify";
2106 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2109 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2110 sw_if_index, 0, 0, 0);
2111 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2112 sw_if_index, 1, 0, 0);
2115 if (sm->endpoint_dependent)
2116 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2117 sw_if_index, 0, 0, 0);
2118 else if (!sm->deterministic)
2119 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2120 sw_if_index, 0, 0, 0);
2131 return VNET_API_ERROR_NO_SUCH_ENTRY;
2133 pool_get (sm->interfaces, i);
2134 i->sw_if_index = sw_if_index;
2136 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
2139 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2143 if (is_inside && !sm->out2in_dpo)
2145 if (sm->endpoint_dependent)
2146 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2147 sw_if_index, 1, 0, 0);
2148 else if (!sm->deterministic)
2149 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2150 sw_if_index, 1, 0, 0);
2156 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2160 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2162 /* Add/delete external addresses to FIB */
2165 vec_foreach (ap, sm->addresses)
2166 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2168 pool_foreach (m, sm->static_mappings,
2170 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2173 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2176 pool_foreach (dm, sm->det_maps,
2178 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2186 snat_interface_add_del_output_feature (u32 sw_if_index,
2187 u8 is_inside, int is_del)
2189 snat_main_t *sm = &snat_main;
2190 snat_interface_t *i;
2192 snat_static_mapping_t *m;
2193 nat_outside_fib_t *outside_fib;
2194 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2198 if (sm->deterministic ||
2199 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2200 return VNET_API_ERROR_UNSUPPORTED;
2203 pool_foreach (i, sm->interfaces,
2205 if (i->sw_if_index == sw_if_index)
2206 return VNET_API_ERROR_VALUE_EXIST;
2213 vec_foreach (outside_fib, sm->outside_fibs)
2215 if (outside_fib->fib_index == fib_index)
2219 outside_fib->refcount--;
2220 if (!outside_fib->refcount)
2221 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2224 outside_fib->refcount++;
2231 vec_add2 (sm->outside_fibs, outside_fib, 1);
2232 outside_fib->refcount = 1;
2233 outside_fib->fib_index = fib_index;
2240 if (sm->endpoint_dependent)
2243 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2247 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2251 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2252 sw_if_index, !is_del, 0, 0);
2253 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2254 sw_if_index, !is_del, 0, 0);
2259 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2263 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2267 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2268 sw_if_index, !is_del, 0, 0);
2269 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2270 sw_if_index, !is_del, 0, 0);
2275 if (sm->num_workers > 1)
2277 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2281 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2284 vnet_feature_enable_disable ("ip4-unicast",
2285 "nat44-out2in-worker-handoff",
2286 sw_if_index, !is_del, 0, 0);
2287 vnet_feature_enable_disable ("ip4-output",
2288 "nat44-in2out-output-worker-handoff",
2289 sw_if_index, !is_del, 0, 0);
2293 if (sm->endpoint_dependent)
2296 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2300 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2304 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2305 sw_if_index, !is_del, 0, 0);
2306 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2307 sw_if_index, !is_del, 0, 0);
2312 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2316 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2320 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2321 sw_if_index, !is_del, 0, 0);
2322 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2323 sw_if_index, !is_del, 0, 0);
2328 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2329 sm->fq_in2out_output_index =
2330 vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
2332 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2333 sm->fq_out2in_index =
2334 vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
2337 pool_foreach (i, sm->output_feature_interfaces,
2339 if (i->sw_if_index == sw_if_index)
2342 pool_put (sm->output_feature_interfaces, i);
2344 return VNET_API_ERROR_VALUE_EXIST;
2352 return VNET_API_ERROR_NO_SUCH_ENTRY;
2354 pool_get (sm->output_feature_interfaces, i);
2355 i->sw_if_index = sw_if_index;
2358 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2360 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2362 /* Add/delete external addresses to FIB */
2368 vec_foreach (ap, sm->addresses)
2369 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2371 pool_foreach (m, sm->static_mappings,
2373 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2376 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2384 snat_set_workers (uword * bitmap)
2386 snat_main_t *sm = &snat_main;
2389 if (sm->num_workers < 2)
2390 return VNET_API_ERROR_FEATURE_DISABLED;
2392 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2393 return VNET_API_ERROR_INVALID_WORKER;
2395 vec_free (sm->workers);
2397 clib_bitmap_foreach (i, bitmap,
2399 vec_add1(sm->workers, i);
2400 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2401 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2406 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2407 sm->num_snat_thread = _vec_len (sm->workers);
2413 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2416 snat_main_t *sm = &snat_main;
2417 nat_outside_fib_t *outside_fib;
2418 snat_interface_t *i;
2422 if (new_fib_index == old_fib_index)
2425 if (!vec_len (sm->outside_fibs))
2429 pool_foreach (i, sm->interfaces,
2431 if (i->sw_if_index == sw_if_index)
2433 if (!(nat_interface_is_outside (i)))
2439 pool_foreach (i, sm->output_feature_interfaces,
2441 if (i->sw_if_index == sw_if_index)
2443 if (!(nat_interface_is_outside (i)))
2453 vec_foreach (outside_fib, sm->outside_fibs)
2455 if (outside_fib->fib_index == old_fib_index)
2457 outside_fib->refcount--;
2458 if (!outside_fib->refcount)
2459 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2464 vec_foreach (outside_fib, sm->outside_fibs)
2466 if (outside_fib->fib_index == new_fib_index)
2468 outside_fib->refcount++;
2476 vec_add2 (sm->outside_fibs, outside_fib, 1);
2477 outside_fib->refcount = 1;
2478 outside_fib->fib_index = new_fib_index;
2483 snat_ip4_table_bind (ip4_main_t * im,
2485 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2487 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2491 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2494 ip4_address_t * address,
2496 u32 if_address_index, u32 is_delete);
2499 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2502 ip4_address_t * address,
2504 u32 if_address_index, u32 is_delete);
2507 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2510 snat_session_key_t * k,
2511 u16 port_per_thread, u32 snat_thread_index);
2514 test_ed_make_split ()
2516 ip4_address_t l_addr;
2517 l_addr.as_u8[0] = 1;
2518 l_addr.as_u8[1] = 1;
2519 l_addr.as_u8[2] = 1;
2520 l_addr.as_u8[3] = 1;
2521 ip4_address_t r_addr;
2522 r_addr.as_u8[0] = 2;
2523 r_addr.as_u8[1] = 2;
2524 r_addr.as_u8[2] = 2;
2525 r_addr.as_u8[3] = 2;
2529 u32 fib_index = 9000001;
2531 clib_bihash_kv_16_8_t kv;
2532 make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port, value, &kv);
2533 ip4_address_t l_addr2;
2534 ip4_address_t r_addr2;
2535 clib_memset (&l_addr2, 0, sizeof (l_addr2));
2536 clib_memset (&r_addr2, 0, sizeof (r_addr2));
2541 split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
2543 u64 value2 = kv.value;
2544 ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2545 ASSERT (r_addr.as_u32 == r_addr2.as_u32);
2546 ASSERT (l_port == l_port2);
2547 ASSERT (r_port == r_port2);
2548 ASSERT (proto == proto2);
2549 ASSERT (fib_index == fib_index2);
2550 ASSERT (value == value2);
2553 always_inline vlib_main_t *
2554 nat_get_vlib_main (u32 thread_index)
2557 vm = vlib_mains[thread_index];
2562 static clib_error_t *
2563 snat_init (vlib_main_t * vm)
2565 snat_main_per_thread_data_t *tsm;
2567 snat_main_t *sm = &snat_main;
2568 clib_error_t *error = 0;
2569 ip4_main_t *im = &ip4_main;
2570 ip_lookup_main_t *lm = &im->lookup_main;
2572 vlib_thread_registration_t *tr;
2573 vlib_thread_main_t *tm = vlib_get_thread_main ();
2576 ip4_add_del_interface_address_callback_t cb4;
2579 sm->vnet_main = vnet_get_main ();
2581 sm->ip4_lookup_main = lm;
2582 sm->api_main = vlibapi_get_main ();
2583 sm->first_worker_index = 0;
2584 sm->num_workers = 0;
2585 sm->num_snat_thread = 1;
2587 sm->port_per_thread = 0xffff - 1024;
2588 sm->fq_in2out_index = ~0;
2589 sm->fq_in2out_output_index = ~0;
2590 sm->fq_out2in_index = ~0;
2592 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2593 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2594 sm->forwarding_enabled = 0;
2595 sm->log_class = vlib_log_register_class ("nat", 0);
2596 sm->log_level = SNAT_LOG_ERROR;
2597 sm->mss_clamping = 0;
2599 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2600 sm->error_node_index = node->index;
2602 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2603 sm->pre_in2out_node_index = node->index;
2604 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2605 sm->pre_out2in_node_index = node->index;
2607 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2608 sm->pre_in2out_node_index = node->index;
2610 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2611 sm->pre_out2in_node_index = node->index;
2613 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2614 sm->in2out_node_index = node->index;
2615 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2616 sm->in2out_output_node_index = node->index;
2617 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2618 sm->in2out_fast_node_index = node->index;
2619 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2620 sm->in2out_slowpath_node_index = node->index;
2621 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2622 sm->in2out_slowpath_output_node_index = node->index;
2624 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2625 sm->ed_in2out_node_index = node->index;
2626 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2627 sm->ed_in2out_slowpath_node_index = node->index;
2629 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2630 sm->out2in_node_index = node->index;
2631 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2632 sm->out2in_fast_node_index = node->index;
2634 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2635 sm->ed_out2in_node_index = node->index;
2636 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2637 sm->ed_out2in_slowpath_node_index = node->index;
2639 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2640 sm->det_in2out_node_index = node->index;
2641 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2642 sm->det_out2in_node_index = node->index;
2644 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2645 sm->hairpinning_node_index = node->index;
2646 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2647 sm->hairpin_dst_node_index = node->index;
2648 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2649 sm->hairpin_src_node_index = node->index;
2650 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2651 sm->ed_hairpinning_node_index = node->index;
2652 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2653 sm->ed_hairpin_dst_node_index = node->index;
2654 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2655 sm->ed_hairpin_src_node_index = node->index;
2657 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2660 tr = (vlib_thread_registration_t *) p[0];
2663 sm->num_workers = tr->count;
2664 sm->first_worker_index = tr->first_index;
2668 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2670 /* Use all available workers by default */
2671 if (sm->num_workers > 1)
2673 for (i = 0; i < sm->num_workers; i++)
2674 bitmap = clib_bitmap_set (bitmap, i, 1);
2675 // sets thread indexes for workes
2676 snat_set_workers (bitmap);
2677 clib_bitmap_free (bitmap);
2681 sm->per_thread_data[0].snat_thread_index = 0;
2684 vec_foreach (tsm, sm->per_thread_data)
2686 tsm->vlib_main = nat_get_vlib_main (tsm->thread_index);
2689 error = snat_api_init (vm, sm);
2693 /* Set up the interface address add/del callback */
2694 cb4.function = snat_ip4_add_del_interface_address_cb;
2695 cb4.function_opaque = 0;
2697 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2699 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2700 cb4.function_opaque = 0;
2702 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2704 nat_dpo_module_init ();
2707 sm->total_users.name = "total-users";
2708 sm->total_users.stat_segment_name = "/nat44/total-users";
2709 vlib_validate_simple_counter (&sm->total_users, 0);
2710 vlib_zero_simple_counter (&sm->total_users, 0);
2711 sm->total_sessions.name = "total-sessions";
2712 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2713 vlib_validate_simple_counter (&sm->total_sessions, 0);
2714 vlib_zero_simple_counter (&sm->total_sessions, 0);
2716 /* Init IPFIX logging */
2717 snat_ipfix_logging_init (vm);
2720 error = nat64_init (vm);
2726 ip4_table_bind_callback_t cbt4 = {
2727 .function = snat_ip4_table_bind,
2729 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2731 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2732 FIB_SOURCE_PRIORITY_HI,
2733 FIB_SOURCE_BH_SIMPLE);
2734 nat_fib_src_low = fib_source_allocate ("nat-low",
2735 FIB_SOURCE_PRIORITY_LOW,
2736 FIB_SOURCE_BH_SIMPLE);
2738 test_ed_make_split ();
2742 VLIB_INIT_FUNCTION (snat_init);
2745 snat_free_outside_address_and_port (snat_address_t * addresses,
2746 u32 thread_index, snat_session_key_t * k)
2750 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2752 for (address_index = 0; address_index < vec_len (addresses);
2755 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2759 ASSERT (address_index < vec_len (addresses));
2761 a = addresses + address_index;
2763 switch (k->protocol)
2765 #define _(N, i, n, s) \
2766 case SNAT_PROTOCOL_##N: \
2767 ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2768 --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2769 a->busy_##n##_ports--; \
2770 a->busy_##n##_ports_per_thread[thread_index]--; \
2772 foreach_snat_protocol
2775 nat_elog_info ("unknown protocol");
2781 nat_set_outside_address_and_port (snat_address_t * addresses,
2782 u32 thread_index, snat_session_key_t * k)
2784 snat_address_t *a = 0;
2786 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2788 for (address_index = 0; address_index < vec_len (addresses);
2791 if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2794 a = addresses + address_index;
2795 switch (k->protocol)
2797 #define _(N, j, n, s) \
2798 case SNAT_PROTOCOL_##N: \
2799 if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
2800 return VNET_API_ERROR_INSTANCE_IN_USE; \
2801 ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
2802 a->busy_##n##_ports_per_thread[thread_index]++; \
2803 a->busy_##n##_ports++; \
2805 foreach_snat_protocol
2808 nat_elog_info ("unknown protocol");
2813 return VNET_API_ERROR_NO_SUCH_ENTRY;
2817 snat_static_mapping_match (snat_main_t * sm,
2818 snat_session_key_t match,
2819 snat_session_key_t * mapping,
2822 twice_nat_type_t * twice_nat,
2823 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2824 u8 * is_identity_nat)
2826 clib_bihash_kv_8_8_t kv, value;
2827 snat_static_mapping_t *m;
2828 snat_session_key_t m_key;
2829 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2830 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2832 nat44_lb_addr_port_t *local;
2834 m_key.fib_index = match.fib_index;
2837 mapping_hash = &sm->static_mapping_by_external;
2838 m_key.fib_index = 0;
2841 m_key.addr = match.addr;
2842 m_key.port = clib_net_to_host_u16 (match.port);
2843 m_key.protocol = match.protocol;
2845 kv.key = m_key.as_u64;
2847 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2849 /* Try address only mapping */
2852 kv.key = m_key.as_u64;
2853 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2857 m = pool_elt_at_index (sm->static_mappings, value.value);
2861 if (is_lb_static_mapping (m))
2863 if (PREDICT_FALSE (lb != 0))
2864 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2865 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2871 local = pool_elt_at_index (m->locals, backend_index);
2872 mapping->addr = local->addr;
2873 mapping->port = clib_host_to_net_u16 (local->port);
2874 mapping->fib_index = local->fib_index;
2877 // pick locals matching this worker
2878 if (PREDICT_FALSE (sm->num_workers > 1))
2880 u32 thread_index = vlib_get_thread_index ();
2882 pool_foreach_index (i, m->locals,
2884 local = pool_elt_at_index (m->locals, i);
2887 .src_address = local->addr,
2890 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2897 ASSERT (vec_len (tmp) != 0);
2902 pool_foreach_index (i, m->locals,
2908 hi = vec_len (tmp) - 1;
2909 local = pool_elt_at_index (m->locals, tmp[hi]);
2910 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2913 mid = ((hi - lo) >> 1) + lo;
2914 local = pool_elt_at_index (m->locals, tmp[mid]);
2915 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2917 local = pool_elt_at_index (m->locals, tmp[lo]);
2918 if (!(local->prefix >= rand))
2920 mapping->addr = local->addr;
2921 mapping->port = clib_host_to_net_u16 (local->port);
2922 mapping->fib_index = local->fib_index;
2925 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2926 match.protocol, match.port,
2927 tmp[lo], m->affinity,
2928 m->affinity_per_service_list_head_index))
2929 nat_elog_info ("create affinity record failed");
2935 if (PREDICT_FALSE (lb != 0))
2937 mapping->fib_index = m->fib_index;
2938 mapping->addr = m->local_addr;
2939 /* Address only mapping doesn't change port */
2940 mapping->port = is_addr_only_static_mapping (m) ? match.port
2941 : clib_host_to_net_u16 (m->local_port);
2943 mapping->protocol = m->proto;
2947 mapping->addr = m->external_addr;
2948 /* Address only mapping doesn't change port */
2949 mapping->port = is_addr_only_static_mapping (m) ? match.port
2950 : clib_host_to_net_u16 (m->external_port);
2951 mapping->fib_index = sm->outside_fib_index;
2955 if (PREDICT_FALSE (is_addr_only != 0))
2956 *is_addr_only = is_addr_only_static_mapping (m);
2958 if (PREDICT_FALSE (twice_nat != 0))
2959 *twice_nat = m->twice_nat;
2961 if (PREDICT_FALSE (is_identity_nat != 0))
2962 *is_identity_nat = is_identity_static_mapping (m);
2967 static_always_inline u16
2968 snat_random_port (u16 min, u16 max)
2970 snat_main_t *sm = &snat_main;
2971 return min + random_u32 (&sm->random_seed) /
2972 (random_u32_max () / (max - min + 1) + 1);
2976 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2979 snat_session_key_t * k,
2980 u16 port_per_thread,
2981 u32 snat_thread_index)
2983 snat_main_t *sm = &snat_main;
2985 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2986 port_per_thread, snat_thread_index);
2990 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2993 snat_session_key_t * k,
2994 u16 port_per_thread, u32 snat_thread_index)
2997 snat_address_t *a, *ga = 0;
3000 for (i = 0; i < vec_len (addresses); i++)
3003 switch (k->protocol)
3005 #define _(N, j, n, s) \
3006 case SNAT_PROTOCOL_##N: \
3007 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
3009 if (a->fib_index == fib_index) \
3013 portnum = (port_per_thread * \
3014 snat_thread_index) + \
3015 snat_random_port(1, port_per_thread) + 1024; \
3016 if (a->busy_##n##_port_refcounts[portnum]) \
3018 --a->busy_##n##_port_refcounts[portnum]; \
3019 a->busy_##n##_ports_per_thread[thread_index]++; \
3020 a->busy_##n##_ports++; \
3021 k->addr = a->addr; \
3022 k->port = clib_host_to_net_u16(portnum); \
3026 else if (a->fib_index == ~0) \
3032 foreach_snat_protocol
3035 nat_elog_info ("unknown protocol");
3044 switch (k->protocol)
3046 #define _(N, j, n, s) \
3047 case SNAT_PROTOCOL_##N: \
3050 portnum = (port_per_thread * \
3051 snat_thread_index) + \
3052 snat_random_port(1, port_per_thread) + 1024; \
3053 if (a->busy_##n##_port_refcounts[portnum]) \
3055 ++a->busy_##n##_port_refcounts[portnum]; \
3056 a->busy_##n##_ports_per_thread[thread_index]++; \
3057 a->busy_##n##_ports++; \
3058 k->addr = a->addr; \
3059 k->port = clib_host_to_net_u16(portnum); \
3063 foreach_snat_protocol
3066 nat_elog_info ("unknown protocol");
3071 /* Totally out of translations to use... */
3072 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3077 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
3080 snat_session_key_t * k,
3081 u16 port_per_thread, u32 snat_thread_index)
3083 snat_main_t *sm = &snat_main;
3084 snat_address_t *a = addresses;
3085 u16 m, ports, portnum, A, j;
3086 m = 16 - (sm->psid_offset + sm->psid_length);
3087 ports = (1 << (16 - sm->psid_length)) - (1 << m);
3089 if (!vec_len (addresses))
3092 switch (k->protocol)
3094 #define _(N, i, n, s) \
3095 case SNAT_PROTOCOL_##N: \
3096 if (a->busy_##n##_ports < ports) \
3100 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
3101 j = snat_random_port(0, pow2_mask(m)); \
3102 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
3103 if (a->busy_##n##_port_refcounts[portnum]) \
3105 ++a->busy_##n##_port_refcounts[portnum]; \
3106 a->busy_##n##_ports++; \
3107 k->addr = a->addr; \
3108 k->port = clib_host_to_net_u16 (portnum); \
3113 foreach_snat_protocol
3116 nat_elog_info ("unknown protocol");
3121 /* Totally out of translations to use... */
3122 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3127 nat_alloc_addr_and_port_range (snat_address_t * addresses,
3130 snat_session_key_t * k,
3131 u16 port_per_thread, u32 snat_thread_index)
3133 snat_main_t *sm = &snat_main;
3134 snat_address_t *a = addresses;
3137 ports = sm->end_port - sm->start_port + 1;
3139 if (!vec_len (addresses))
3142 switch (k->protocol)
3144 #define _(N, i, n, s) \
3145 case SNAT_PROTOCOL_##N: \
3146 if (a->busy_##n##_ports < ports) \
3150 portnum = snat_random_port(sm->start_port, sm->end_port); \
3151 if (a->busy_##n##_port_refcounts[portnum]) \
3153 ++a->busy_##n##_port_refcounts[portnum]; \
3154 a->busy_##n##_ports++; \
3155 k->addr = a->addr; \
3156 k->port = clib_host_to_net_u16 (portnum); \
3161 foreach_snat_protocol
3164 nat_elog_info ("unknown protocol");
3169 /* Totally out of translations to use... */
3170 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3175 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
3177 dpo_id_t dpo_v4 = DPO_INVALID;
3178 fib_prefix_t pfx = {
3179 .fp_proto = FIB_PROTOCOL_IP4,
3181 .fp_addr.ip4.as_u32 = addr.as_u32,
3186 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
3187 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
3188 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
3189 dpo_reset (&dpo_v4);
3193 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
3198 format_session_kvp (u8 * s, va_list * args)
3200 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3201 snat_session_key_t k;
3205 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
3211 format_static_mapping_kvp (u8 * s, va_list * args)
3213 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3214 snat_session_key_t k;
3218 s = format (s, "%U static-mapping-index %llu",
3219 format_static_mapping_key, &k, v->value);
3225 format_user_kvp (u8 * s, va_list * args)
3227 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3232 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
3233 k.fib_index, v->value);
3239 format_ed_session_kvp (u8 * s, va_list * args)
3241 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3245 ip4_address_t l_addr, r_addr;
3248 split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
3250 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
3251 format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
3252 format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
3253 format_ip_protocol, proto, fib_index, v->value);
3259 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3262 snat_main_t *sm = &snat_main;
3263 u32 next_worker_index = 0;
3266 next_worker_index = sm->first_worker_index;
3267 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3268 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3270 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3271 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3273 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3275 return next_worker_index;
3279 snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
3280 u32 rx_fib_index0, u8 is_output)
3282 snat_main_t *sm = &snat_main;
3285 snat_session_key_t m_key;
3286 clib_bihash_kv_8_8_t kv, value;
3287 snat_static_mapping_t *m;
3289 u32 next_worker_index = 0;
3291 /* first try static mappings without port */
3292 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3294 m_key.addr = ip0->dst_address;
3297 m_key.fib_index = rx_fib_index0;
3298 kv.key = m_key.as_u64;
3299 if (!clib_bihash_search_8_8
3300 (&sm->static_mapping_by_external, &kv, &value))
3302 m = pool_elt_at_index (sm->static_mappings, value.value);
3303 return m->workers[0];
3307 proto = ip_proto_to_snat_proto (ip0->protocol);
3308 udp = ip4_next_header (ip0);
3309 port = udp->dst_port;
3311 /* unknown protocol */
3312 if (PREDICT_FALSE (proto == ~0))
3314 /* use current thread */
3315 return vlib_get_thread_index ();
3318 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3320 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3321 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3322 if (!icmp_type_is_error_message
3323 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3324 port = vnet_buffer (b)->ip.reass.l4_src_port;
3327 /* if error message, then it's not fragmented and we can access it */
3328 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3329 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3330 void *l4_header = ip4_next_header (inner_ip);
3333 case SNAT_PROTOCOL_ICMP:
3334 icmp = (icmp46_header_t *) l4_header;
3335 echo = (icmp_echo_header_t *) (icmp + 1);
3336 port = echo->identifier;
3338 case SNAT_PROTOCOL_UDP:
3339 case SNAT_PROTOCOL_TCP:
3340 port = ((tcp_udp_header_t *) l4_header)->src_port;
3343 return vlib_get_thread_index ();
3348 /* try static mappings with port */
3349 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3351 m_key.addr = ip0->dst_address;
3352 m_key.port = clib_net_to_host_u16 (port);
3353 m_key.protocol = proto;
3354 m_key.fib_index = rx_fib_index0;
3355 kv.key = m_key.as_u64;
3356 if (!clib_bihash_search_8_8
3357 (&sm->static_mapping_by_external, &kv, &value))
3359 m = pool_elt_at_index (sm->static_mappings, value.value);
3360 return m->workers[0];
3364 /* worker by outside port */
3365 next_worker_index = sm->first_worker_index;
3366 next_worker_index +=
3367 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3368 return next_worker_index;
3372 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3375 snat_main_t *sm = &snat_main;
3376 u32 next_worker_index = sm->first_worker_index;
3379 clib_bihash_kv_16_8_t kv16, value16;
3380 snat_main_per_thread_data_t *tsm;
3383 if (PREDICT_FALSE (is_output))
3385 u32 fib_index = sm->outside_fib_index;
3386 nat_outside_fib_t *outside_fib;
3387 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3388 fib_prefix_t pfx = {
3389 .fp_proto = FIB_PROTOCOL_IP4,
3392 .ip4.as_u32 = ip->dst_address.as_u32,
3397 udp = ip4_next_header (ip);
3399 switch (vec_len (sm->outside_fibs))
3402 fib_index = sm->outside_fib_index;
3405 fib_index = sm->outside_fibs[0].fib_index;
3409 vec_foreach (outside_fib, sm->outside_fibs)
3411 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3412 if (FIB_NODE_INDEX_INVALID != fei)
3414 if (fib_entry_get_resolving_interface (fei) != ~0)
3416 fib_index = outside_fib->fib_index;
3425 make_ed_kv (&ip->src_address, &ip->dst_address,
3426 ip->protocol, fib_index, udp->src_port, udp->dst_port,
3430 vec_foreach (tsm, sm->per_thread_data)
3432 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3435 next_worker_index += tsm->thread_index;
3437 nat_elog_debug_handoff (
3438 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3439 next_worker_index, fib_index,
3440 clib_net_to_host_u32 (ip->src_address.as_u32),
3441 clib_net_to_host_u32 (ip->dst_address.as_u32));
3443 return next_worker_index;
3449 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3450 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3452 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3453 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3455 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3457 if (PREDICT_TRUE (!is_output))
3459 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3460 next_worker_index, rx_fib_index,
3461 clib_net_to_host_u32 (ip->src_address.as_u32),
3462 clib_net_to_host_u32 (ip->dst_address.as_u32));
3466 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3467 next_worker_index, rx_fib_index,
3468 clib_net_to_host_u32 (ip->src_address.as_u32),
3469 clib_net_to_host_u32 (ip->dst_address.as_u32));
3472 return next_worker_index;
3476 nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
3477 u32 rx_fib_index, u8 is_output)
3479 snat_main_t *sm = &snat_main;
3480 clib_bihash_kv_8_8_t kv, value;
3481 clib_bihash_kv_16_8_t kv16, value16;
3482 snat_main_per_thread_data_t *tsm;
3484 u32 proto, next_worker_index = 0;
3487 snat_static_mapping_t *m;
3490 proto = ip_proto_to_snat_proto (ip->protocol);
3492 if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3494 udp = ip4_next_header (ip);
3496 make_ed_kv (&ip->dst_address, &ip->src_address,
3497 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port,
3501 vec_foreach (tsm, sm->per_thread_data)
3503 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3506 next_worker_index = sm->first_worker_index + tsm->thread_index;
3507 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3508 next_worker_index, rx_fib_index,
3509 clib_net_to_host_u32 (ip->src_address.as_u32),
3510 clib_net_to_host_u32 (ip->dst_address.as_u32));
3511 return next_worker_index;
3516 else if (proto == SNAT_PROTOCOL_ICMP)
3518 if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0ULL, 0, 0, 0, &kv16))
3521 vec_foreach (tsm, sm->per_thread_data)
3523 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3526 next_worker_index = sm->first_worker_index +
3528 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3529 next_worker_index, rx_fib_index,
3530 clib_net_to_host_u32 (ip->src_address.as_u32),
3531 clib_net_to_host_u32 (ip->dst_address.as_u32));
3532 return next_worker_index;
3539 /* first try static mappings without port */
3540 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3542 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3543 if (!clib_bihash_search_8_8
3544 (&sm->static_mapping_by_external, &kv, &value))
3546 m = pool_elt_at_index (sm->static_mappings, value.value);
3547 next_worker_index = m->workers[0];
3552 /* unknown protocol */
3553 if (PREDICT_FALSE (proto == ~0))
3555 /* use current thread */
3556 next_worker_index = vlib_get_thread_index ();
3560 udp = ip4_next_header (ip);
3561 port = udp->dst_port;
3563 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3565 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3566 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3567 if (!icmp_type_is_error_message
3568 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3569 port = vnet_buffer (b)->ip.reass.l4_src_port;
3572 /* if error message, then it's not fragmented and we can access it */
3573 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3574 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3575 void *l4_header = ip4_next_header (inner_ip);
3578 case SNAT_PROTOCOL_ICMP:
3579 icmp = (icmp46_header_t *) l4_header;
3580 echo = (icmp_echo_header_t *) (icmp + 1);
3581 port = echo->identifier;
3583 case SNAT_PROTOCOL_UDP:
3584 case SNAT_PROTOCOL_TCP:
3585 port = ((tcp_udp_header_t *) l4_header)->src_port;
3588 next_worker_index = vlib_get_thread_index ();
3594 /* try static mappings with port */
3595 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3597 make_sm_kv (&kv, &ip->dst_address, proto, 0,
3598 clib_net_to_host_u16 (port));
3599 if (!clib_bihash_search_8_8
3600 (&sm->static_mapping_by_external, &kv, &value))
3602 m = pool_elt_at_index (sm->static_mappings, value.value);
3603 if (!is_lb_static_mapping (m))
3605 next_worker_index = m->workers[0];
3609 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3610 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3612 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3614 m->workers[hash & (_vec_len (m->workers) - 1)];
3616 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3621 /* worker by outside port */
3622 next_worker_index = sm->first_worker_index;
3623 next_worker_index +=
3624 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3627 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3628 clib_net_to_host_u32 (ip->src_address.as_u32),
3629 clib_net_to_host_u32 (ip->dst_address.as_u32));
3630 return next_worker_index;
3634 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3635 ip4_address_t * out_addr, u16 out_port,
3636 ip4_address_t * eh_addr, u16 eh_port,
3637 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3638 u32 fib_index, u16 flags, u32 thread_index)
3640 snat_main_t *sm = &snat_main;
3641 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3642 snat_session_key_t key;
3645 clib_bihash_kv_8_8_t kv;
3646 f64 now = vlib_time_now (tsm->vlib_main);
3647 nat_outside_fib_t *outside_fib;
3648 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3649 fib_prefix_t pfx = {
3650 .fp_proto = FIB_PROTOCOL_IP4,
3653 .ip4.as_u32 = eh_addr->as_u32,
3657 key.addr.as_u32 = out_addr->as_u32;
3658 key.port = out_port;
3659 key.protocol = proto;
3661 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3663 if (nat_set_outside_address_and_port
3664 (sm->addresses, thread_index, &key))
3668 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3672 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3676 s->last_heard = now;
3678 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3679 s->ext_host_port = eh_port;
3680 user_session_increment (sm, u, snat_is_session_static (s));
3681 switch (vec_len (sm->outside_fibs))
3684 key.fib_index = sm->outside_fib_index;
3687 key.fib_index = sm->outside_fibs[0].fib_index;
3691 vec_foreach (outside_fib, sm->outside_fibs)
3693 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3694 if (FIB_NODE_INDEX_INVALID != fei)
3696 if (fib_entry_get_resolving_interface (fei) != ~0)
3698 key.fib_index = outside_fib->fib_index;
3707 kv.key = key.as_u64;
3708 kv.value = s - tsm->sessions;
3709 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3710 nat_elog_warn ("out2in key add failed");
3712 key.addr.as_u32 = in_addr->as_u32;
3714 key.fib_index = fib_index;
3716 kv.key = key.as_u64;
3717 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3718 nat_elog_warn ("in2out key add failed");
3722 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3723 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3726 snat_main_t *sm = &snat_main;
3727 snat_session_key_t key;
3728 clib_bihash_kv_8_8_t kv, value;
3731 snat_main_per_thread_data_t *tsm;
3733 if (sm->num_workers > 1)
3735 sm->first_worker_index +
3736 (sm->workers[(clib_net_to_host_u16 (out_port) -
3737 1024) / sm->port_per_thread]);
3739 thread_index = sm->num_workers;
3740 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3742 key.addr.as_u32 = out_addr->as_u32;
3743 key.port = out_port;
3744 key.protocol = proto;
3745 key.fib_index = fib_index;
3746 kv.key = key.as_u64;
3747 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3750 s = pool_elt_at_index (tsm->sessions, value.value);
3751 nat_free_session_data (sm, s, thread_index, 1);
3752 nat44_delete_session (sm, s, thread_index);
3756 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3757 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3758 u32 total_pkts, u64 total_bytes, u32 thread_index)
3760 snat_main_t *sm = &snat_main;
3761 snat_session_key_t key;
3762 clib_bihash_kv_8_8_t kv, value;
3764 snat_main_per_thread_data_t *tsm;
3766 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3768 key.addr.as_u32 = out_addr->as_u32;
3769 key.port = out_port;
3770 key.protocol = proto;
3771 key.fib_index = fib_index;
3772 kv.key = key.as_u64;
3773 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3776 s = pool_elt_at_index (tsm->sessions, value.value);
3777 s->total_pkts = total_pkts;
3778 s->total_bytes = total_bytes;
3782 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3783 ip4_address_t * out_addr, u16 out_port,
3784 ip4_address_t * eh_addr, u16 eh_port,
3785 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3786 u32 fib_index, u16 flags, u32 thread_index)
3788 snat_main_t *sm = &snat_main;
3789 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3790 snat_session_key_t key;
3792 clib_bihash_kv_16_8_t kv;
3793 f64 now = vlib_time_now (tsm->vlib_main);
3794 nat_outside_fib_t *outside_fib;
3795 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3796 fib_prefix_t pfx = {
3797 .fp_proto = FIB_PROTOCOL_IP4,
3800 .ip4.as_u32 = eh_addr->as_u32,
3804 key.addr.as_u32 = out_addr->as_u32;
3805 key.port = out_port;
3806 key.protocol = proto;
3808 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3810 if (nat_set_outside_address_and_port
3811 (sm->addresses, thread_index, &key))
3815 key.addr.as_u32 = ehn_addr->as_u32;
3816 key.port = ehn_port;
3817 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3819 if (nat_set_outside_address_and_port
3820 (sm->twice_nat_addresses, thread_index, &key))
3824 s = nat_ed_session_alloc (sm, thread_index, now);
3828 s->last_heard = now;
3830 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3831 s->ext_host_nat_port = s->ext_host_port = eh_port;
3832 if (is_twice_nat_session (s))
3834 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3835 s->ext_host_nat_port = ehn_port;
3837 switch (vec_len (sm->outside_fibs))
3840 key.fib_index = sm->outside_fib_index;
3843 key.fib_index = sm->outside_fibs[0].fib_index;
3847 vec_foreach (outside_fib, sm->outside_fibs)
3849 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3850 if (FIB_NODE_INDEX_INVALID != fei)
3852 if (fib_entry_get_resolving_interface (fei) != ~0)
3854 key.fib_index = outside_fib->fib_index;
3862 key.addr.as_u32 = out_addr->as_u32;
3863 key.port = out_port;
3865 kv.value = s - tsm->sessions;
3867 key.addr.as_u32 = in_addr->as_u32;
3869 key.fib_index = fib_index;
3872 make_ed_kv (in_addr, &s->ext_host_nat_addr,
3873 snat_proto_to_ip_proto (proto), fib_index, in_port,
3874 s->ext_host_nat_port, s - tsm->sessions, &kv);
3875 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3876 nat_elog_warn ("in2out key add failed");
3878 make_ed_kv (out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3879 s->out2in.fib_index, out_port, eh_port, s - tsm->sessions, &kv);
3880 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3881 nat_elog_warn ("out2in key add failed");
3885 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3886 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3887 u32 fib_index, u32 ti)
3889 snat_main_t *sm = &snat_main;
3890 clib_bihash_kv_16_8_t kv, value;
3893 snat_main_per_thread_data_t *tsm;
3895 if (sm->num_workers > 1)
3897 sm->first_worker_index +
3898 (sm->workers[(clib_net_to_host_u16 (out_port) -
3899 1024) / sm->port_per_thread]);
3901 thread_index = sm->num_workers;
3902 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3904 make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
3906 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3909 s = pool_elt_at_index (tsm->sessions, value.value);
3910 nat_free_session_data (sm, s, thread_index, 1);
3911 nat44_delete_session (sm, s, thread_index);
3915 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3916 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3917 u32 fib_index, u32 total_pkts, u64 total_bytes,
3920 snat_main_t *sm = &snat_main;
3921 clib_bihash_kv_16_8_t kv, value;
3923 snat_main_per_thread_data_t *tsm;
3925 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3927 make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
3929 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3932 s = pool_elt_at_index (tsm->sessions, value.value);
3933 s->total_pkts = total_pkts;
3934 s->total_bytes = total_bytes;
3938 nat44_db_init (snat_main_per_thread_data_t * tsm)
3940 snat_main_t *sm = &snat_main;
3942 pool_alloc (tsm->sessions, sm->max_translations);
3943 pool_alloc (tsm->global_lru_pool, sm->max_translations);
3946 pool_get (tsm->global_lru_pool, head);
3947 tsm->global_lru_head_index = head - tsm->global_lru_pool;
3948 clib_dlist_init (tsm->global_lru_pool, tsm->global_lru_head_index);
3950 if (sm->endpoint_dependent)
3952 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3953 sm->translation_buckets,
3954 sm->translation_memory_size);
3955 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3956 format_ed_session_kvp);
3957 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3958 sm->translation_buckets,
3959 sm->translation_memory_size);
3960 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3961 format_ed_session_kvp);
3965 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3966 sm->translation_buckets,
3967 sm->translation_memory_size);
3968 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp);
3969 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3970 sm->translation_buckets,
3971 sm->translation_memory_size);
3972 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp);
3975 // TODO: resolve static mappings (put only to !ED)
3976 pool_alloc (tsm->list_pool, sm->max_translations);
3977 clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets,
3978 sm->user_memory_size);
3979 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
3983 nat44_db_free (snat_main_per_thread_data_t * tsm)
3985 snat_main_t *sm = &snat_main;
3987 pool_free (tsm->sessions);
3988 pool_free (tsm->global_lru_pool);
3990 if (sm->endpoint_dependent)
3992 clib_bihash_free_16_8 (&tsm->in2out_ed);
3993 clib_bihash_free_16_8 (&tsm->out2in_ed);
3997 clib_bihash_free_8_8 (&tsm->in2out);
3998 clib_bihash_free_8_8 (&tsm->out2in);
4001 // TODO: resolve static mappings (put only to !ED)
4002 pool_free (tsm->users);
4003 pool_free (tsm->list_pool);
4004 clib_bihash_free_8_8 (&tsm->user_hash);
4007 static clib_error_t *
4008 snat_config (vlib_main_t * vm, unformat_input_t * input)
4010 snat_main_t *sm = &snat_main;
4011 nat66_main_t *nm = &nat66_main;
4012 //dslite_main_t *dm = &dslite_main;
4013 snat_main_per_thread_data_t *tsm;
4015 u32 static_mapping_buckets = 1024;
4016 uword static_mapping_memory_size = 64 << 20;
4018 u32 nat64_bib_buckets = 1024;
4019 u32 nat64_bib_memory_size = 128 << 20;
4021 u32 nat64_st_buckets = 2048;
4022 uword nat64_st_memory_size = 256 << 20;
4024 u32 user_buckets = 128;
4025 uword user_memory_size = 64 << 20;
4026 u32 translation_buckets = 1024;
4027 uword translation_memory_size = 128 << 20;
4029 u32 max_translations_per_user = ~0;
4031 u32 outside_vrf_id = 0;
4032 u32 outside_ip6_vrf_id = 0;
4033 u32 inside_vrf_id = 0;
4034 u8 static_mapping_only = 0;
4035 u8 static_mapping_connection_tracking = 0;
4037 // configurable timeouts
4038 u32 udp_timeout = SNAT_UDP_TIMEOUT;
4039 u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
4040 u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
4041 u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
4043 sm->deterministic = 0;
4045 sm->endpoint_dependent = 0;
4047 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4050 (input, "translation hash buckets %d", &translation_buckets))
4052 else if (unformat (input, "udp timeout %d", &udp_timeout))
4054 else if (unformat (input, "icmp timeout %d", &icmp_timeout))
4056 else if (unformat (input, "tcp transitory timeout %d",
4057 &tcp_transitory_timeout));
4058 else if (unformat (input, "tcp established timeout %d",
4059 &tcp_established_timeout));
4060 else if (unformat (input, "translation hash memory %d",
4061 &translation_memory_size));
4062 else if (unformat (input, "user hash buckets %d", &user_buckets))
4064 else if (unformat (input, "user hash memory %d", &user_memory_size))
4066 else if (unformat (input, "max translations per user %d",
4067 &max_translations_per_user))
4069 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
4071 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
4073 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
4075 else if (unformat (input, "static mapping only"))
4077 static_mapping_only = 1;
4078 if (unformat (input, "connection tracking"))
4079 static_mapping_connection_tracking = 1;
4081 else if (unformat (input, "deterministic"))
4082 sm->deterministic = 1;
4083 else if (unformat (input, "nat64 bib hash buckets %d",
4084 &nat64_bib_buckets))
4086 else if (unformat (input, "nat64 bib hash memory %d",
4087 &nat64_bib_memory_size))
4090 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
4092 else if (unformat (input, "nat64 st hash memory %d",
4093 &nat64_st_memory_size))
4095 else if (unformat (input, "out2in dpo"))
4097 //else if (unformat (input, "dslite ce"))
4098 //dslite_set_ce (dm, 1);
4099 else if (unformat (input, "endpoint-dependent"))
4100 sm->endpoint_dependent = 1;
4102 return clib_error_return (0, "unknown input '%U'",
4103 format_unformat_error, input);
4106 if (sm->deterministic && sm->endpoint_dependent)
4107 return clib_error_return (0,
4108 "deterministic and endpoint-dependent modes are mutually exclusive");
4110 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
4111 return clib_error_return (0,
4112 "static mapping only mode available only for simple nat");
4114 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
4115 return clib_error_return (0,
4116 "out2in dpo mode available only for simple nat");
4118 /* optionally configurable timeouts for testing purposes */
4119 sm->udp_timeout = udp_timeout;
4120 sm->tcp_transitory_timeout = tcp_transitory_timeout;
4121 sm->tcp_established_timeout = tcp_established_timeout;
4122 sm->icmp_timeout = icmp_timeout;
4124 sm->user_buckets = user_buckets;
4125 sm->user_memory_size = user_memory_size;
4127 sm->translation_buckets = translation_buckets;
4128 sm->translation_memory_size = translation_memory_size;
4129 /* do not exceed load factor 10 */
4130 sm->max_translations = 10 * translation_buckets;
4131 vec_add1 (sm->max_translations_per_fib, sm->max_translations);
4133 sm->max_translations_per_user = max_translations_per_user == ~0 ?
4134 sm->max_translations : max_translations_per_user;
4136 sm->outside_vrf_id = outside_vrf_id;
4137 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4140 nm->outside_vrf_id = outside_ip6_vrf_id;
4141 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
4144 sm->inside_vrf_id = inside_vrf_id;
4145 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4148 sm->static_mapping_only = static_mapping_only;
4149 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
4151 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
4152 nat64_st_memory_size);
4154 if (sm->deterministic)
4156 sm->in2out_node_index = snat_det_in2out_node.index;
4157 sm->in2out_output_node_index = ~0;
4158 sm->out2in_node_index = snat_det_out2in_node.index;
4159 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
4160 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
4164 if (sm->endpoint_dependent)
4166 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
4167 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
4169 sm->handoff_out2in_index = nat_pre_out2in_node.index;
4170 sm->handoff_in2out_index = nat_pre_in2out_node.index;
4171 sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
4173 sm->in2out_node_index = nat44_ed_in2out_node.index;
4174 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
4175 sm->out2in_node_index = nat44_ed_out2in_node.index;
4177 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
4178 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
4179 nat_affinity_init (vm);
4180 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
4185 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
4186 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
4188 sm->handoff_out2in_index = snat_out2in_node.index;
4189 sm->handoff_in2out_index = snat_in2out_node.index;
4190 sm->handoff_in2out_output_index = snat_in2out_output_node.index;
4192 sm->in2out_node_index = snat_in2out_node.index;
4193 sm->in2out_output_node_index = snat_in2out_output_node.index;
4194 sm->out2in_node_index = snat_out2in_node.index;
4195 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
4196 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
4197 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
4199 if (!static_mapping_only ||
4200 (static_mapping_only && static_mapping_connection_tracking))
4203 vec_foreach (tsm, sm->per_thread_data)
4205 nat44_db_init (tsm);
4211 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
4212 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
4214 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
4215 "static_mapping_by_local", static_mapping_buckets,
4216 static_mapping_memory_size);
4217 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
4218 format_static_mapping_kvp);
4220 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
4221 "static_mapping_by_external",
4222 static_mapping_buckets,
4223 static_mapping_memory_size);
4224 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
4225 format_static_mapping_kvp);
4231 VLIB_CONFIG_FUNCTION (snat_config, "nat");
4234 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
4237 ip4_address_t * address,
4239 u32 if_address_index, u32 is_delete)
4241 snat_main_t *sm = &snat_main;
4242 snat_static_map_resolve_t *rp;
4243 snat_static_mapping_t *m;
4244 snat_session_key_t m_key;
4245 clib_bihash_kv_8_8_t kv, value;
4247 ip4_address_t l_addr;
4249 for (i = 0; i < vec_len (sm->to_resolve); i++)
4251 rp = sm->to_resolve + i;
4252 if (rp->addr_only == 0)
4254 if (rp->sw_if_index == sw_if_index)
4261 m_key.addr.as_u32 = address->as_u32;
4262 m_key.port = rp->addr_only ? 0 : rp->e_port;
4263 m_key.protocol = rp->addr_only ? 0 : rp->proto;
4264 m_key.fib_index = sm->outside_fib_index;
4265 kv.key = m_key.as_u64;
4266 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4269 m = pool_elt_at_index (sm->static_mappings, value.value);
4273 /* Don't trip over lease renewal, static config */
4283 /* Indetity mapping? */
4284 if (rp->l_addr.as_u32 == 0)
4285 l_addr.as_u32 = address[0].as_u32;
4287 l_addr.as_u32 = rp->l_addr.as_u32;
4288 /* Add the static mapping */
4289 rv = snat_add_static_mapping (l_addr,
4294 rp->addr_only, ~0 /* sw_if_index */ ,
4295 rp->proto, !is_delete, rp->twice_nat,
4296 rp->out2in_only, rp->tag, rp->identity_nat);
4298 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4302 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4305 ip4_address_t * address,
4307 u32 if_address_index, u32 is_delete)
4309 snat_main_t *sm = &snat_main;
4310 snat_static_map_resolve_t *rp;
4311 ip4_address_t l_addr;
4315 snat_address_t *addresses = sm->addresses;
4317 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4319 if (sw_if_index == sm->auto_add_sw_if_indices[i])
4323 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4326 addresses = sm->twice_nat_addresses;
4327 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4336 /* Don't trip over lease renewal, static config */
4337 for (j = 0; j < vec_len (addresses); j++)
4338 if (addresses[j].addr.as_u32 == address->as_u32)
4341 (void) snat_add_address (sm, address, ~0, twice_nat);
4342 /* Scan static map resolution vector */
4343 for (j = 0; j < vec_len (sm->to_resolve); j++)
4345 rp = sm->to_resolve + j;
4348 /* On this interface? */
4349 if (rp->sw_if_index == sw_if_index)
4351 /* Indetity mapping? */
4352 if (rp->l_addr.as_u32 == 0)
4353 l_addr.as_u32 = address[0].as_u32;
4355 l_addr.as_u32 = rp->l_addr.as_u32;
4356 /* Add the static mapping */
4357 rv = snat_add_static_mapping (l_addr,
4363 ~0 /* sw_if_index */ ,
4365 rp->is_add, rp->twice_nat,
4366 rp->out2in_only, rp->tag,
4369 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4377 (void) snat_del_address (sm, address[0], 1, twice_nat);
4384 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4387 ip4_main_t *ip4_main = sm->ip4_main;
4388 ip4_address_t *first_int_addr;
4389 snat_static_map_resolve_t *rp;
4390 u32 *indices_to_delete = 0;
4392 u32 *auto_add_sw_if_indices =
4394 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4396 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4399 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4401 if (auto_add_sw_if_indices[i] == sw_if_index)
4405 /* if have address remove it */
4407 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4410 for (j = 0; j < vec_len (sm->to_resolve); j++)
4412 rp = sm->to_resolve + j;
4413 if (rp->sw_if_index == sw_if_index)
4414 vec_add1 (indices_to_delete, j);
4416 if (vec_len (indices_to_delete))
4418 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4419 vec_del1 (sm->to_resolve, j);
4420 vec_free (indices_to_delete);
4424 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4426 vec_del1 (sm->auto_add_sw_if_indices, i);
4429 return VNET_API_ERROR_VALUE_EXIST;
4436 return VNET_API_ERROR_NO_SUCH_ENTRY;
4438 /* add to the auto-address list */
4440 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4442 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4444 /* If the address is already bound - or static - add it now */
4446 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4452 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4453 snat_protocol_t proto, u32 vrf_id, int is_in)
4455 snat_main_per_thread_data_t *tsm;
4456 clib_bihash_kv_8_8_t kv, value;
4458 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4459 snat_session_key_t key;
4461 clib_bihash_8_8_t *t;
4463 if (sm->endpoint_dependent)
4464 return VNET_API_ERROR_UNSUPPORTED;
4466 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4467 if (sm->num_workers > 1)
4469 vec_elt_at_index (sm->per_thread_data,
4470 sm->worker_in2out_cb (&ip, fib_index, 0));
4472 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4474 key.addr.as_u32 = addr->as_u32;
4475 key.port = clib_host_to_net_u16 (port);
4476 key.protocol = proto;
4477 key.fib_index = fib_index;
4478 kv.key = key.as_u64;
4479 t = is_in ? &tsm->in2out : &tsm->out2in;
4480 if (!clib_bihash_search_8_8 (t, &kv, &value))
4482 if (pool_is_free_index (tsm->sessions, value.value))
4483 return VNET_API_ERROR_UNSPECIFIED;
4485 s = pool_elt_at_index (tsm->sessions, value.value);
4486 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4487 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4491 return VNET_API_ERROR_NO_SUCH_ENTRY;
4495 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4496 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4497 u32 vrf_id, int is_in)
4500 clib_bihash_16_8_t *t;
4501 clib_bihash_kv_16_8_t kv, value;
4502 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4504 snat_main_per_thread_data_t *tsm;
4506 if (!sm->endpoint_dependent)
4507 return VNET_API_ERROR_FEATURE_DISABLED;
4509 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4510 if (sm->num_workers > 1)
4512 vec_elt_at_index (sm->per_thread_data,
4513 sm->worker_in2out_cb (&ip, fib_index, 0));
4515 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4517 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4518 make_ed_kv (addr, eh_addr, proto, fib_index, clib_host_to_net_u16 (port),
4519 clib_host_to_net_u16 (eh_port), ~0ULL, &kv);
4520 if (clib_bihash_search_16_8 (t, &kv, &value))
4522 return VNET_API_ERROR_NO_SUCH_ENTRY;
4525 if (pool_is_free_index (tsm->sessions, value.value))
4526 return VNET_API_ERROR_UNSPECIFIED;
4527 s = pool_elt_at_index (tsm->sessions, value.value);
4528 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4529 nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
4534 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4536 snat_main_t *sm = &snat_main;
4538 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4539 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4541 sm->psid_offset = psid_offset;
4542 sm->psid_length = psid_length;
4546 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4548 snat_main_t *sm = &snat_main;
4550 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4551 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4552 sm->start_port = start_port;
4553 sm->end_port = end_port;
4557 nat_set_alloc_addr_and_port_default (void)
4559 snat_main_t *sm = &snat_main;
4561 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4562 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4565 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4566 vlib_node_runtime_t * node,
4567 vlib_frame_t * frame)
4573 VLIB_REGISTER_NODE (nat_default_node) = {
4574 .name = "nat-default",
4575 .vector_size = sizeof (u32),
4577 .type = VLIB_NODE_TYPE_INTERNAL,
4579 .n_next_nodes = NAT_N_NEXT,
4581 [NAT_NEXT_DROP] = "error-drop",
4582 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4583 [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4584 [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4585 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4586 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4587 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4588 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4589 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4595 * fd.io coding-style-patch-verification: ON
4598 * eval: (c-set-style "gnu")