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;
202 nat_ed_ses_key_t ed_key;
203 clib_bihash_kv_16_8_t ed_kv;
204 snat_main_per_thread_data_t *tsm =
205 vec_elt_at_index (sm->per_thread_data, thread_index);
207 if (is_fwd_bypass_session (s))
209 if (snat_is_unk_proto_session (s))
211 ed_key.proto = s->in2out.port;
217 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
218 ed_key.l_port = s->in2out.port;
219 ed_key.r_port = s->ext_host_port;
221 ed_key.l_addr = s->in2out.addr;
222 ed_key.r_addr = s->ext_host_addr;
223 ed_key.fib_index = 0;
224 ed_kv.key[0] = ed_key.as_u64[0];
225 ed_kv.key[1] = ed_key.as_u64[1];
226 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
227 nat_elog_warn ("in2out_ed key del failed");
231 /* session lookup tables */
232 if (is_ed_session (s))
234 if (is_affinity_sessions (s))
235 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
236 s->in2out.protocol, s->out2in.port);
237 ed_key.l_addr = s->out2in.addr;
238 ed_key.r_addr = s->ext_host_addr;
239 ed_key.fib_index = s->out2in.fib_index;
240 if (snat_is_unk_proto_session (s))
242 ed_key.proto = s->in2out.port;
248 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
249 ed_key.l_port = s->out2in.port;
250 ed_key.r_port = s->ext_host_port;
252 ed_kv.key[0] = ed_key.as_u64[0];
253 ed_kv.key[1] = ed_key.as_u64[1];
254 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
255 nat_elog_warn ("out2in_ed key del failed");
256 ed_key.l_addr = s->in2out.addr;
257 ed_key.fib_index = s->in2out.fib_index;
258 if (!snat_is_unk_proto_session (s))
259 ed_key.l_port = s->in2out.port;
260 if (is_twice_nat_session (s))
262 ed_key.r_addr = s->ext_host_nat_addr;
263 ed_key.r_port = s->ext_host_nat_port;
265 ed_kv.key[0] = ed_key.as_u64[0];
266 ed_kv.key[1] = ed_key.as_u64[1];
267 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
268 nat_elog_warn ("in2out_ed key del failed");
271 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
272 &s->in2out.addr, s->in2out.port,
273 &s->ext_host_nat_addr, s->ext_host_nat_port,
274 &s->out2in.addr, s->out2in.port,
275 &s->ext_host_addr, s->ext_host_port,
276 s->in2out.protocol, is_twice_nat_session (s));
280 kv.key = s->in2out.as_u64;
281 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
282 nat_elog_warn ("in2out key del failed");
283 kv.key = s->out2in.as_u64;
284 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
285 nat_elog_warn ("out2in key del failed");
288 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
289 &s->in2out.addr, s->in2out.port,
290 &s->out2in.addr, s->out2in.port,
294 if (snat_is_unk_proto_session (s))
300 snat_ipfix_logging_nat44_ses_delete (thread_index,
301 s->in2out.addr.as_u32,
302 s->out2in.addr.as_u32,
306 s->in2out.fib_index);
308 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
309 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
313 /* Twice NAT address and port for external host */
314 if (is_twice_nat_session (s))
316 key.protocol = s->in2out.protocol;
317 key.port = s->ext_host_nat_port;
318 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
319 snat_free_outside_address_and_port (sm->twice_nat_addresses,
323 if (snat_is_session_static (s))
326 ed_bihash_kv_t bihash_key;
327 clib_memset (&bihash_key, 0, sizeof (bihash_key));
328 bihash_key.k.dst_address = s->ext_host_addr.as_u32;
329 bihash_key.k.dst_port = s->ext_host_port;
330 bihash_key.k.src_address = s->out2in.addr.as_u32;
331 bihash_key.k.src_port = s->out2in.port;
332 bihash_key.k.protocol = s->out2in.protocol;
333 clib_bihash_add_del_16_8 (&sm->ed_ext_ports, &bihash_key.kv,
336 snat_free_outside_address_and_port (sm->addresses, thread_index,
341 nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
342 u32 thread_index, u8 is_ha)
344 snat_session_key_t key;
345 nat_ed_ses_key_t ed_key;
346 clib_bihash_kv_16_8_t ed_kv;
347 snat_main_per_thread_data_t *tsm =
348 vec_elt_at_index (sm->per_thread_data, thread_index);
350 if (is_fwd_bypass_session (s))
352 if (snat_is_unk_proto_session (s))
354 ed_key.proto = s->in2out.port;
360 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
361 ed_key.l_port = s->in2out.port;
362 ed_key.r_port = s->ext_host_port;
365 ed_key.l_addr = s->in2out.addr;
366 ed_key.r_addr = s->ext_host_addr;
367 ed_key.fib_index = 0;
368 ed_kv.key[0] = ed_key.as_u64[0];
369 ed_kv.key[1] = ed_key.as_u64[1];
372 (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
373 nat_elog_warn ("in2out_ed key del failed");
377 /* session lookup tables */
378 if (is_affinity_sessions (s))
379 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
380 s->in2out.protocol, s->out2in.port);
381 ed_key.l_addr = s->out2in.addr;
382 ed_key.r_addr = s->ext_host_addr;
383 ed_key.fib_index = s->out2in.fib_index;
384 if (snat_is_unk_proto_session (s))
386 ed_key.proto = s->in2out.port;
392 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
393 ed_key.l_port = s->out2in.port;
394 ed_key.r_port = s->ext_host_port;
396 ed_kv.key[0] = ed_key.as_u64[0];
397 ed_kv.key[1] = ed_key.as_u64[1];
399 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
400 nat_elog_warn ("out2in_ed key del failed");
402 ed_key.l_addr = s->in2out.addr;
403 ed_key.fib_index = s->in2out.fib_index;
405 if (!snat_is_unk_proto_session (s))
406 ed_key.l_port = s->in2out.port;
408 if (is_twice_nat_session (s))
410 ed_key.r_addr = s->ext_host_nat_addr;
411 ed_key.r_port = s->ext_host_nat_port;
414 ed_kv.key[0] = ed_key.as_u64[0];
415 ed_kv.key[1] = ed_key.as_u64[1];
417 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
418 nat_elog_warn ("in2out_ed key del failed");
422 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
423 &s->in2out.addr, s->in2out.port,
424 &s->ext_host_nat_addr, s->ext_host_nat_port,
425 &s->out2in.addr, s->out2in.port,
426 &s->ext_host_addr, s->ext_host_port,
427 s->in2out.protocol, is_twice_nat_session (s));
430 if (snat_is_unk_proto_session (s))
436 snat_ipfix_logging_nat44_ses_delete (thread_index,
437 s->in2out.addr.as_u32,
438 s->out2in.addr.as_u32,
442 s->in2out.fib_index);
443 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
444 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
448 /* Twice NAT address and port for external host */
449 if (is_twice_nat_session (s))
451 key.protocol = s->in2out.protocol;
452 key.port = s->ext_host_nat_port;
453 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
454 snat_free_outside_address_and_port (sm->twice_nat_addresses,
458 if (snat_is_session_static (s))
461 ed_bihash_kv_t bihash_key;
462 clib_memset (&bihash_key, 0, sizeof (bihash_key));
463 bihash_key.k.dst_address = s->ext_host_addr.as_u32;
464 bihash_key.k.dst_port = s->ext_host_port;
465 bihash_key.k.src_address = s->out2in.addr.as_u32;
466 bihash_key.k.src_port = s->out2in.port;
467 bihash_key.k.protocol = s->out2in.protocol;
468 clib_bihash_add_del_16_8 (&sm->ed_ext_ports, &bihash_key.kv,
471 // should be called for every dynamic session
472 snat_free_outside_address_and_port (sm->addresses, thread_index,
478 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
482 snat_user_key_t user_key;
483 clib_bihash_kv_8_8_t kv, value;
484 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
485 dlist_elt_t *per_user_list_head_elt;
487 user_key.addr.as_u32 = addr->as_u32;
488 user_key.fib_index = fib_index;
489 kv.key = user_key.as_u64;
491 /* Ever heard of the "user" = src ip4 address before? */
492 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
494 /* no, make a new one */
495 pool_get (tsm->users, u);
496 clib_memset (u, 0, sizeof (*u));
498 u->min_session_timeout = 0;
500 u->addr.as_u32 = addr->as_u32;
501 u->fib_index = fib_index;
503 pool_get (tsm->list_pool, per_user_list_head_elt);
505 u->sessions_per_user_list_head_index = per_user_list_head_elt -
508 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
510 kv.value = u - tsm->users;
513 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
515 nat_elog_warn ("user_hash key add failed");
516 nat44_delete_user_with_no_session (sm, u, thread_index);
520 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
521 pool_elts (tsm->users));
525 u = pool_elt_at_index (tsm->users, value.value);
532 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
533 u32 thread_index, f64 now)
536 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
537 u32 oldest_per_user_translation_list_index, session_index;
538 dlist_elt_t *oldest_per_user_translation_list_elt;
539 dlist_elt_t *per_user_translation_list_elt;
541 /* Over quota? Recycle the least recently used translation */
542 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
544 oldest_per_user_translation_list_index =
545 clib_dlist_remove_head (tsm->list_pool,
546 u->sessions_per_user_list_head_index);
548 ASSERT (oldest_per_user_translation_list_index != ~0);
550 /* Add it back to the end of the LRU list */
551 clib_dlist_addtail (tsm->list_pool,
552 u->sessions_per_user_list_head_index,
553 oldest_per_user_translation_list_index);
554 /* Get the list element */
555 oldest_per_user_translation_list_elt =
556 pool_elt_at_index (tsm->list_pool,
557 oldest_per_user_translation_list_index);
559 /* Get the session index from the list element */
560 session_index = oldest_per_user_translation_list_elt->value;
562 /* Get the session */
563 s = pool_elt_at_index (tsm->sessions, session_index);
564 nat_free_session_data (sm, s, thread_index, 0);
565 if (snat_is_session_static (s))
566 u->nstaticsessions--;
573 s->ext_host_addr.as_u32 = 0;
574 s->ext_host_port = 0;
575 s->ext_host_nat_addr.as_u32 = 0;
576 s->ext_host_nat_port = 0;
580 pool_get (tsm->sessions, s);
581 clib_memset (s, 0, sizeof (*s));
583 /* Create list elts */
584 pool_get (tsm->list_pool, per_user_translation_list_elt);
585 clib_dlist_init (tsm->list_pool,
586 per_user_translation_list_elt - tsm->list_pool);
588 per_user_translation_list_elt->value = s - tsm->sessions;
589 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
590 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
592 clib_dlist_addtail (tsm->list_pool,
593 s->per_user_list_head_index,
594 per_user_translation_list_elt - tsm->list_pool);
596 s->user_index = u - tsm->users;
597 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
598 pool_elts (tsm->sessions));
601 s->ha_last_refreshed = now;
607 nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
611 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
613 dlist_elt_t *oldest_elt;
614 u64 sess_timeout_time;
618 if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
623 ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user))
625 if (nat44_max_translations_per_user_cleanup (u, thread_index, now))
628 nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
629 clib_net_to_host_u32 (u->addr.as_u32));
630 snat_ipfix_logging_max_entries_per_user (thread_index,
631 sm->max_translations_per_user,
637 clib_dlist_remove_head (tsm->list_pool,
638 u->sessions_per_user_list_head_index);
639 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
640 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
642 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
643 if (now >= sess_timeout_time ||
644 (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
647 clib_dlist_addtail (tsm->list_pool,
648 u->sessions_per_user_list_head_index, oldest_index);
649 s = nat44_session_reuse_old (sm, u, s, thread_index, now);
654 clib_dlist_addhead (tsm->list_pool,
655 u->sessions_per_user_list_head_index, oldest_index);
657 s = nat44_session_alloc_new (tsm, u, now);
658 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
659 pool_elts (tsm->sessions));
665 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
668 fib_prefix_t prefix = {
670 .fp_proto = FIB_PROTOCOL_IP4,
672 .ip4.as_u32 = addr->as_u32,
675 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
678 fib_table_entry_update_one_path (fib_index,
681 (FIB_ENTRY_FLAG_CONNECTED |
682 FIB_ENTRY_FLAG_LOCAL |
683 FIB_ENTRY_FLAG_EXCLUSIVE),
687 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
689 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
693 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
698 vlib_thread_main_t *tm = vlib_get_thread_main ();
700 if (twice_nat && !sm->endpoint_dependent)
701 return VNET_API_ERROR_FEATURE_DISABLED;
703 /* Check if address already exists */
705 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
707 if (ap->addr.as_u32 == addr->as_u32)
708 return VNET_API_ERROR_VALUE_EXIST;
713 vec_add2 (sm->twice_nat_addresses, ap, 1);
715 vec_add2 (sm->addresses, ap, 1);
720 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
724 #define _(N, i, n, s) \
725 clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
726 ap->busy_##n##_ports = 0; \
727 ap->busy_##n##_ports_per_thread = 0;\
728 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
729 foreach_snat_protocol
734 /* Add external address to FIB */
736 pool_foreach (i, sm->interfaces,
738 if (nat_interface_is_inside(i) || sm->out2in_dpo)
741 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
744 pool_foreach (i, sm->output_feature_interfaces,
746 if (nat_interface_is_inside(i) || sm->out2in_dpo)
749 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
758 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
760 snat_static_mapping_t *m;
762 pool_foreach (m, sm->static_mappings,
764 if (is_addr_only_static_mapping (m) ||
765 is_out2in_only_static_mapping (m) ||
766 is_identity_static_mapping (m))
768 if (m->external_addr.as_u32 == addr.as_u32)
777 snat_add_static_mapping_when_resolved (snat_main_t * sm,
778 ip4_address_t l_addr,
783 snat_protocol_t proto,
784 int addr_only, int is_add, u8 * tag,
785 int twice_nat, int out2in_only,
788 snat_static_map_resolve_t *rp;
790 vec_add2 (sm->to_resolve, rp, 1);
791 rp->l_addr.as_u32 = l_addr.as_u32;
793 rp->sw_if_index = sw_if_index;
797 rp->addr_only = addr_only;
799 rp->twice_nat = twice_nat;
800 rp->out2in_only = out2in_only;
801 rp->identity_nat = identity_nat;
802 rp->tag = vec_dup (tag);
806 get_thread_idx_by_port (u16 e_port)
808 snat_main_t *sm = &snat_main;
809 u32 thread_idx = sm->num_workers;
810 if (sm->num_workers > 1)
813 sm->first_worker_index +
814 sm->workers[(e_port - 1024) / sm->port_per_thread];
820 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
821 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
822 u32 sw_if_index, snat_protocol_t proto, int is_add,
823 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
826 snat_main_t *sm = &snat_main;
827 snat_static_mapping_t *m;
828 snat_session_key_t m_key;
829 clib_bihash_kv_8_8_t kv, value;
830 snat_address_t *a = 0;
832 snat_interface_t *interface;
834 snat_main_per_thread_data_t *tsm;
835 snat_user_key_t u_key;
837 dlist_elt_t *head, *elt;
838 u32 elt_index, head_index;
842 snat_static_map_resolve_t *rp, *rp_match = 0;
843 nat44_lb_addr_port_t *local;
846 if (!sm->endpoint_dependent)
848 if (twice_nat || out2in_only)
849 return VNET_API_ERROR_FEATURE_DISABLED;
852 /* If the external address is a specific interface address */
853 if (sw_if_index != ~0)
855 ip4_address_t *first_int_addr;
857 for (i = 0; i < vec_len (sm->to_resolve); i++)
859 rp = sm->to_resolve + i;
860 if (rp->sw_if_index != sw_if_index ||
861 rp->l_addr.as_u32 != l_addr.as_u32 ||
862 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
867 if ((rp->l_port != l_port && rp->e_port != e_port)
868 || rp->proto != proto)
876 /* Might be already set... */
877 first_int_addr = ip4_interface_first_address
878 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
883 return VNET_API_ERROR_VALUE_EXIST;
885 snat_add_static_mapping_when_resolved
886 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
887 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
889 /* DHCP resolution required? */
890 if (first_int_addr == 0)
896 e_addr.as_u32 = first_int_addr->as_u32;
897 /* Identity mapping? */
898 if (l_addr.as_u32 == 0)
899 l_addr.as_u32 = e_addr.as_u32;
905 return VNET_API_ERROR_NO_SUCH_ENTRY;
907 vec_del1 (sm->to_resolve, i);
911 e_addr.as_u32 = first_int_addr->as_u32;
912 /* Identity mapping? */
913 if (l_addr.as_u32 == 0)
914 l_addr.as_u32 = e_addr.as_u32;
922 m_key.port = addr_only ? 0 : e_port;
923 m_key.protocol = addr_only ? 0 : proto;
925 kv.key = m_key.as_u64;
926 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
929 m = pool_elt_at_index (sm->static_mappings, value.value);
935 if (is_identity_static_mapping (m))
938 pool_foreach (local, m->locals,
940 if (local->vrf_id == vrf_id)
941 return VNET_API_ERROR_VALUE_EXIST;
944 pool_get (m->locals, local);
945 local->vrf_id = vrf_id;
947 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
949 m_key.addr = m->local_addr;
950 m_key.port = m->local_port;
951 m_key.protocol = m->proto;
952 m_key.fib_index = local->fib_index;
953 kv.key = m_key.as_u64;
954 kv.value = m - sm->static_mappings;
955 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
959 return VNET_API_ERROR_VALUE_EXIST;
962 if (twice_nat && addr_only)
963 return VNET_API_ERROR_UNSUPPORTED;
965 /* Convert VRF id to FIB index */
968 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
970 /* If not specified use inside VRF id from SNAT plugin startup config */
973 fib_index = sm->inside_fib_index;
974 vrf_id = sm->inside_vrf_id;
975 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
978 if (!(out2in_only || identity_nat))
981 m_key.port = addr_only ? 0 : l_port;
982 m_key.protocol = addr_only ? 0 : proto;
983 m_key.fib_index = fib_index;
984 kv.key = m_key.as_u64;
985 if (!clib_bihash_search_8_8
986 (&sm->static_mapping_by_local, &kv, &value))
987 return VNET_API_ERROR_VALUE_EXIST;
990 /* Find external address in allocated addresses and reserve port for
991 address and port pair mapping when dynamic translations enabled */
992 if (!(addr_only || sm->static_mapping_only || out2in_only))
994 for (i = 0; i < vec_len (sm->addresses); i++)
996 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
998 a = sm->addresses + i;
999 /* External port must be unused */
1002 #define _(N, j, n, s) \
1003 case SNAT_PROTOCOL_##N: \
1004 if (a->busy_##n##_port_refcounts[e_port]) \
1005 return VNET_API_ERROR_INVALID_VALUE; \
1006 ++a->busy_##n##_port_refcounts[e_port]; \
1007 if (e_port > 1024) \
1009 a->busy_##n##_ports++; \
1010 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1013 foreach_snat_protocol
1016 nat_elog_info ("unknown protocol");
1017 return VNET_API_ERROR_INVALID_VALUE_2;
1022 /* External address must be allocated */
1023 if (!a && (l_addr.as_u32 != e_addr.as_u32))
1025 if (sw_if_index != ~0)
1027 for (i = 0; i < vec_len (sm->to_resolve); i++)
1029 rp = sm->to_resolve + i;
1032 if (rp->sw_if_index != sw_if_index &&
1033 rp->l_addr.as_u32 != l_addr.as_u32 &&
1034 rp->vrf_id != vrf_id && rp->l_port != l_port &&
1035 rp->e_port != e_port && rp->proto != proto)
1038 vec_del1 (sm->to_resolve, i);
1042 return VNET_API_ERROR_NO_SUCH_ENTRY;
1046 pool_get (sm->static_mappings, m);
1047 clib_memset (m, 0, sizeof (*m));
1048 m->tag = vec_dup (tag);
1049 m->local_addr = l_addr;
1050 m->external_addr = e_addr;
1051 m->twice_nat = twice_nat;
1053 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1055 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
1058 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
1059 pool_get (m->locals, local);
1060 local->vrf_id = vrf_id;
1061 local->fib_index = fib_index;
1066 m->fib_index = fib_index;
1070 m->local_port = l_port;
1071 m->external_port = e_port;
1075 if (sm->num_workers > 1)
1078 .src_address = m->local_addr,
1080 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
1081 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1084 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1086 m_key.addr = m->local_addr;
1087 m_key.port = m->local_port;
1088 m_key.protocol = m->proto;
1089 m_key.fib_index = fib_index;
1090 kv.key = m_key.as_u64;
1091 kv.value = m - sm->static_mappings;
1093 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1095 m_key.addr = m->external_addr;
1096 m_key.port = m->external_port;
1097 m_key.fib_index = 0;
1098 kv.key = m_key.as_u64;
1099 kv.value = m - sm->static_mappings;
1100 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
1102 /* Delete dynamic sessions matching local address (+ local port) */
1103 if (!(sm->static_mapping_only))
1105 u_key.addr = m->local_addr;
1106 u_key.fib_index = m->fib_index;
1107 kv.key = u_key.as_u64;
1108 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1110 user_index = value.value;
1111 u = pool_elt_at_index (tsm->users, user_index);
1114 head_index = u->sessions_per_user_list_head_index;
1115 head = pool_elt_at_index (tsm->list_pool, head_index);
1116 elt_index = head->next;
1117 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1118 ses_index = elt->value;
1119 while (ses_index != ~0)
1121 s = pool_elt_at_index (tsm->sessions, ses_index);
1122 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1123 ses_index = elt->value;
1125 if (snat_is_session_static (s))
1129 && (clib_net_to_host_u16 (s->in2out.port) !=
1133 nat_free_session_data (sm, s,
1134 tsm - sm->per_thread_data, 0);
1135 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1137 if (!addr_only && !sm->endpoint_dependent)
1148 if (sw_if_index != ~0)
1151 return VNET_API_ERROR_NO_SUCH_ENTRY;
1157 vrf_id = sm->inside_vrf_id;
1160 pool_foreach (local, m->locals,
1162 if (local->vrf_id == vrf_id)
1163 find = local - m->locals;
1167 return VNET_API_ERROR_NO_SUCH_ENTRY;
1169 local = pool_elt_at_index (m->locals, find);
1170 fib_index = local->fib_index;
1171 pool_put (m->locals, local);
1174 fib_index = m->fib_index;
1176 /* Free external address port */
1177 if (!(addr_only || sm->static_mapping_only || out2in_only))
1179 for (i = 0; i < vec_len (sm->addresses); i++)
1181 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1183 a = sm->addresses + i;
1186 #define _(N, j, n, s) \
1187 case SNAT_PROTOCOL_##N: \
1188 --a->busy_##n##_port_refcounts[e_port]; \
1189 if (e_port > 1024) \
1191 a->busy_##n##_ports--; \
1192 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1195 foreach_snat_protocol
1198 nat_elog_info ("unknown protocol");
1199 return VNET_API_ERROR_INVALID_VALUE_2;
1206 if (sm->num_workers > 1)
1207 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1209 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1211 m_key.addr = m->local_addr;
1212 m_key.port = m->local_port;
1213 m_key.protocol = m->proto;
1214 m_key.fib_index = fib_index;
1215 kv.key = m_key.as_u64;
1217 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1219 /* Delete session(s) for static mapping if exist */
1220 if (!(sm->static_mapping_only) ||
1221 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1223 u_key.addr = m->local_addr;
1224 u_key.fib_index = fib_index;
1225 kv.key = u_key.as_u64;
1226 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1228 user_index = value.value;
1229 u = pool_elt_at_index (tsm->users, user_index);
1230 if (u->nstaticsessions)
1232 head_index = u->sessions_per_user_list_head_index;
1233 head = pool_elt_at_index (tsm->list_pool, head_index);
1234 elt_index = head->next;
1235 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1236 ses_index = elt->value;
1237 while (ses_index != ~0)
1239 s = pool_elt_at_index (tsm->sessions, ses_index);
1240 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1241 ses_index = elt->value;
1245 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1246 (clib_net_to_host_u16 (s->out2in.port) !=
1251 if (is_lb_session (s))
1254 if (!snat_is_session_static (s))
1257 nat_free_session_data (sm, s,
1258 tsm - sm->per_thread_data, 0);
1259 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1261 if (!addr_only && !sm->endpoint_dependent)
1268 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1269 if (pool_elts (m->locals))
1272 m_key.addr = m->external_addr;
1273 m_key.port = m->external_port;
1274 m_key.fib_index = 0;
1275 kv.key = m_key.as_u64;
1276 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1279 vec_free (m->workers);
1280 /* Delete static mapping from pool */
1281 pool_put (sm->static_mappings, m);
1284 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1287 /* Add/delete external address to FIB */
1289 pool_foreach (interface, sm->interfaces,
1291 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1294 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1297 pool_foreach (interface, sm->output_feature_interfaces,
1299 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1302 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1311 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1312 snat_protocol_t proto,
1313 nat44_lb_addr_port_t * locals, u8 is_add,
1314 twice_nat_type_t twice_nat, u8 out2in_only,
1315 u8 * tag, u32 affinity)
1317 snat_main_t *sm = &snat_main;
1318 snat_static_mapping_t *m;
1319 snat_session_key_t m_key;
1320 clib_bihash_kv_8_8_t kv, value;
1321 snat_address_t *a = 0;
1323 nat44_lb_addr_port_t *local;
1324 u32 elt_index, head_index, ses_index;
1325 snat_main_per_thread_data_t *tsm;
1326 snat_user_key_t u_key;
1329 dlist_elt_t *head, *elt;
1332 if (!sm->endpoint_dependent)
1333 return VNET_API_ERROR_FEATURE_DISABLED;
1335 m_key.addr = e_addr;
1336 m_key.port = e_port;
1337 m_key.protocol = proto;
1338 m_key.fib_index = 0;
1339 kv.key = m_key.as_u64;
1340 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1343 m = pool_elt_at_index (sm->static_mappings, value.value);
1348 return VNET_API_ERROR_VALUE_EXIST;
1350 if (vec_len (locals) < 2)
1351 return VNET_API_ERROR_INVALID_VALUE;
1353 /* Find external address in allocated addresses and reserve port for
1354 address and port pair mapping when dynamic translations enabled */
1355 if (!(sm->static_mapping_only || out2in_only))
1357 for (i = 0; i < vec_len (sm->addresses); i++)
1359 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1361 a = sm->addresses + i;
1362 /* External port must be unused */
1365 #define _(N, j, n, s) \
1366 case SNAT_PROTOCOL_##N: \
1367 if (a->busy_##n##_port_refcounts[e_port]) \
1368 return VNET_API_ERROR_INVALID_VALUE; \
1369 ++a->busy_##n##_port_refcounts[e_port]; \
1370 if (e_port > 1024) \
1372 a->busy_##n##_ports++; \
1373 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1376 foreach_snat_protocol
1379 nat_elog_info ("unknown protocol");
1380 return VNET_API_ERROR_INVALID_VALUE_2;
1385 /* External address must be allocated */
1387 return VNET_API_ERROR_NO_SUCH_ENTRY;
1390 pool_get (sm->static_mappings, m);
1391 clib_memset (m, 0, sizeof (*m));
1392 m->tag = vec_dup (tag);
1393 m->external_addr = e_addr;
1394 m->external_port = e_port;
1396 m->twice_nat = twice_nat;
1397 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1399 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1400 m->affinity = affinity;
1403 m->affinity_per_service_list_head_index =
1404 nat_affinity_get_per_service_list_head_index ();
1406 m->affinity_per_service_list_head_index = ~0;
1408 m_key.addr = m->external_addr;
1409 m_key.port = m->external_port;
1410 m_key.protocol = m->proto;
1411 m_key.fib_index = 0;
1412 kv.key = m_key.as_u64;
1413 kv.value = m - sm->static_mappings;
1414 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1416 nat_elog_err ("static_mapping_by_external key add failed");
1417 return VNET_API_ERROR_UNSPECIFIED;
1420 m_key.fib_index = m->fib_index;
1421 for (i = 0; i < vec_len (locals); i++)
1423 locals[i].fib_index =
1424 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1427 m_key.addr = locals[i].addr;
1428 m_key.fib_index = locals[i].fib_index;
1431 m_key.port = locals[i].port;
1432 kv.key = m_key.as_u64;
1433 kv.value = m - sm->static_mappings;
1434 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1436 locals[i].prefix = (i == 0) ? locals[i].probability :
1437 (locals[i - 1].prefix + locals[i].probability);
1438 pool_get (m->locals, local);
1440 if (sm->num_workers > 1)
1443 .src_address = locals[i].addr,
1446 clib_bitmap_set (bitmap,
1447 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1452 /* Assign workers */
1453 if (sm->num_workers > 1)
1456 clib_bitmap_foreach (i, bitmap,
1458 vec_add1(m->workers, i);
1466 return VNET_API_ERROR_NO_SUCH_ENTRY;
1468 if (!is_lb_static_mapping (m))
1469 return VNET_API_ERROR_INVALID_VALUE;
1471 /* Free external address port */
1472 if (!(sm->static_mapping_only || out2in_only))
1474 for (i = 0; i < vec_len (sm->addresses); i++)
1476 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1478 a = sm->addresses + i;
1481 #define _(N, j, n, s) \
1482 case SNAT_PROTOCOL_##N: \
1483 --a->busy_##n##_port_refcounts[e_port]; \
1484 if (e_port > 1024) \
1486 a->busy_##n##_ports--; \
1487 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1490 foreach_snat_protocol
1493 nat_elog_info ("unknown protocol");
1494 return VNET_API_ERROR_INVALID_VALUE_2;
1501 m_key.addr = m->external_addr;
1502 m_key.port = m->external_port;
1503 m_key.protocol = m->proto;
1504 m_key.fib_index = 0;
1505 kv.key = m_key.as_u64;
1506 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1508 nat_elog_err ("static_mapping_by_external key del failed");
1509 return VNET_API_ERROR_UNSPECIFIED;
1513 pool_foreach (local, m->locals,
1515 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1517 m_key.addr = local->addr;
1520 m_key.port = local->port;
1521 m_key.fib_index = local->fib_index;
1522 kv.key = m_key.as_u64;
1523 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1525 nat_elog_err ("static_mapping_by_local key del failed");
1526 return VNET_API_ERROR_UNSPECIFIED;
1530 if (sm->num_workers > 1)
1533 .src_address = local->addr,
1535 tsm = vec_elt_at_index (sm->per_thread_data,
1536 sm->worker_in2out_cb (&ip, m->fib_index, 0));
1539 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1541 /* Delete sessions */
1542 u_key.addr = local->addr;
1543 u_key.fib_index = local->fib_index;
1544 kv.key = u_key.as_u64;
1545 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1547 u = pool_elt_at_index (tsm->users, value.value);
1548 if (u->nstaticsessions)
1550 head_index = u->sessions_per_user_list_head_index;
1551 head = pool_elt_at_index (tsm->list_pool, head_index);
1552 elt_index = head->next;
1553 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1554 ses_index = elt->value;
1555 while (ses_index != ~0)
1557 s = pool_elt_at_index (tsm->sessions, ses_index);
1558 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1559 ses_index = elt->value;
1561 if (!(is_lb_session (s)))
1564 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1565 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1568 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1569 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1576 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1577 pool_free (m->locals);
1579 vec_free (m->workers);
1581 pool_put (sm->static_mappings, m);
1588 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1589 ip4_address_t l_addr, u16 l_port,
1590 snat_protocol_t proto, u32 vrf_id,
1591 u8 probability, u8 is_add)
1593 snat_main_t *sm = &snat_main;
1594 snat_static_mapping_t *m = 0;
1595 snat_session_key_t m_key;
1596 clib_bihash_kv_8_8_t kv, value;
1597 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1598 snat_main_per_thread_data_t *tsm;
1599 snat_user_key_t u_key;
1602 dlist_elt_t *head, *elt;
1603 u32 elt_index, head_index, ses_index, *locals = 0;
1607 if (!sm->endpoint_dependent)
1608 return VNET_API_ERROR_FEATURE_DISABLED;
1610 m_key.addr = e_addr;
1611 m_key.port = e_port;
1612 m_key.protocol = proto;
1613 m_key.fib_index = 0;
1614 kv.key = m_key.as_u64;
1615 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1616 m = pool_elt_at_index (sm->static_mappings, value.value);
1619 return VNET_API_ERROR_NO_SUCH_ENTRY;
1621 if (!is_lb_static_mapping (m))
1622 return VNET_API_ERROR_INVALID_VALUE;
1625 pool_foreach (local, m->locals,
1627 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1628 (local->vrf_id == vrf_id))
1630 match_local = local;
1639 return VNET_API_ERROR_VALUE_EXIST;
1641 pool_get (m->locals, local);
1642 clib_memset (local, 0, sizeof (*local));
1643 local->addr.as_u32 = l_addr.as_u32;
1644 local->port = l_port;
1645 local->probability = probability;
1646 local->vrf_id = vrf_id;
1648 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1651 if (!is_out2in_only_static_mapping (m))
1653 m_key.addr = l_addr;
1654 m_key.port = l_port;
1655 m_key.fib_index = local->fib_index;
1656 kv.key = m_key.as_u64;
1657 kv.value = m - sm->static_mappings;
1658 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1659 nat_elog_err ("static_mapping_by_local key add failed");
1665 return VNET_API_ERROR_NO_SUCH_ENTRY;
1667 if (pool_elts (m->locals) < 3)
1668 return VNET_API_ERROR_UNSPECIFIED;
1670 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1673 if (!is_out2in_only_static_mapping (m))
1675 m_key.addr = l_addr;
1676 m_key.port = l_port;
1677 m_key.fib_index = match_local->fib_index;
1678 kv.key = m_key.as_u64;
1679 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1680 nat_elog_err ("static_mapping_by_local key del failed");
1683 if (sm->num_workers > 1)
1686 .src_address = local->addr,
1688 tsm = vec_elt_at_index (sm->per_thread_data,
1689 sm->worker_in2out_cb (&ip, m->fib_index,
1693 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1695 /* Delete sessions */
1696 u_key.addr = match_local->addr;
1697 u_key.fib_index = match_local->fib_index;
1698 kv.key = u_key.as_u64;
1699 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1701 u = pool_elt_at_index (tsm->users, value.value);
1702 if (u->nstaticsessions)
1704 head_index = u->sessions_per_user_list_head_index;
1705 head = pool_elt_at_index (tsm->list_pool, head_index);
1706 elt_index = head->next;
1707 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1708 ses_index = elt->value;
1709 while (ses_index != ~0)
1711 s = pool_elt_at_index (tsm->sessions, ses_index);
1712 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1713 ses_index = elt->value;
1715 if (!(is_lb_session (s)))
1718 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1719 (clib_net_to_host_u16 (s->in2out.port) !=
1723 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1724 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1729 pool_put (m->locals, match_local);
1732 vec_free (m->workers);
1735 pool_foreach (local, m->locals,
1737 vec_add1 (locals, local - m->locals);
1738 if (sm->num_workers > 1)
1741 ip.src_address.as_u32 = local->addr.as_u32,
1742 bitmap = clib_bitmap_set (bitmap,
1743 sm->worker_in2out_cb (&ip, local->fib_index, 0),
1749 ASSERT (vec_len (locals) > 1);
1751 local = pool_elt_at_index (m->locals, locals[0]);
1752 local->prefix = local->probability;
1753 for (i = 1; i < vec_len (locals); i++)
1755 local = pool_elt_at_index (m->locals, locals[i]);
1756 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1757 local->prefix = local->probability + prev_local->prefix;
1760 /* Assign workers */
1761 if (sm->num_workers > 1)
1764 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1772 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1775 snat_address_t *a = 0;
1776 snat_session_t *ses;
1777 u32 *ses_to_be_removed = 0, *ses_index;
1778 snat_main_per_thread_data_t *tsm;
1779 snat_static_mapping_t *m;
1780 snat_interface_t *interface;
1782 snat_address_t *addresses =
1783 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1785 /* Find SNAT address */
1786 for (i = 0; i < vec_len (addresses); i++)
1788 if (addresses[i].addr.as_u32 == addr.as_u32)
1795 return VNET_API_ERROR_NO_SUCH_ENTRY;
1800 pool_foreach (m, sm->static_mappings,
1802 if (m->external_addr.as_u32 == addr.as_u32)
1803 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1804 m->local_port, m->external_port,
1805 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1806 m->proto, 0, m->twice_nat,
1807 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1813 /* Check if address is used in some static mapping */
1814 if (is_snat_address_used_in_static_mapping (sm, addr))
1816 nat_elog_notice ("address used in static mapping");
1817 return VNET_API_ERROR_UNSPECIFIED;
1821 if (a->fib_index != ~0)
1822 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1824 /* Delete sessions using address */
1825 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1828 vec_foreach (tsm, sm->per_thread_data)
1830 pool_foreach (ses, tsm->sessions, ({
1831 if (ses->out2in.addr.as_u32 == addr.as_u32)
1833 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1834 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1838 vec_foreach (ses_index, ses_to_be_removed)
1840 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1841 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1844 vec_free (ses_to_be_removed);
1849 #define _(N, i, n, s) \
1850 vec_free (a->busy_##n##_ports_per_thread);
1851 foreach_snat_protocol
1855 vec_del1 (sm->twice_nat_addresses, i);
1859 vec_del1 (sm->addresses, i);
1861 /* Delete external address from FIB */
1863 pool_foreach (interface, sm->interfaces,
1865 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1868 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1871 pool_foreach (interface, sm->output_feature_interfaces,
1873 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1876 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1885 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1887 snat_main_t *sm = &snat_main;
1888 snat_interface_t *i;
1889 const char *feature_name, *del_feature_name;
1891 snat_static_mapping_t *m;
1893 nat_outside_fib_t *outside_fib;
1894 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1897 if (sm->out2in_dpo && !is_inside)
1898 return VNET_API_ERROR_UNSUPPORTED;
1901 pool_foreach (i, sm->output_feature_interfaces,
1903 if (i->sw_if_index == sw_if_index)
1904 return VNET_API_ERROR_VALUE_EXIST;
1908 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1909 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1912 if (sm->num_workers > 1 && !sm->deterministic)
1914 is_inside ? "nat44-in2out-worker-handoff" :
1915 "nat44-out2in-worker-handoff";
1916 else if (sm->deterministic)
1917 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1918 else if (sm->endpoint_dependent)
1920 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1923 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1926 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1927 sm->fq_in2out_index =
1928 vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
1930 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1931 sm->fq_out2in_index =
1932 vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
1937 vec_foreach (outside_fib, sm->outside_fibs)
1939 if (outside_fib->fib_index == fib_index)
1943 outside_fib->refcount--;
1944 if (!outside_fib->refcount)
1945 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1948 outside_fib->refcount++;
1955 vec_add2 (sm->outside_fibs, outside_fib, 1);
1956 outside_fib->refcount = 1;
1957 outside_fib->fib_index = fib_index;
1962 pool_foreach (i, sm->interfaces,
1964 if (i->sw_if_index == sw_if_index)
1968 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1971 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1973 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1975 if (sm->num_workers > 1 && !sm->deterministic)
1977 del_feature_name = "nat44-handoff-classify";
1978 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1979 "nat44-out2in-worker-handoff";
1981 else if (sm->deterministic)
1983 del_feature_name = "nat44-det-classify";
1984 feature_name = !is_inside ? "nat44-det-in2out" :
1987 else if (sm->endpoint_dependent)
1989 del_feature_name = "nat44-ed-classify";
1990 feature_name = !is_inside ? "nat-pre-in2out" :
1995 del_feature_name = "nat44-classify";
1996 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1999 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2002 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2003 sw_if_index, 0, 0, 0);
2004 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2005 sw_if_index, 1, 0, 0);
2008 if (sm->endpoint_dependent)
2009 vnet_feature_enable_disable ("ip4-local",
2010 "nat44-ed-hairpinning",
2011 sw_if_index, 1, 0, 0);
2012 else if (!sm->deterministic)
2013 vnet_feature_enable_disable ("ip4-local",
2014 "nat44-hairpinning",
2015 sw_if_index, 1, 0, 0);
2020 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2023 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2024 sw_if_index, 0, 0, 0);
2025 pool_put (sm->interfaces, i);
2028 if (sm->endpoint_dependent)
2029 vnet_feature_enable_disable ("ip4-local",
2030 "nat44-ed-hairpinning",
2031 sw_if_index, 0, 0, 0);
2032 else if (!sm->deterministic)
2033 vnet_feature_enable_disable ("ip4-local",
2034 "nat44-hairpinning",
2035 sw_if_index, 0, 0, 0);
2041 if ((nat_interface_is_inside(i) && is_inside) ||
2042 (nat_interface_is_outside(i) && !is_inside))
2045 if (sm->num_workers > 1 && !sm->deterministic)
2047 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
2048 "nat44-out2in-worker-handoff";
2049 feature_name = "nat44-handoff-classify";
2051 else if (sm->deterministic)
2053 del_feature_name = !is_inside ? "nat44-det-in2out" :
2055 feature_name = "nat44-det-classify";
2057 else if (sm->endpoint_dependent)
2059 del_feature_name = !is_inside ? "nat-pre-in2out" :
2062 feature_name = "nat44-ed-classify";
2066 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
2067 feature_name = "nat44-classify";
2070 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2073 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2074 sw_if_index, 0, 0, 0);
2075 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2076 sw_if_index, 1, 0, 0);
2079 if (sm->endpoint_dependent)
2080 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2081 sw_if_index, 0, 0, 0);
2082 else if (!sm->deterministic)
2083 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2084 sw_if_index, 0, 0, 0);
2095 return VNET_API_ERROR_NO_SUCH_ENTRY;
2097 pool_get (sm->interfaces, i);
2098 i->sw_if_index = sw_if_index;
2100 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
2103 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2107 if (is_inside && !sm->out2in_dpo)
2109 if (sm->endpoint_dependent)
2110 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2111 sw_if_index, 1, 0, 0);
2112 else if (!sm->deterministic)
2113 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2114 sw_if_index, 1, 0, 0);
2120 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2124 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2126 /* Add/delete external addresses to FIB */
2129 vec_foreach (ap, sm->addresses)
2130 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2132 pool_foreach (m, sm->static_mappings,
2134 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2137 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2140 pool_foreach (dm, sm->det_maps,
2142 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2150 snat_interface_add_del_output_feature (u32 sw_if_index,
2151 u8 is_inside, int is_del)
2153 snat_main_t *sm = &snat_main;
2154 snat_interface_t *i;
2156 snat_static_mapping_t *m;
2157 nat_outside_fib_t *outside_fib;
2158 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2162 if (sm->deterministic ||
2163 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2164 return VNET_API_ERROR_UNSUPPORTED;
2167 pool_foreach (i, sm->interfaces,
2169 if (i->sw_if_index == sw_if_index)
2170 return VNET_API_ERROR_VALUE_EXIST;
2177 vec_foreach (outside_fib, sm->outside_fibs)
2179 if (outside_fib->fib_index == fib_index)
2183 outside_fib->refcount--;
2184 if (!outside_fib->refcount)
2185 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2188 outside_fib->refcount++;
2195 vec_add2 (sm->outside_fibs, outside_fib, 1);
2196 outside_fib->refcount = 1;
2197 outside_fib->fib_index = fib_index;
2204 if (sm->endpoint_dependent)
2207 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2211 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2215 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2216 sw_if_index, !is_del, 0, 0);
2217 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2218 sw_if_index, !is_del, 0, 0);
2223 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2227 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2231 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2232 sw_if_index, !is_del, 0, 0);
2233 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2234 sw_if_index, !is_del, 0, 0);
2239 if (sm->num_workers > 1)
2241 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2245 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2248 vnet_feature_enable_disable ("ip4-unicast",
2249 "nat44-out2in-worker-handoff",
2250 sw_if_index, !is_del, 0, 0);
2251 vnet_feature_enable_disable ("ip4-output",
2252 "nat44-in2out-output-worker-handoff",
2253 sw_if_index, !is_del, 0, 0);
2257 if (sm->endpoint_dependent)
2260 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2264 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2268 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2269 sw_if_index, !is_del, 0, 0);
2270 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2271 sw_if_index, !is_del, 0, 0);
2276 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2280 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2284 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2285 sw_if_index, !is_del, 0, 0);
2286 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2287 sw_if_index, !is_del, 0, 0);
2292 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2293 sm->fq_in2out_output_index =
2294 vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
2296 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2297 sm->fq_out2in_index =
2298 vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
2301 pool_foreach (i, sm->output_feature_interfaces,
2303 if (i->sw_if_index == sw_if_index)
2306 pool_put (sm->output_feature_interfaces, i);
2308 return VNET_API_ERROR_VALUE_EXIST;
2316 return VNET_API_ERROR_NO_SUCH_ENTRY;
2318 pool_get (sm->output_feature_interfaces, i);
2319 i->sw_if_index = sw_if_index;
2322 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2324 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2326 /* Add/delete external addresses to FIB */
2332 vec_foreach (ap, sm->addresses)
2333 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2335 pool_foreach (m, sm->static_mappings,
2337 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2340 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2348 snat_set_workers (uword * bitmap)
2350 snat_main_t *sm = &snat_main;
2353 if (sm->num_workers < 2)
2354 return VNET_API_ERROR_FEATURE_DISABLED;
2356 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2357 return VNET_API_ERROR_INVALID_WORKER;
2359 vec_free (sm->workers);
2361 clib_bitmap_foreach (i, bitmap,
2363 vec_add1(sm->workers, i);
2364 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2365 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2370 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2371 sm->num_snat_thread = _vec_len (sm->workers);
2377 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2380 snat_main_t *sm = &snat_main;
2381 nat_outside_fib_t *outside_fib;
2382 snat_interface_t *i;
2386 if (new_fib_index == old_fib_index)
2389 if (!vec_len (sm->outside_fibs))
2393 pool_foreach (i, sm->interfaces,
2395 if (i->sw_if_index == sw_if_index)
2397 if (!(nat_interface_is_outside (i)))
2403 pool_foreach (i, sm->output_feature_interfaces,
2405 if (i->sw_if_index == sw_if_index)
2407 if (!(nat_interface_is_outside (i)))
2417 vec_foreach (outside_fib, sm->outside_fibs)
2419 if (outside_fib->fib_index == old_fib_index)
2421 outside_fib->refcount--;
2422 if (!outside_fib->refcount)
2423 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2428 vec_foreach (outside_fib, sm->outside_fibs)
2430 if (outside_fib->fib_index == new_fib_index)
2432 outside_fib->refcount++;
2440 vec_add2 (sm->outside_fibs, outside_fib, 1);
2441 outside_fib->refcount = 1;
2442 outside_fib->fib_index = new_fib_index;
2447 snat_ip4_table_bind (ip4_main_t * im,
2449 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2451 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2455 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2458 ip4_address_t * address,
2460 u32 if_address_index, u32 is_delete);
2463 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2466 ip4_address_t * address,
2468 u32 if_address_index, u32 is_delete);
2471 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2474 snat_session_key_t * k,
2475 u16 port_per_thread, u32 snat_thread_index);
2477 static clib_error_t *
2478 snat_init (vlib_main_t * vm)
2480 snat_main_t *sm = &snat_main;
2481 clib_error_t *error = 0;
2482 ip4_main_t *im = &ip4_main;
2483 ip_lookup_main_t *lm = &im->lookup_main;
2485 vlib_thread_registration_t *tr;
2486 vlib_thread_main_t *tm = vlib_get_thread_main ();
2489 ip4_add_del_interface_address_callback_t cb4;
2493 sm->vnet_main = vnet_get_main ();
2495 sm->ip4_lookup_main = lm;
2496 sm->api_main = vlibapi_get_main ();
2497 sm->first_worker_index = 0;
2498 sm->num_workers = 0;
2499 sm->num_snat_thread = 1;
2501 sm->port_per_thread = 0xffff - 1024;
2502 sm->fq_in2out_index = ~0;
2503 sm->fq_in2out_output_index = ~0;
2504 sm->fq_out2in_index = ~0;
2506 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2507 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2508 sm->forwarding_enabled = 0;
2509 sm->log_class = vlib_log_register_class ("nat", 0);
2510 sm->log_level = SNAT_LOG_ERROR;
2511 sm->mss_clamping = 0;
2513 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2514 sm->error_node_index = node->index;
2516 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2517 sm->pre_in2out_node_index = node->index;
2518 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2519 sm->pre_out2in_node_index = node->index;
2521 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2522 sm->pre_in2out_node_index = node->index;
2524 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2525 sm->pre_out2in_node_index = node->index;
2527 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2528 sm->in2out_node_index = node->index;
2529 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2530 sm->in2out_output_node_index = node->index;
2531 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2532 sm->in2out_fast_node_index = node->index;
2533 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2534 sm->in2out_slowpath_node_index = node->index;
2535 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2536 sm->in2out_slowpath_output_node_index = node->index;
2538 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2539 sm->ed_in2out_node_index = node->index;
2540 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2541 sm->ed_in2out_slowpath_node_index = node->index;
2543 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2544 sm->out2in_node_index = node->index;
2545 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2546 sm->out2in_fast_node_index = node->index;
2548 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2549 sm->ed_out2in_node_index = node->index;
2550 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2551 sm->ed_out2in_slowpath_node_index = node->index;
2553 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2554 sm->det_in2out_node_index = node->index;
2555 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2556 sm->det_out2in_node_index = node->index;
2558 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2559 sm->hairpinning_node_index = node->index;
2560 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2561 sm->hairpin_dst_node_index = node->index;
2562 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2563 sm->hairpin_src_node_index = node->index;
2564 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2565 sm->ed_hairpinning_node_index = node->index;
2566 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2567 sm->ed_hairpin_dst_node_index = node->index;
2568 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2569 sm->ed_hairpin_src_node_index = node->index;
2571 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2574 tr = (vlib_thread_registration_t *) p[0];
2577 sm->num_workers = tr->count;
2578 sm->first_worker_index = tr->first_index;
2582 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2584 /* Use all available workers by default */
2585 if (sm->num_workers > 1)
2587 for (i = 0; i < sm->num_workers; i++)
2588 bitmap = clib_bitmap_set (bitmap, i, 1);
2589 snat_set_workers (bitmap);
2590 clib_bitmap_free (bitmap);
2594 sm->per_thread_data[0].snat_thread_index = 0;
2597 error = snat_api_init (vm, sm);
2601 /* Set up the interface address add/del callback */
2602 cb4.function = snat_ip4_add_del_interface_address_cb;
2603 cb4.function_opaque = 0;
2605 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2607 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2608 cb4.function_opaque = 0;
2610 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2612 nat_dpo_module_init ();
2615 sm->total_users.name = "total-users";
2616 sm->total_users.stat_segment_name = "/nat44/total-users";
2617 vlib_validate_simple_counter (&sm->total_users, 0);
2618 vlib_zero_simple_counter (&sm->total_users, 0);
2619 sm->total_sessions.name = "total-sessions";
2620 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2621 vlib_validate_simple_counter (&sm->total_sessions, 0);
2622 vlib_zero_simple_counter (&sm->total_sessions, 0);
2624 /* Init IPFIX logging */
2625 snat_ipfix_logging_init (vm);
2628 error = nat64_init (vm);
2634 ip4_table_bind_callback_t cbt4 = {
2635 .function = snat_ip4_table_bind,
2637 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2639 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2640 FIB_SOURCE_PRIORITY_HI,
2641 FIB_SOURCE_BH_SIMPLE);
2642 nat_fib_src_low = fib_source_allocate ("nat-low",
2643 FIB_SOURCE_PRIORITY_LOW,
2644 FIB_SOURCE_BH_SIMPLE);
2649 VLIB_INIT_FUNCTION (snat_init);
2652 snat_free_outside_address_and_port (snat_address_t * addresses,
2653 u32 thread_index, snat_session_key_t * k)
2657 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2659 for (address_index = 0; address_index < vec_len (addresses);
2662 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2666 ASSERT (address_index < vec_len (addresses));
2668 a = addresses + address_index;
2670 switch (k->protocol)
2672 #define _(N, i, n, s) \
2673 case SNAT_PROTOCOL_##N: \
2674 ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2675 --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2676 a->busy_##n##_ports--; \
2677 a->busy_##n##_ports_per_thread[thread_index]--; \
2679 foreach_snat_protocol
2682 nat_elog_info ("unknown protocol");
2688 nat_set_outside_address_and_port (snat_address_t * addresses,
2689 u32 thread_index, snat_session_key_t * k)
2691 snat_address_t *a = 0;
2693 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2695 for (address_index = 0; address_index < vec_len (addresses);
2698 if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2701 a = addresses + address_index;
2702 switch (k->protocol)
2704 #define _(N, j, n, s) \
2705 case SNAT_PROTOCOL_##N: \
2706 if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
2707 return VNET_API_ERROR_INSTANCE_IN_USE; \
2708 ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
2709 a->busy_##n##_ports_per_thread[thread_index]++; \
2710 a->busy_##n##_ports++; \
2712 foreach_snat_protocol
2715 nat_elog_info ("unknown protocol");
2720 return VNET_API_ERROR_NO_SUCH_ENTRY;
2724 snat_static_mapping_match (snat_main_t * sm,
2725 snat_session_key_t match,
2726 snat_session_key_t * mapping,
2729 twice_nat_type_t * twice_nat,
2730 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2731 u8 * is_identity_nat)
2733 clib_bihash_kv_8_8_t kv, value;
2734 snat_static_mapping_t *m;
2735 snat_session_key_t m_key;
2736 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2737 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2739 nat44_lb_addr_port_t *local;
2741 m_key.fib_index = match.fib_index;
2744 mapping_hash = &sm->static_mapping_by_external;
2745 m_key.fib_index = 0;
2748 m_key.addr = match.addr;
2749 m_key.port = clib_net_to_host_u16 (match.port);
2750 m_key.protocol = match.protocol;
2752 kv.key = m_key.as_u64;
2754 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2756 /* Try address only mapping */
2759 kv.key = m_key.as_u64;
2760 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2764 m = pool_elt_at_index (sm->static_mappings, value.value);
2768 if (is_lb_static_mapping (m))
2770 if (PREDICT_FALSE (lb != 0))
2771 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2772 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2778 local = pool_elt_at_index (m->locals, backend_index);
2779 mapping->addr = local->addr;
2780 mapping->port = clib_host_to_net_u16 (local->port);
2781 mapping->fib_index = local->fib_index;
2784 // pick locals matching this worker
2785 if (PREDICT_FALSE (sm->num_workers > 1))
2787 u32 thread_index = vlib_get_thread_index ();
2789 pool_foreach_index (i, m->locals,
2791 local = pool_elt_at_index (m->locals, i);
2794 .src_address = local->addr,
2797 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2804 ASSERT (vec_len (tmp) != 0);
2809 pool_foreach_index (i, m->locals,
2815 hi = vec_len (tmp) - 1;
2816 local = pool_elt_at_index (m->locals, tmp[hi]);
2817 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2820 mid = ((hi - lo) >> 1) + lo;
2821 local = pool_elt_at_index (m->locals, tmp[mid]);
2822 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2824 local = pool_elt_at_index (m->locals, tmp[lo]);
2825 if (!(local->prefix >= rand))
2827 mapping->addr = local->addr;
2828 mapping->port = clib_host_to_net_u16 (local->port);
2829 mapping->fib_index = local->fib_index;
2832 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2833 match.protocol, match.port,
2834 tmp[lo], m->affinity,
2835 m->affinity_per_service_list_head_index))
2836 nat_elog_info ("create affinity record failed");
2842 if (PREDICT_FALSE (lb != 0))
2844 mapping->fib_index = m->fib_index;
2845 mapping->addr = m->local_addr;
2846 /* Address only mapping doesn't change port */
2847 mapping->port = is_addr_only_static_mapping (m) ? match.port
2848 : clib_host_to_net_u16 (m->local_port);
2850 mapping->protocol = m->proto;
2854 mapping->addr = m->external_addr;
2855 /* Address only mapping doesn't change port */
2856 mapping->port = is_addr_only_static_mapping (m) ? match.port
2857 : clib_host_to_net_u16 (m->external_port);
2858 mapping->fib_index = sm->outside_fib_index;
2862 if (PREDICT_FALSE (is_addr_only != 0))
2863 *is_addr_only = is_addr_only_static_mapping (m);
2865 if (PREDICT_FALSE (twice_nat != 0))
2866 *twice_nat = m->twice_nat;
2868 if (PREDICT_FALSE (is_identity_nat != 0))
2869 *is_identity_nat = is_identity_static_mapping (m);
2874 static_always_inline u16
2875 snat_random_port (u16 min, u16 max)
2877 snat_main_t *sm = &snat_main;
2878 return min + random_u32 (&sm->random_seed) /
2879 (random_u32_max () / (max - min + 1) + 1);
2883 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2886 snat_session_key_t * k,
2887 u16 port_per_thread,
2888 u32 snat_thread_index)
2890 snat_main_t *sm = &snat_main;
2892 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2893 port_per_thread, snat_thread_index);
2897 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2900 snat_session_key_t * k,
2901 u16 port_per_thread, u32 snat_thread_index)
2904 snat_address_t *a, *ga = 0;
2907 for (i = 0; i < vec_len (addresses); i++)
2910 switch (k->protocol)
2912 #define _(N, j, n, s) \
2913 case SNAT_PROTOCOL_##N: \
2914 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2916 if (a->fib_index == fib_index) \
2920 portnum = (port_per_thread * \
2921 snat_thread_index) + \
2922 snat_random_port(1, port_per_thread) + 1024; \
2923 if (a->busy_##n##_port_refcounts[portnum]) \
2925 --a->busy_##n##_port_refcounts[portnum]; \
2926 a->busy_##n##_ports_per_thread[thread_index]++; \
2927 a->busy_##n##_ports++; \
2928 k->addr = a->addr; \
2929 k->port = clib_host_to_net_u16(portnum); \
2933 else if (a->fib_index == ~0) \
2939 foreach_snat_protocol
2942 nat_elog_info ("unknown protocol");
2951 switch (k->protocol)
2953 #define _(N, j, n, s) \
2954 case SNAT_PROTOCOL_##N: \
2957 portnum = (port_per_thread * \
2958 snat_thread_index) + \
2959 snat_random_port(1, port_per_thread) + 1024; \
2960 if (a->busy_##n##_port_refcounts[portnum]) \
2962 ++a->busy_##n##_port_refcounts[portnum]; \
2963 a->busy_##n##_ports_per_thread[thread_index]++; \
2964 a->busy_##n##_ports++; \
2965 k->addr = a->addr; \
2966 k->port = clib_host_to_net_u16(portnum); \
2970 foreach_snat_protocol
2973 nat_elog_info ("unknown protocol");
2978 /* Totally out of translations to use... */
2979 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2984 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2987 snat_session_key_t * k,
2988 u16 port_per_thread, u32 snat_thread_index)
2990 snat_main_t *sm = &snat_main;
2991 snat_address_t *a = addresses;
2992 u16 m, ports, portnum, A, j;
2993 m = 16 - (sm->psid_offset + sm->psid_length);
2994 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2996 if (!vec_len (addresses))
2999 switch (k->protocol)
3001 #define _(N, i, n, s) \
3002 case SNAT_PROTOCOL_##N: \
3003 if (a->busy_##n##_ports < ports) \
3007 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
3008 j = snat_random_port(0, pow2_mask(m)); \
3009 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
3010 if (a->busy_##n##_port_refcounts[portnum]) \
3012 ++a->busy_##n##_port_refcounts[portnum]; \
3013 a->busy_##n##_ports++; \
3014 k->addr = a->addr; \
3015 k->port = clib_host_to_net_u16 (portnum); \
3020 foreach_snat_protocol
3023 nat_elog_info ("unknown protocol");
3028 /* Totally out of translations to use... */
3029 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3034 nat_alloc_addr_and_port_range (snat_address_t * addresses,
3037 snat_session_key_t * k,
3038 u16 port_per_thread, u32 snat_thread_index)
3040 snat_main_t *sm = &snat_main;
3041 snat_address_t *a = addresses;
3044 ports = sm->end_port - sm->start_port + 1;
3046 if (!vec_len (addresses))
3049 switch (k->protocol)
3051 #define _(N, i, n, s) \
3052 case SNAT_PROTOCOL_##N: \
3053 if (a->busy_##n##_ports < ports) \
3057 portnum = snat_random_port(sm->start_port, sm->end_port); \
3058 if (a->busy_##n##_port_refcounts[portnum]) \
3060 ++a->busy_##n##_port_refcounts[portnum]; \
3061 a->busy_##n##_ports++; \
3062 k->addr = a->addr; \
3063 k->port = clib_host_to_net_u16 (portnum); \
3068 foreach_snat_protocol
3071 nat_elog_info ("unknown protocol");
3076 /* Totally out of translations to use... */
3077 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3082 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
3084 dpo_id_t dpo_v4 = DPO_INVALID;
3085 fib_prefix_t pfx = {
3086 .fp_proto = FIB_PROTOCOL_IP4,
3088 .fp_addr.ip4.as_u32 = addr.as_u32,
3093 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
3094 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
3095 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
3096 dpo_reset (&dpo_v4);
3100 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
3105 format_session_kvp (u8 * s, va_list * args)
3107 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3108 snat_session_key_t k;
3112 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
3118 format_static_mapping_kvp (u8 * s, va_list * args)
3120 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3121 snat_session_key_t k;
3125 s = format (s, "%U static-mapping-index %llu",
3126 format_static_mapping_key, &k, v->value);
3132 format_user_kvp (u8 * s, va_list * args)
3134 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3139 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
3140 k.fib_index, v->value);
3146 format_ed_session_kvp (u8 * s, va_list * args)
3148 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3151 k.as_u64[0] = v->key[0];
3152 k.as_u64[1] = v->key[1];
3155 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
3156 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
3157 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
3158 format_ip_protocol, k.proto, k.fib_index, v->value);
3164 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3167 snat_main_t *sm = &snat_main;
3168 u32 next_worker_index = 0;
3171 next_worker_index = sm->first_worker_index;
3172 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3173 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3175 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3176 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3178 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3180 return next_worker_index;
3184 snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
3185 u32 rx_fib_index0, u8 is_output)
3187 snat_main_t *sm = &snat_main;
3190 snat_session_key_t m_key;
3191 clib_bihash_kv_8_8_t kv, value;
3192 snat_static_mapping_t *m;
3194 u32 next_worker_index = 0;
3196 /* first try static mappings without port */
3197 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3199 m_key.addr = ip0->dst_address;
3202 m_key.fib_index = rx_fib_index0;
3203 kv.key = m_key.as_u64;
3204 if (!clib_bihash_search_8_8
3205 (&sm->static_mapping_by_external, &kv, &value))
3207 m = pool_elt_at_index (sm->static_mappings, value.value);
3208 return m->workers[0];
3212 proto = ip_proto_to_snat_proto (ip0->protocol);
3213 udp = ip4_next_header (ip0);
3214 port = udp->dst_port;
3216 /* unknown protocol */
3217 if (PREDICT_FALSE (proto == ~0))
3219 /* use current thread */
3220 return vlib_get_thread_index ();
3223 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3225 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3226 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3227 if (!icmp_type_is_error_message
3228 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3229 port = vnet_buffer (b)->ip.reass.l4_src_port;
3232 /* if error message, then it's not fragmented and we can access it */
3233 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3234 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3235 void *l4_header = ip4_next_header (inner_ip);
3238 case SNAT_PROTOCOL_ICMP:
3239 icmp = (icmp46_header_t *) l4_header;
3240 echo = (icmp_echo_header_t *) (icmp + 1);
3241 port = echo->identifier;
3243 case SNAT_PROTOCOL_UDP:
3244 case SNAT_PROTOCOL_TCP:
3245 port = ((tcp_udp_header_t *) l4_header)->src_port;
3248 return vlib_get_thread_index ();
3253 /* try static mappings with port */
3254 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3256 m_key.addr = ip0->dst_address;
3257 m_key.port = clib_net_to_host_u16 (port);
3258 m_key.protocol = proto;
3259 m_key.fib_index = rx_fib_index0;
3260 kv.key = m_key.as_u64;
3261 if (!clib_bihash_search_8_8
3262 (&sm->static_mapping_by_external, &kv, &value))
3264 m = pool_elt_at_index (sm->static_mappings, value.value);
3265 return m->workers[0];
3269 /* worker by outside port */
3270 next_worker_index = sm->first_worker_index;
3271 next_worker_index +=
3272 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3273 return next_worker_index;
3277 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3280 snat_main_t *sm = &snat_main;
3281 u32 next_worker_index = sm->first_worker_index;
3284 clib_bihash_kv_16_8_t kv16, value16;
3285 snat_main_per_thread_data_t *tsm;
3288 if (PREDICT_FALSE (is_output))
3290 u32 fib_index = sm->outside_fib_index;
3291 nat_outside_fib_t *outside_fib;
3292 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3293 fib_prefix_t pfx = {
3294 .fp_proto = FIB_PROTOCOL_IP4,
3297 .ip4.as_u32 = ip->dst_address.as_u32,
3302 udp = ip4_next_header (ip);
3304 switch (vec_len (sm->outside_fibs))
3307 fib_index = sm->outside_fib_index;
3310 fib_index = sm->outside_fibs[0].fib_index;
3314 vec_foreach (outside_fib, sm->outside_fibs)
3316 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3317 if (FIB_NODE_INDEX_INVALID != fei)
3319 if (fib_entry_get_resolving_interface (fei) != ~0)
3321 fib_index = outside_fib->fib_index;
3330 make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
3331 ip->protocol, fib_index, udp->src_port, udp->dst_port);
3334 vec_foreach (tsm, sm->per_thread_data)
3336 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3339 next_worker_index += tsm->thread_index;
3341 nat_elog_debug_handoff (
3342 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3343 next_worker_index, fib_index,
3344 clib_net_to_host_u32 (ip->src_address.as_u32),
3345 clib_net_to_host_u32 (ip->dst_address.as_u32));
3347 return next_worker_index;
3353 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3354 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3356 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3357 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3359 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3361 if (PREDICT_TRUE (!is_output))
3363 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3364 next_worker_index, rx_fib_index,
3365 clib_net_to_host_u32 (ip->src_address.as_u32),
3366 clib_net_to_host_u32 (ip->dst_address.as_u32));
3370 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3371 next_worker_index, rx_fib_index,
3372 clib_net_to_host_u32 (ip->src_address.as_u32),
3373 clib_net_to_host_u32 (ip->dst_address.as_u32));
3376 return next_worker_index;
3380 nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
3381 u32 rx_fib_index, u8 is_output)
3383 snat_main_t *sm = &snat_main;
3384 clib_bihash_kv_8_8_t kv, value;
3385 clib_bihash_kv_16_8_t kv16, value16;
3386 snat_main_per_thread_data_t *tsm;
3388 u32 proto, next_worker_index = 0;
3391 snat_static_mapping_t *m;
3394 proto = ip_proto_to_snat_proto (ip->protocol);
3396 if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3398 udp = ip4_next_header (ip);
3400 make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
3401 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
3404 vec_foreach (tsm, sm->per_thread_data)
3406 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3409 next_worker_index = sm->first_worker_index + tsm->thread_index;
3410 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3411 next_worker_index, rx_fib_index,
3412 clib_net_to_host_u32 (ip->src_address.as_u32),
3413 clib_net_to_host_u32 (ip->dst_address.as_u32));
3414 return next_worker_index;
3419 else if (proto == SNAT_PROTOCOL_ICMP)
3421 nat_ed_ses_key_t key;
3423 if (!get_icmp_o2i_ed_key (b, ip, &key))
3426 key.fib_index = rx_fib_index;
3427 kv16.key[0] = key.as_u64[0];
3428 kv16.key[1] = key.as_u64[1];
3431 vec_foreach (tsm, sm->per_thread_data)
3433 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3436 next_worker_index = sm->first_worker_index +
3438 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3439 next_worker_index, rx_fib_index,
3440 clib_net_to_host_u32 (ip->src_address.as_u32),
3441 clib_net_to_host_u32 (ip->dst_address.as_u32));
3442 return next_worker_index;
3449 /* first try static mappings without port */
3450 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3452 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3453 if (!clib_bihash_search_8_8
3454 (&sm->static_mapping_by_external, &kv, &value))
3456 m = pool_elt_at_index (sm->static_mappings, value.value);
3457 next_worker_index = m->workers[0];
3462 /* unknown protocol */
3463 if (PREDICT_FALSE (proto == ~0))
3465 /* use current thread */
3466 next_worker_index = vlib_get_thread_index ();
3470 udp = ip4_next_header (ip);
3471 port = udp->dst_port;
3473 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3475 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3476 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3477 if (!icmp_type_is_error_message
3478 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3479 port = vnet_buffer (b)->ip.reass.l4_src_port;
3482 /* if error message, then it's not fragmented and we can access it */
3483 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3484 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3485 void *l4_header = ip4_next_header (inner_ip);
3488 case SNAT_PROTOCOL_ICMP:
3489 icmp = (icmp46_header_t *) l4_header;
3490 echo = (icmp_echo_header_t *) (icmp + 1);
3491 port = echo->identifier;
3493 case SNAT_PROTOCOL_UDP:
3494 case SNAT_PROTOCOL_TCP:
3495 port = ((tcp_udp_header_t *) l4_header)->src_port;
3498 next_worker_index = vlib_get_thread_index ();
3504 /* try static mappings with port */
3505 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3507 make_sm_kv (&kv, &ip->dst_address, proto, 0,
3508 clib_net_to_host_u16 (port));
3509 if (!clib_bihash_search_8_8
3510 (&sm->static_mapping_by_external, &kv, &value))
3512 m = pool_elt_at_index (sm->static_mappings, value.value);
3513 if (!is_lb_static_mapping (m))
3515 next_worker_index = m->workers[0];
3519 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3520 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3522 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3524 m->workers[hash & (_vec_len (m->workers) - 1)];
3526 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3531 /* worker by outside port */
3532 next_worker_index = sm->first_worker_index;
3533 next_worker_index +=
3534 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3537 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3538 clib_net_to_host_u32 (ip->src_address.as_u32),
3539 clib_net_to_host_u32 (ip->dst_address.as_u32));
3540 return next_worker_index;
3544 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3545 ip4_address_t * out_addr, u16 out_port,
3546 ip4_address_t * eh_addr, u16 eh_port,
3547 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3548 u32 fib_index, u16 flags, u32 thread_index)
3550 snat_main_t *sm = &snat_main;
3551 snat_session_key_t key;
3554 clib_bihash_kv_8_8_t kv;
3555 f64 now = vlib_time_now (sm->vlib_main);
3556 nat_outside_fib_t *outside_fib;
3557 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3558 snat_main_per_thread_data_t *tsm;
3559 fib_prefix_t pfx = {
3560 .fp_proto = FIB_PROTOCOL_IP4,
3563 .ip4.as_u32 = eh_addr->as_u32,
3567 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3569 key.addr.as_u32 = out_addr->as_u32;
3570 key.port = out_port;
3571 key.protocol = proto;
3573 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3575 if (nat_set_outside_address_and_port
3576 (sm->addresses, thread_index, &key))
3580 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3584 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3588 s->last_heard = now;
3590 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3591 s->ext_host_port = eh_port;
3592 user_session_increment (sm, u, snat_is_session_static (s));
3593 switch (vec_len (sm->outside_fibs))
3596 key.fib_index = sm->outside_fib_index;
3599 key.fib_index = sm->outside_fibs[0].fib_index;
3603 vec_foreach (outside_fib, sm->outside_fibs)
3605 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3606 if (FIB_NODE_INDEX_INVALID != fei)
3608 if (fib_entry_get_resolving_interface (fei) != ~0)
3610 key.fib_index = outside_fib->fib_index;
3619 kv.key = key.as_u64;
3620 kv.value = s - tsm->sessions;
3621 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3622 nat_elog_warn ("out2in key add failed");
3624 key.addr.as_u32 = in_addr->as_u32;
3626 key.fib_index = fib_index;
3628 kv.key = key.as_u64;
3629 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3630 nat_elog_warn ("in2out key add failed");
3634 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3635 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3638 snat_main_t *sm = &snat_main;
3639 snat_session_key_t key;
3640 clib_bihash_kv_8_8_t kv, value;
3643 snat_main_per_thread_data_t *tsm;
3645 if (sm->num_workers > 1)
3647 sm->first_worker_index +
3648 (sm->workers[(clib_net_to_host_u16 (out_port) -
3649 1024) / sm->port_per_thread]);
3651 thread_index = sm->num_workers;
3652 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3654 key.addr.as_u32 = out_addr->as_u32;
3655 key.port = out_port;
3656 key.protocol = proto;
3657 key.fib_index = fib_index;
3658 kv.key = key.as_u64;
3659 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3662 s = pool_elt_at_index (tsm->sessions, value.value);
3663 nat_free_session_data (sm, s, thread_index, 1);
3664 nat44_delete_session (sm, s, thread_index);
3668 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3669 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3670 u32 total_pkts, u64 total_bytes, u32 thread_index)
3672 snat_main_t *sm = &snat_main;
3673 snat_session_key_t key;
3674 clib_bihash_kv_8_8_t kv, value;
3676 snat_main_per_thread_data_t *tsm;
3678 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3680 key.addr.as_u32 = out_addr->as_u32;
3681 key.port = out_port;
3682 key.protocol = proto;
3683 key.fib_index = fib_index;
3684 kv.key = key.as_u64;
3685 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3688 s = pool_elt_at_index (tsm->sessions, value.value);
3689 s->total_pkts = total_pkts;
3690 s->total_bytes = total_bytes;
3694 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3695 ip4_address_t * out_addr, u16 out_port,
3696 ip4_address_t * eh_addr, u16 eh_port,
3697 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3698 u32 fib_index, u16 flags, u32 thread_index)
3700 snat_main_t *sm = &snat_main;
3701 snat_session_key_t key;
3704 clib_bihash_kv_16_8_t kv;
3705 f64 now = vlib_time_now (sm->vlib_main);
3706 nat_outside_fib_t *outside_fib;
3707 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3708 snat_main_per_thread_data_t *tsm;
3709 fib_prefix_t pfx = {
3710 .fp_proto = FIB_PROTOCOL_IP4,
3713 .ip4.as_u32 = eh_addr->as_u32,
3717 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3719 key.addr.as_u32 = out_addr->as_u32;
3720 key.port = out_port;
3721 key.protocol = proto;
3723 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3725 if (nat_set_outside_address_and_port
3726 (sm->addresses, thread_index, &key))
3730 key.addr.as_u32 = ehn_addr->as_u32;
3731 key.port = ehn_port;
3732 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3734 if (nat_set_outside_address_and_port
3735 (sm->twice_nat_addresses, thread_index, &key))
3739 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3743 s = nat_ed_session_alloc (sm, u, thread_index, now);
3747 s->last_heard = now;
3749 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3750 s->ext_host_nat_port = s->ext_host_port = eh_port;
3751 if (is_twice_nat_session (s))
3753 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3754 s->ext_host_nat_port = ehn_port;
3756 user_session_increment (sm, u, snat_is_session_static (s));
3757 switch (vec_len (sm->outside_fibs))
3760 key.fib_index = sm->outside_fib_index;
3763 key.fib_index = sm->outside_fibs[0].fib_index;
3767 vec_foreach (outside_fib, sm->outside_fibs)
3769 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3770 if (FIB_NODE_INDEX_INVALID != fei)
3772 if (fib_entry_get_resolving_interface (fei) != ~0)
3774 key.fib_index = outside_fib->fib_index;
3782 key.addr.as_u32 = out_addr->as_u32;
3783 key.port = out_port;
3785 kv.value = s - tsm->sessions;
3787 key.addr.as_u32 = in_addr->as_u32;
3789 key.fib_index = fib_index;
3792 make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
3793 snat_proto_to_ip_proto (proto), fib_index, in_port,
3794 s->ext_host_nat_port);
3795 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3796 nat_elog_warn ("in2out key add failed");
3798 make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3799 s->out2in.fib_index, out_port, eh_port);
3800 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3801 nat_elog_warn ("out2in key add failed");
3805 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3806 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3807 u32 fib_index, u32 ti)
3809 snat_main_t *sm = &snat_main;
3810 nat_ed_ses_key_t key;
3811 clib_bihash_kv_16_8_t kv, value;
3814 snat_main_per_thread_data_t *tsm;
3816 if (sm->num_workers > 1)
3818 sm->first_worker_index +
3819 (sm->workers[(clib_net_to_host_u16 (out_port) -
3820 1024) / sm->port_per_thread]);
3822 thread_index = sm->num_workers;
3823 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3825 key.l_addr.as_u32 = out_addr->as_u32;
3826 key.l_port = out_port;
3827 key.r_addr.as_u32 = eh_addr->as_u32;
3828 key.r_port = eh_port;
3830 key.fib_index = fib_index;
3831 kv.key[0] = key.as_u64[0];
3832 kv.key[1] = key.as_u64[1];
3833 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3836 s = pool_elt_at_index (tsm->sessions, value.value);
3837 nat_free_session_data (sm, s, thread_index, 1);
3838 nat44_delete_session (sm, s, thread_index);
3842 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3843 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3844 u32 fib_index, u32 total_pkts, u64 total_bytes,
3847 snat_main_t *sm = &snat_main;
3848 nat_ed_ses_key_t key;
3849 clib_bihash_kv_16_8_t kv, value;
3851 snat_main_per_thread_data_t *tsm;
3853 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3855 key.l_addr.as_u32 = out_addr->as_u32;
3856 key.l_port = out_port;
3857 key.r_addr.as_u32 = eh_addr->as_u32;
3858 key.r_port = eh_port;
3860 key.fib_index = fib_index;
3861 kv.key[0] = key.as_u64[0];
3862 kv.key[1] = key.as_u64[1];
3863 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3866 s = pool_elt_at_index (tsm->sessions, value.value);
3867 s->total_pkts = total_pkts;
3868 s->total_bytes = total_bytes;
3871 static clib_error_t *
3872 snat_config (vlib_main_t * vm, unformat_input_t * input)
3874 snat_main_t *sm = &snat_main;
3875 nat66_main_t *nm = &nat66_main;
3876 //dslite_main_t *dm = &dslite_main;
3877 snat_main_per_thread_data_t *tsm;
3879 u32 static_mapping_buckets = 1024;
3880 u32 static_mapping_memory_size = 64 << 20;
3882 u32 nat64_bib_buckets = 1024;
3883 u32 nat64_bib_memory_size = 128 << 20;
3885 u32 nat64_st_buckets = 2048;
3886 u32 nat64_st_memory_size = 256 << 20;
3888 u32 user_buckets = 128;
3889 u32 user_memory_size = 64 << 20;
3890 u32 translation_buckets = 1024;
3891 u32 translation_memory_size = 128 << 20;
3893 u32 max_translations_per_user = ~0;
3895 u32 outside_vrf_id = 0;
3896 u32 outside_ip6_vrf_id = 0;
3897 u32 inside_vrf_id = 0;
3898 u8 static_mapping_only = 0;
3899 u8 static_mapping_connection_tracking = 0;
3901 // configurable timeouts
3902 u32 udp_timeout = SNAT_UDP_TIMEOUT;
3903 u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
3904 u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3905 u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3907 sm->deterministic = 0;
3909 sm->endpoint_dependent = 0;
3911 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3914 (input, "translation hash buckets %d", &translation_buckets))
3916 else if (unformat (input, "udp timeout %d", &udp_timeout))
3918 else if (unformat (input, "icmp timeout %d", &icmp_timeout))
3920 else if (unformat (input, "tcp transitory timeout %d",
3921 &tcp_transitory_timeout));
3922 else if (unformat (input, "tcp established timeout %d",
3923 &tcp_established_timeout));
3924 else if (unformat (input, "translation hash memory %d",
3925 &translation_memory_size));
3926 else if (unformat (input, "user hash buckets %d", &user_buckets))
3928 else if (unformat (input, "user hash memory %d", &user_memory_size))
3930 else if (unformat (input, "max translations per user %d",
3931 &max_translations_per_user))
3933 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3935 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3937 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3939 else if (unformat (input, "static mapping only"))
3941 static_mapping_only = 1;
3942 if (unformat (input, "connection tracking"))
3943 static_mapping_connection_tracking = 1;
3945 else if (unformat (input, "deterministic"))
3946 sm->deterministic = 1;
3947 else if (unformat (input, "nat64 bib hash buckets %d",
3948 &nat64_bib_buckets))
3950 else if (unformat (input, "nat64 bib hash memory %d",
3951 &nat64_bib_memory_size))
3954 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3956 else if (unformat (input, "nat64 st hash memory %d",
3957 &nat64_st_memory_size))
3959 else if (unformat (input, "out2in dpo"))
3961 //else if (unformat (input, "dslite ce"))
3962 //dslite_set_ce (dm, 1);
3963 else if (unformat (input, "endpoint-dependent"))
3964 sm->endpoint_dependent = 1;
3966 return clib_error_return (0, "unknown input '%U'",
3967 format_unformat_error, input);
3970 if (sm->deterministic && sm->endpoint_dependent)
3971 return clib_error_return (0,
3972 "deterministic and endpoint-dependent modes are mutually exclusive");
3974 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
3975 return clib_error_return (0,
3976 "static mapping only mode available only for simple nat");
3978 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
3979 return clib_error_return (0,
3980 "out2in dpo mode available only for simple nat");
3982 /* optionally configurable timeouts for testing purposes */
3983 sm->udp_timeout = udp_timeout;
3984 sm->tcp_transitory_timeout = tcp_transitory_timeout;
3985 sm->tcp_established_timeout = tcp_established_timeout;
3986 sm->icmp_timeout = icmp_timeout;
3988 sm->min_timeout = nat44_minimal_timeout (sm);
3990 sm->user_buckets = user_buckets;
3991 sm->user_memory_size = user_memory_size;
3993 sm->translation_buckets = translation_buckets;
3994 sm->translation_memory_size = translation_memory_size;
3996 /* do not exceed load factor 10 */
3997 sm->max_translations = 10 * translation_buckets;
3998 sm->max_translations_per_user = max_translations_per_user == ~0 ?
3999 sm->max_translations : max_translations_per_user;
4001 sm->outside_vrf_id = outside_vrf_id;
4002 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4005 nm->outside_vrf_id = outside_ip6_vrf_id;
4006 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
4009 sm->inside_vrf_id = inside_vrf_id;
4010 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4013 sm->static_mapping_only = static_mapping_only;
4014 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
4016 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
4017 nat64_st_memory_size);
4019 if (sm->deterministic)
4021 sm->in2out_node_index = snat_det_in2out_node.index;
4022 sm->in2out_output_node_index = ~0;
4023 sm->out2in_node_index = snat_det_out2in_node.index;
4024 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
4025 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
4029 if (sm->endpoint_dependent)
4031 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
4032 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
4034 sm->handoff_out2in_index = nat_pre_out2in_node.index;
4035 sm->handoff_in2out_index = nat_pre_in2out_node.index;
4036 sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
4038 sm->in2out_node_index = nat44_ed_in2out_node.index;
4039 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
4040 sm->out2in_node_index = nat44_ed_out2in_node.index;
4042 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
4043 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
4044 nat_affinity_init (vm);
4045 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
4050 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
4051 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
4053 sm->handoff_out2in_index = snat_out2in_node.index;
4054 sm->handoff_in2out_index = snat_in2out_node.index;
4055 sm->handoff_in2out_output_index = snat_in2out_output_node.index;
4057 sm->in2out_node_index = snat_in2out_node.index;
4058 sm->in2out_output_node_index = snat_in2out_output_node.index;
4059 sm->out2in_node_index = snat_out2in_node.index;
4060 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
4061 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
4062 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
4064 if (!static_mapping_only ||
4065 (static_mapping_only && static_mapping_connection_tracking))
4068 vec_foreach (tsm, sm->per_thread_data)
4070 tsm->min_session_timeout = 0;
4073 tsm->cleanup_runs = 0;
4074 tsm->cleanup_timeout = 0;
4076 pool_alloc (tsm->sessions, sm->max_translations);
4077 pool_alloc (tsm->list_pool, sm->max_translations);
4079 if (sm->endpoint_dependent)
4081 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
4082 translation_buckets,
4083 translation_memory_size);
4084 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
4085 format_ed_session_kvp);
4087 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
4088 translation_buckets,
4089 translation_memory_size);
4090 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
4091 format_ed_session_kvp);
4092 clib_bihash_init_16_8
4093 (&sm->ed_ext_ports, "ed-nat-5-tuple-port-overload-hash",
4094 translation_buckets, translation_memory_size);
4098 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
4099 translation_buckets,
4100 translation_memory_size);
4101 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
4102 format_session_kvp);
4104 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
4105 translation_buckets,
4106 translation_memory_size);
4107 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
4108 format_session_kvp);
4111 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
4113 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
4121 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
4122 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
4124 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
4125 "static_mapping_by_local", static_mapping_buckets,
4126 static_mapping_memory_size);
4127 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
4128 format_static_mapping_kvp);
4130 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
4131 "static_mapping_by_external",
4132 static_mapping_buckets,
4133 static_mapping_memory_size);
4134 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
4135 format_static_mapping_kvp);
4141 VLIB_CONFIG_FUNCTION (snat_config, "nat");
4144 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
4147 ip4_address_t * address,
4149 u32 if_address_index, u32 is_delete)
4151 snat_main_t *sm = &snat_main;
4152 snat_static_map_resolve_t *rp;
4153 snat_static_mapping_t *m;
4154 snat_session_key_t m_key;
4155 clib_bihash_kv_8_8_t kv, value;
4157 ip4_address_t l_addr;
4159 for (i = 0; i < vec_len (sm->to_resolve); i++)
4161 rp = sm->to_resolve + i;
4162 if (rp->addr_only == 0)
4164 if (rp->sw_if_index == sw_if_index)
4171 m_key.addr.as_u32 = address->as_u32;
4172 m_key.port = rp->addr_only ? 0 : rp->e_port;
4173 m_key.protocol = rp->addr_only ? 0 : rp->proto;
4174 m_key.fib_index = sm->outside_fib_index;
4175 kv.key = m_key.as_u64;
4176 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4179 m = pool_elt_at_index (sm->static_mappings, value.value);
4183 /* Don't trip over lease renewal, static config */
4193 /* Indetity mapping? */
4194 if (rp->l_addr.as_u32 == 0)
4195 l_addr.as_u32 = address[0].as_u32;
4197 l_addr.as_u32 = rp->l_addr.as_u32;
4198 /* Add the static mapping */
4199 rv = snat_add_static_mapping (l_addr,
4204 rp->addr_only, ~0 /* sw_if_index */ ,
4205 rp->proto, !is_delete, rp->twice_nat,
4206 rp->out2in_only, rp->tag, rp->identity_nat);
4208 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4212 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4215 ip4_address_t * address,
4217 u32 if_address_index, u32 is_delete)
4219 snat_main_t *sm = &snat_main;
4220 snat_static_map_resolve_t *rp;
4221 ip4_address_t l_addr;
4225 snat_address_t *addresses = sm->addresses;
4227 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4229 if (sw_if_index == sm->auto_add_sw_if_indices[i])
4233 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4236 addresses = sm->twice_nat_addresses;
4237 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4246 /* Don't trip over lease renewal, static config */
4247 for (j = 0; j < vec_len (addresses); j++)
4248 if (addresses[j].addr.as_u32 == address->as_u32)
4251 (void) snat_add_address (sm, address, ~0, twice_nat);
4252 /* Scan static map resolution vector */
4253 for (j = 0; j < vec_len (sm->to_resolve); j++)
4255 rp = sm->to_resolve + j;
4258 /* On this interface? */
4259 if (rp->sw_if_index == sw_if_index)
4261 /* Indetity mapping? */
4262 if (rp->l_addr.as_u32 == 0)
4263 l_addr.as_u32 = address[0].as_u32;
4265 l_addr.as_u32 = rp->l_addr.as_u32;
4266 /* Add the static mapping */
4267 rv = snat_add_static_mapping (l_addr,
4273 ~0 /* sw_if_index */ ,
4275 rp->is_add, rp->twice_nat,
4276 rp->out2in_only, rp->tag,
4279 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4287 (void) snat_del_address (sm, address[0], 1, twice_nat);
4294 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4297 ip4_main_t *ip4_main = sm->ip4_main;
4298 ip4_address_t *first_int_addr;
4299 snat_static_map_resolve_t *rp;
4300 u32 *indices_to_delete = 0;
4302 u32 *auto_add_sw_if_indices =
4304 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4306 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4309 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4311 if (auto_add_sw_if_indices[i] == sw_if_index)
4315 /* if have address remove it */
4317 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4320 for (j = 0; j < vec_len (sm->to_resolve); j++)
4322 rp = sm->to_resolve + j;
4323 if (rp->sw_if_index == sw_if_index)
4324 vec_add1 (indices_to_delete, j);
4326 if (vec_len (indices_to_delete))
4328 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4329 vec_del1 (sm->to_resolve, j);
4330 vec_free (indices_to_delete);
4334 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4336 vec_del1 (sm->auto_add_sw_if_indices, i);
4339 return VNET_API_ERROR_VALUE_EXIST;
4346 return VNET_API_ERROR_NO_SUCH_ENTRY;
4348 /* add to the auto-address list */
4350 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4352 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4354 /* If the address is already bound - or static - add it now */
4356 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4362 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4363 snat_protocol_t proto, u32 vrf_id, int is_in)
4365 snat_main_per_thread_data_t *tsm;
4366 clib_bihash_kv_8_8_t kv, value;
4368 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4369 snat_session_key_t key;
4371 clib_bihash_8_8_t *t;
4373 if (sm->endpoint_dependent)
4374 return VNET_API_ERROR_UNSUPPORTED;
4376 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4377 if (sm->num_workers > 1)
4379 vec_elt_at_index (sm->per_thread_data,
4380 sm->worker_in2out_cb (&ip, fib_index, 0));
4382 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4384 key.addr.as_u32 = addr->as_u32;
4385 key.port = clib_host_to_net_u16 (port);
4386 key.protocol = proto;
4387 key.fib_index = fib_index;
4388 kv.key = key.as_u64;
4389 t = is_in ? &tsm->in2out : &tsm->out2in;
4390 if (!clib_bihash_search_8_8 (t, &kv, &value))
4392 if (pool_is_free_index (tsm->sessions, value.value))
4393 return VNET_API_ERROR_UNSPECIFIED;
4395 s = pool_elt_at_index (tsm->sessions, value.value);
4396 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4397 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4401 return VNET_API_ERROR_NO_SUCH_ENTRY;
4405 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4406 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4407 u32 vrf_id, int is_in)
4410 clib_bihash_16_8_t *t;
4411 nat_ed_ses_key_t key;
4412 clib_bihash_kv_16_8_t kv, value;
4413 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4415 snat_main_per_thread_data_t *tsm;
4417 if (!sm->endpoint_dependent)
4418 return VNET_API_ERROR_FEATURE_DISABLED;
4420 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4421 if (sm->num_workers > 1)
4423 vec_elt_at_index (sm->per_thread_data,
4424 sm->worker_in2out_cb (&ip, fib_index, 0));
4426 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4428 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4429 key.l_addr.as_u32 = addr->as_u32;
4430 key.r_addr.as_u32 = eh_addr->as_u32;
4431 key.l_port = clib_host_to_net_u16 (port);
4432 key.r_port = clib_host_to_net_u16 (eh_port);
4434 key.fib_index = fib_index;
4435 kv.key[0] = key.as_u64[0];
4436 kv.key[1] = key.as_u64[1];
4437 if (clib_bihash_search_16_8 (t, &kv, &value))
4438 return VNET_API_ERROR_NO_SUCH_ENTRY;
4440 if (pool_is_free_index (tsm->sessions, value.value))
4441 return VNET_API_ERROR_UNSPECIFIED;
4442 s = pool_elt_at_index (tsm->sessions, value.value);
4443 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4444 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4449 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4451 snat_main_t *sm = &snat_main;
4453 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4454 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4456 sm->psid_offset = psid_offset;
4457 sm->psid_length = psid_length;
4461 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4463 snat_main_t *sm = &snat_main;
4465 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4466 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4467 sm->start_port = start_port;
4468 sm->end_port = end_port;
4472 nat_set_alloc_addr_and_port_default (void)
4474 snat_main_t *sm = &snat_main;
4476 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4477 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4480 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4481 vlib_node_runtime_t * node,
4482 vlib_frame_t * frame)
4488 VLIB_REGISTER_NODE (nat_default_node) = {
4489 .name = "nat-default",
4490 .vector_size = sizeof (u32),
4492 .type = VLIB_NODE_TYPE_INTERNAL,
4494 .n_next_nodes = NAT_N_NEXT,
4496 [NAT_NEXT_DROP] = "error-drop",
4497 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4498 [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4499 [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4500 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4501 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4502 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4503 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4504 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4510 * fd.io coding-style-patch-verification: ON
4513 * eval: (c-set-style "gnu")