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/nat64.h>
26 #include <nat/nat_inlines.h>
27 #include <nat/nat44/inlines.h>
28 #include <nat/nat_affinity.h>
29 #include <nat/nat_syslog.h>
30 #include <nat/nat_ha.h>
31 #include <vnet/fib/fib_table.h>
32 #include <vnet/fib/ip4_fib.h>
33 #include <vnet/ip/reass/ip4_sv_reass.h>
34 #include <vppinfra/bihash_16_8.h>
35 #include <nat/nat44/ed_inlines.h>
37 #include <vpp/app/version.h>
39 snat_main_t snat_main;
41 fib_source_t nat_fib_src_hi;
42 fib_source_t nat_fib_src_low;
45 /* Hook up input features */
46 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
47 .arc_name = "ip4-unicast",
48 .node_name = "nat-pre-in2out",
49 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
50 "ip4-sv-reassembly-feature"),
52 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
53 .arc_name = "ip4-unicast",
54 .node_name = "nat-pre-out2in",
55 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
56 "ip4-dhcp-client-detect",
57 "ip4-sv-reassembly-feature"),
59 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
60 .arc_name = "ip4-unicast",
61 .node_name = "nat44-in2out-worker-handoff",
62 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
64 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
65 .arc_name = "ip4-unicast",
66 .node_name = "nat44-out2in-worker-handoff",
67 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
68 "ip4-dhcp-client-detect"),
70 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
71 .arc_name = "ip4-unicast",
72 .node_name = "nat44-in2out",
73 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
75 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
76 .arc_name = "ip4-unicast",
77 .node_name = "nat44-out2in",
78 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
79 "ip4-dhcp-client-detect"),
81 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
82 .arc_name = "ip4-unicast",
83 .node_name = "nat44-classify",
84 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
86 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
87 .arc_name = "ip4-unicast",
88 .node_name = "nat44-ed-in2out",
89 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
91 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
92 .arc_name = "ip4-unicast",
93 .node_name = "nat44-ed-out2in",
94 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
95 "ip4-dhcp-client-detect"),
97 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
98 .arc_name = "ip4-unicast",
99 .node_name = "nat44-ed-classify",
100 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
102 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
103 .arc_name = "ip4-unicast",
104 .node_name = "nat44-handoff-classify",
105 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
107 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
108 .arc_name = "ip4-unicast",
109 .node_name = "nat44-in2out-fast",
110 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
112 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
113 .arc_name = "ip4-unicast",
114 .node_name = "nat44-out2in-fast",
115 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
116 "ip4-dhcp-client-detect"),
118 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
119 .arc_name = "ip4-unicast",
120 .node_name = "nat44-hairpin-dst",
121 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
123 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
124 .arc_name = "ip4-unicast",
125 .node_name = "nat44-ed-hairpin-dst",
126 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
129 /* Hook up output features */
130 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
131 .arc_name = "ip4-output",
132 .node_name = "nat44-in2out-output",
133 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
135 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
136 .arc_name = "ip4-output",
137 .node_name = "nat44-in2out-output-worker-handoff",
138 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
140 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
141 .arc_name = "ip4-output",
142 .node_name = "nat44-hairpin-src",
143 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
145 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
146 .arc_name = "ip4-output",
147 .node_name = "nat44-ed-in2out-output",
148 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
149 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
151 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
152 .arc_name = "ip4-output",
153 .node_name = "nat44-ed-hairpin-src",
154 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
155 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
158 /* Hook up ip4-local features */
159 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
161 .arc_name = "ip4-local",
162 .node_name = "nat44-hairpinning",
163 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
165 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
167 .arc_name = "ip4-local",
168 .node_name = "nat44-ed-hairpinning",
169 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
173 VLIB_PLUGIN_REGISTER () = {
174 .version = VPP_BUILD_VER,
175 .description = "Network Address Translation (NAT)",
180 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
183 clib_bihash_kv_8_8_t kv;
186 ip4_address_t *l_addr, *r_addr;
188 clib_bihash_kv_16_8_t ed_kv;
189 snat_main_per_thread_data_t *tsm =
190 vec_elt_at_index (sm->per_thread_data, thread_index);
192 if (is_fwd_bypass_session (s))
194 if (snat_is_unk_proto_session (s))
196 init_ed_k (&ed_kv, s->in2out.addr, 0, s->ext_host_addr, 0, 0,
201 l_port = s->in2out.port;
202 r_port = s->ext_host_port;
203 l_addr = &s->in2out.addr;
204 r_addr = &s->ext_host_addr;
205 proto = nat_proto_to_ip_proto (s->nat_proto);
206 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index,
209 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
210 nat_elog_warn ("in2out_ed key del failed");
214 /* session lookup tables */
215 if (is_ed_session (s))
217 if (is_affinity_sessions (s))
218 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
219 s->nat_proto, s->out2in.port);
220 l_addr = &s->out2in.addr;
221 r_addr = &s->ext_host_addr;
222 fib_index = s->out2in.fib_index;
223 if (snat_is_unk_proto_session (s))
225 proto = s->in2out.port;
231 proto = nat_proto_to_ip_proto (s->nat_proto);
232 l_port = s->out2in.port;
233 r_port = s->ext_host_port;
235 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
236 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
237 nat_elog_warn ("out2in_ed key del failed");
238 l_addr = &s->in2out.addr;
239 fib_index = s->in2out.fib_index;
240 if (!snat_is_unk_proto_session (s))
241 l_port = s->in2out.port;
242 if (is_twice_nat_session (s))
244 r_addr = &s->ext_host_nat_addr;
245 r_port = s->ext_host_nat_port;
247 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
248 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
249 nat_elog_warn ("in2out_ed key del failed");
252 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
253 &s->in2out.addr, s->in2out.port,
254 &s->ext_host_nat_addr, s->ext_host_nat_port,
255 &s->out2in.addr, s->out2in.port,
256 &s->ext_host_addr, s->ext_host_port,
257 s->nat_proto, is_twice_nat_session (s));
261 init_nat_i2o_k (&kv, s);
262 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
263 nat_elog_warn ("in2out key del failed");
264 init_nat_o2i_k (&kv, s);
265 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
266 nat_elog_warn ("out2in key del failed");
269 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
270 &s->in2out.addr, s->in2out.port,
271 &s->out2in.addr, s->out2in.port,
275 if (snat_is_unk_proto_session (s))
281 snat_ipfix_logging_nat44_ses_delete (thread_index,
282 s->in2out.addr.as_u32,
283 s->out2in.addr.as_u32,
287 s->in2out.fib_index);
289 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
290 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
294 /* Twice NAT address and port for external host */
295 if (is_twice_nat_session (s))
297 snat_free_outside_address_and_port (sm->twice_nat_addresses,
299 &s->ext_host_nat_addr,
300 s->ext_host_nat_port, s->nat_proto);
303 if (snat_is_session_static (s))
306 snat_free_outside_address_and_port (sm->addresses, thread_index,
307 &s->out2in.addr, s->out2in.port,
312 nat44_set_session_limit (u32 session_limit, u32 vrf_id)
314 snat_main_t *sm = &snat_main;
315 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
316 u32 len = vec_len (sm->max_translations_per_fib);
318 if (len <= fib_index)
320 vec_validate (sm->max_translations_per_fib, fib_index + 1);
322 for (; len < vec_len (sm->max_translations_per_fib); len++)
323 sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
326 sm->max_translations_per_fib[fib_index] = session_limit;
331 nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
332 u32 thread_index, u8 is_ha)
336 ip4_address_t *l_addr, *r_addr;
338 clib_bihash_kv_16_8_t ed_kv;
339 snat_main_per_thread_data_t *tsm =
340 vec_elt_at_index (sm->per_thread_data, thread_index);
342 if (is_fwd_bypass_session (s))
344 if (snat_is_unk_proto_session (s))
346 proto = s->in2out.port;
352 proto = nat_proto_to_ip_proto (s->nat_proto);
353 l_port = s->in2out.port;
354 r_port = s->ext_host_port;
357 l_addr = &s->in2out.addr;
358 r_addr = &s->ext_host_addr;
360 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
363 (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
364 nat_elog_warn ("in2out_ed key del failed");
368 /* session lookup tables */
369 if (is_affinity_sessions (s))
370 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
371 s->nat_proto, s->out2in.port);
372 l_addr = &s->out2in.addr;
373 r_addr = &s->ext_host_addr;
374 fib_index = s->out2in.fib_index;
375 if (snat_is_unk_proto_session (s))
377 proto = s->in2out.port;
383 proto = nat_proto_to_ip_proto (s->nat_proto);
384 l_port = s->out2in.port;
385 r_port = s->ext_host_port;
387 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
389 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0)))
390 nat_elog_warn ("out2in_ed key del failed");
392 l_addr = &s->in2out.addr;
393 fib_index = s->in2out.fib_index;
395 if (!snat_is_unk_proto_session (s))
396 l_port = s->in2out.port;
398 if (is_twice_nat_session (s))
400 r_addr = &s->ext_host_nat_addr;
401 r_port = s->ext_host_nat_port;
403 init_ed_k (&ed_kv, *l_addr, l_port, *r_addr, r_port, fib_index, proto);
405 if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
406 nat_elog_warn ("in2out_ed key del failed");
410 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
411 &s->in2out.addr, s->in2out.port,
412 &s->ext_host_nat_addr, s->ext_host_nat_port,
413 &s->out2in.addr, s->out2in.port,
414 &s->ext_host_addr, s->ext_host_port,
415 s->nat_proto, is_twice_nat_session (s));
418 if (snat_is_unk_proto_session (s))
423 snat_ipfix_logging_nat44_ses_delete (thread_index,
424 s->in2out.addr.as_u32,
425 s->out2in.addr.as_u32,
429 s->in2out.fib_index);
430 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
431 s->ext_host_port, s->nat_proto, s->out2in.fib_index,
435 /* Twice NAT address and port for external host */
436 if (is_twice_nat_session (s))
438 snat_free_outside_address_and_port (sm->twice_nat_addresses,
440 &s->ext_host_nat_addr,
441 s->ext_host_nat_port, s->nat_proto);
444 if (snat_is_session_static (s))
447 snat_free_outside_address_and_port (sm->addresses, thread_index,
448 &s->out2in.addr, s->out2in.port,
454 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
458 snat_user_key_t user_key;
459 clib_bihash_kv_8_8_t kv, value;
460 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
461 dlist_elt_t *per_user_list_head_elt;
463 user_key.addr.as_u32 = addr->as_u32;
464 user_key.fib_index = fib_index;
465 kv.key = user_key.as_u64;
467 /* Ever heard of the "user" = src ip4 address before? */
468 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
470 if (pool_elts (tsm->users) >= sm->max_users_per_thread)
472 vlib_increment_simple_counter (&sm->user_limit_reached,
474 nat_elog_warn ("maximum user limit reached");
477 /* no, make a new one */
478 pool_get (tsm->users, u);
479 clib_memset (u, 0, sizeof (*u));
481 u->addr.as_u32 = addr->as_u32;
482 u->fib_index = fib_index;
484 pool_get (tsm->list_pool, per_user_list_head_elt);
486 u->sessions_per_user_list_head_index = per_user_list_head_elt -
489 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
491 kv.value = u - tsm->users;
494 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
496 nat_elog_warn ("user_hash key add failed");
497 nat44_delete_user_with_no_session (sm, u, thread_index);
501 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
502 pool_elts (tsm->users));
506 u = pool_elt_at_index (tsm->users, value.value);
513 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
514 u32 thread_index, f64 now)
517 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
518 u32 oldest_per_user_translation_list_index, session_index;
519 dlist_elt_t *oldest_per_user_translation_list_elt;
520 dlist_elt_t *per_user_translation_list_elt;
522 /* Over quota? Recycle the least recently used translation */
523 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
525 oldest_per_user_translation_list_index =
526 clib_dlist_remove_head (tsm->list_pool,
527 u->sessions_per_user_list_head_index);
529 ASSERT (oldest_per_user_translation_list_index != ~0);
531 /* Add it back to the end of the LRU list */
532 clib_dlist_addtail (tsm->list_pool,
533 u->sessions_per_user_list_head_index,
534 oldest_per_user_translation_list_index);
535 /* Get the list element */
536 oldest_per_user_translation_list_elt =
537 pool_elt_at_index (tsm->list_pool,
538 oldest_per_user_translation_list_index);
540 /* Get the session index from the list element */
541 session_index = oldest_per_user_translation_list_elt->value;
543 /* Get the session */
544 s = pool_elt_at_index (tsm->sessions, session_index);
545 nat_free_session_data (sm, s, thread_index, 0);
546 if (snat_is_session_static (s))
547 u->nstaticsessions--;
554 s->ext_host_addr.as_u32 = 0;
555 s->ext_host_port = 0;
556 s->ext_host_nat_addr.as_u32 = 0;
557 s->ext_host_nat_port = 0;
561 pool_get (tsm->sessions, s);
562 clib_memset (s, 0, sizeof (*s));
564 /* Create list elts */
565 pool_get (tsm->list_pool, per_user_translation_list_elt);
566 clib_dlist_init (tsm->list_pool,
567 per_user_translation_list_elt - tsm->list_pool);
569 per_user_translation_list_elt->value = s - tsm->sessions;
570 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
571 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
573 clib_dlist_addtail (tsm->list_pool,
574 s->per_user_list_head_index,
575 per_user_translation_list_elt - tsm->list_pool);
577 s->user_index = u - tsm->users;
578 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
579 pool_elts (tsm->sessions));
582 s->ha_last_refreshed = now;
588 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
591 fib_prefix_t prefix = {
593 .fp_proto = FIB_PROTOCOL_IP4,
595 .ip4.as_u32 = addr->as_u32,
598 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
601 fib_table_entry_update_one_path (fib_index,
604 (FIB_ENTRY_FLAG_CONNECTED |
605 FIB_ENTRY_FLAG_LOCAL |
606 FIB_ENTRY_FLAG_EXCLUSIVE),
610 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
612 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
616 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
621 vlib_thread_main_t *tm = vlib_get_thread_main ();
623 if (twice_nat && !sm->endpoint_dependent)
624 return VNET_API_ERROR_FEATURE_DISABLED;
626 /* Check if address already exists */
628 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
630 if (ap->addr.as_u32 == addr->as_u32)
631 return VNET_API_ERROR_VALUE_EXIST;
636 vec_add2 (sm->twice_nat_addresses, ap, 1);
638 vec_add2 (sm->addresses, ap, 1);
643 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
647 #define _(N, i, n, s) \
648 clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
649 ap->busy_##n##_ports = 0; \
650 ap->busy_##n##_ports_per_thread = 0;\
651 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
657 /* Add external address to FIB */
659 pool_foreach (i, sm->interfaces,
661 if (nat_interface_is_inside(i) || sm->out2in_dpo)
664 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
667 pool_foreach (i, sm->output_feature_interfaces,
669 if (nat_interface_is_inside(i) || sm->out2in_dpo)
672 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
681 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
683 snat_static_mapping_t *m;
685 pool_foreach (m, sm->static_mappings,
687 if (is_addr_only_static_mapping (m) ||
688 is_out2in_only_static_mapping (m) ||
689 is_identity_static_mapping (m))
691 if (m->external_addr.as_u32 == addr.as_u32)
700 snat_add_static_mapping_when_resolved (snat_main_t * sm,
701 ip4_address_t l_addr,
706 nat_protocol_t proto,
707 int addr_only, int is_add, u8 * tag,
708 int twice_nat, int out2in_only,
711 snat_static_map_resolve_t *rp;
713 vec_add2 (sm->to_resolve, rp, 1);
714 rp->l_addr.as_u32 = l_addr.as_u32;
716 rp->sw_if_index = sw_if_index;
720 rp->addr_only = addr_only;
722 rp->twice_nat = twice_nat;
723 rp->out2in_only = out2in_only;
724 rp->identity_nat = identity_nat;
725 rp->tag = vec_dup (tag);
729 get_thread_idx_by_port (u16 e_port)
731 snat_main_t *sm = &snat_main;
732 u32 thread_idx = sm->num_workers;
733 if (sm->num_workers > 1)
736 sm->first_worker_index +
737 sm->workers[(e_port - 1024) / sm->port_per_thread];
743 snat_static_mapping_del_sessions (snat_main_t * sm,
744 snat_main_per_thread_data_t * tsm,
745 snat_user_key_t u_key, int addr_only,
746 ip4_address_t e_addr, u16 e_port)
748 clib_bihash_kv_8_8_t kv, value;
749 kv.key = u_key.as_u64;
751 dlist_elt_t *head, *elt;
754 u32 elt_index, head_index, ses_index;
755 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
757 user_index = value.value;
758 u = pool_elt_at_index (tsm->users, user_index);
759 if (u->nstaticsessions)
761 head_index = u->sessions_per_user_list_head_index;
762 head = pool_elt_at_index (tsm->list_pool, head_index);
763 elt_index = head->next;
764 elt = pool_elt_at_index (tsm->list_pool, elt_index);
765 ses_index = elt->value;
766 while (ses_index != ~0)
768 s = pool_elt_at_index (tsm->sessions, ses_index);
769 elt = pool_elt_at_index (tsm->list_pool, elt->next);
770 ses_index = elt->value;
774 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
775 (s->out2in.port != e_port))
779 if (is_lb_session (s))
782 if (!snat_is_session_static (s))
785 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
786 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
796 snat_ed_static_mapping_del_sessions (snat_main_t * sm,
797 snat_main_per_thread_data_t * tsm,
798 ip4_address_t l_addr,
801 u32 fib_index, int addr_only,
802 ip4_address_t e_addr, u16 e_port)
805 u32 *indexes_to_free = NULL;
807 pool_foreach (s, tsm->sessions, {
808 if (s->in2out.fib_index != fib_index ||
809 s->in2out.addr.as_u32 != l_addr.as_u32)
815 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
816 s->out2in.port != e_port ||
817 s->in2out.port != l_port ||
818 s->nat_proto != protocol)
822 if (is_lb_session (s))
824 if (!snat_is_session_static (s))
826 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
827 vec_add1 (indexes_to_free, s - tsm->sessions);
833 vec_foreach (ses_index, indexes_to_free)
835 s = pool_elt_at_index (tsm->sessions, *ses_index);
836 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
838 vec_free (indexes_to_free);
842 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
843 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
844 u32 sw_if_index, nat_protocol_t proto, int is_add,
845 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
848 snat_main_t *sm = &snat_main;
849 snat_static_mapping_t *m;
850 clib_bihash_kv_8_8_t kv, value;
851 snat_address_t *a = 0;
853 snat_interface_t *interface;
855 snat_main_per_thread_data_t *tsm;
856 snat_user_key_t u_key;
858 dlist_elt_t *head, *elt;
859 u32 elt_index, head_index;
863 snat_static_map_resolve_t *rp, *rp_match = 0;
864 nat44_lb_addr_port_t *local;
867 if (!sm->endpoint_dependent)
869 if (twice_nat || out2in_only)
870 return VNET_API_ERROR_FEATURE_DISABLED;
873 /* If the external address is a specific interface address */
874 if (sw_if_index != ~0)
876 ip4_address_t *first_int_addr;
878 for (i = 0; i < vec_len (sm->to_resolve); i++)
880 rp = sm->to_resolve + i;
881 if (rp->sw_if_index != sw_if_index ||
882 rp->l_addr.as_u32 != l_addr.as_u32 ||
883 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
888 if ((rp->l_port != l_port && rp->e_port != e_port)
889 || rp->proto != proto)
897 /* Might be already set... */
898 first_int_addr = ip4_interface_first_address
899 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
904 return VNET_API_ERROR_VALUE_EXIST;
906 snat_add_static_mapping_when_resolved
907 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
908 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
910 /* DHCP resolution required? */
911 if (first_int_addr == 0)
917 e_addr.as_u32 = first_int_addr->as_u32;
918 /* Identity mapping? */
919 if (l_addr.as_u32 == 0)
920 l_addr.as_u32 = e_addr.as_u32;
926 return VNET_API_ERROR_NO_SUCH_ENTRY;
928 vec_del1 (sm->to_resolve, i);
932 e_addr.as_u32 = first_int_addr->as_u32;
933 /* Identity mapping? */
934 if (l_addr.as_u32 == 0)
935 l_addr.as_u32 = e_addr.as_u32;
942 init_nat_k (&kv, e_addr, addr_only ? 0 : e_port, 0, addr_only ? 0 : proto);
943 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
946 m = pool_elt_at_index (sm->static_mappings, value.value);
952 if (is_identity_static_mapping (m))
955 pool_foreach (local, m->locals,
957 if (local->vrf_id == vrf_id)
958 return VNET_API_ERROR_VALUE_EXIST;
961 pool_get (m->locals, local);
962 local->vrf_id = vrf_id;
964 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
966 init_nat_kv (&kv, m->local_addr, m->local_port,
967 local->fib_index, m->proto,
968 m - sm->static_mappings);
969 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
973 return VNET_API_ERROR_VALUE_EXIST;
976 if (twice_nat && addr_only)
977 return VNET_API_ERROR_UNSUPPORTED;
979 /* Convert VRF id to FIB index */
982 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
984 /* If not specified use inside VRF id from SNAT plugin startup config */
987 fib_index = sm->inside_fib_index;
988 vrf_id = sm->inside_vrf_id;
989 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
992 if (!(out2in_only || identity_nat))
994 init_nat_k (&kv, l_addr, addr_only ? 0 : l_port, fib_index,
995 addr_only ? 0 : proto);
996 if (!clib_bihash_search_8_8
997 (&sm->static_mapping_by_local, &kv, &value))
998 return VNET_API_ERROR_VALUE_EXIST;
1001 /* Find external address in allocated addresses and reserve port for
1002 address and port pair mapping when dynamic translations enabled */
1003 if (!(addr_only || sm->static_mapping_only || out2in_only))
1005 for (i = 0; i < vec_len (sm->addresses); i++)
1007 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1009 a = sm->addresses + i;
1010 /* External port must be unused */
1013 #define _(N, j, n, s) \
1014 case NAT_PROTOCOL_##N: \
1015 if (a->busy_##n##_port_refcounts[e_port]) \
1016 return VNET_API_ERROR_INVALID_VALUE; \
1017 ++a->busy_##n##_port_refcounts[e_port]; \
1018 if (e_port > 1024) \
1020 a->busy_##n##_ports++; \
1021 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1024 foreach_nat_protocol
1027 nat_elog_info ("unknown protocol");
1028 return VNET_API_ERROR_INVALID_VALUE_2;
1033 /* External address must be allocated */
1034 if (!a && (l_addr.as_u32 != e_addr.as_u32))
1036 if (sw_if_index != ~0)
1038 for (i = 0; i < vec_len (sm->to_resolve); i++)
1040 rp = sm->to_resolve + i;
1043 if (rp->sw_if_index != sw_if_index &&
1044 rp->l_addr.as_u32 != l_addr.as_u32 &&
1045 rp->vrf_id != vrf_id && rp->l_port != l_port &&
1046 rp->e_port != e_port && rp->proto != proto)
1049 vec_del1 (sm->to_resolve, i);
1053 return VNET_API_ERROR_NO_SUCH_ENTRY;
1057 pool_get (sm->static_mappings, m);
1058 clib_memset (m, 0, sizeof (*m));
1059 m->tag = vec_dup (tag);
1060 m->local_addr = l_addr;
1061 m->external_addr = e_addr;
1062 m->twice_nat = twice_nat;
1064 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1066 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
1069 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
1070 pool_get (m->locals, local);
1071 local->vrf_id = vrf_id;
1072 local->fib_index = fib_index;
1077 m->fib_index = fib_index;
1081 m->local_port = l_port;
1082 m->external_port = e_port;
1086 if (sm->num_workers > 1)
1089 .src_address = m->local_addr,
1091 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
1092 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1095 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1097 init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto,
1098 m - sm->static_mappings);
1100 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1102 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto,
1103 m - sm->static_mappings);
1104 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
1106 /* Delete dynamic sessions matching local address (+ local port) */
1107 if (!(sm->static_mapping_only))
1109 u_key.addr = m->local_addr;
1110 u_key.fib_index = m->fib_index;
1111 kv.key = u_key.as_u64;
1112 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1114 user_index = value.value;
1115 u = pool_elt_at_index (tsm->users, user_index);
1118 head_index = u->sessions_per_user_list_head_index;
1119 head = pool_elt_at_index (tsm->list_pool, head_index);
1120 elt_index = head->next;
1121 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1122 ses_index = elt->value;
1123 while (ses_index != ~0)
1125 s = pool_elt_at_index (tsm->sessions, ses_index);
1126 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1127 ses_index = elt->value;
1129 if (snat_is_session_static (s))
1132 if (!addr_only && s->in2out.port != m->local_port)
1135 nat_free_session_data (sm, s,
1136 tsm - sm->per_thread_data, 0);
1137 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1139 if (!addr_only && !sm->endpoint_dependent)
1150 if (sw_if_index != ~0)
1153 return VNET_API_ERROR_NO_SUCH_ENTRY;
1159 vrf_id = sm->inside_vrf_id;
1162 pool_foreach (local, m->locals,
1164 if (local->vrf_id == vrf_id)
1165 find = local - m->locals;
1169 return VNET_API_ERROR_NO_SUCH_ENTRY;
1171 local = pool_elt_at_index (m->locals, find);
1172 fib_index = local->fib_index;
1173 pool_put (m->locals, local);
1176 fib_index = m->fib_index;
1178 /* Free external address port */
1179 if (!(addr_only || sm->static_mapping_only || out2in_only))
1181 for (i = 0; i < vec_len (sm->addresses); i++)
1183 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1185 a = sm->addresses + i;
1188 #define _(N, j, n, s) \
1189 case NAT_PROTOCOL_##N: \
1190 --a->busy_##n##_port_refcounts[e_port]; \
1191 if (e_port > 1024) \
1193 a->busy_##n##_ports--; \
1194 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1197 foreach_nat_protocol
1200 nat_elog_info ("unknown protocol");
1201 return VNET_API_ERROR_INVALID_VALUE_2;
1208 if (sm->num_workers > 1)
1209 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1211 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1213 init_nat_k (&kv, m->local_addr, m->local_port, fib_index, m->proto);
1215 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1217 /* Delete session(s) for static mapping if exist */
1218 if (!(sm->static_mapping_only) ||
1219 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1221 if (sm->endpoint_dependent)
1223 snat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr,
1224 m->local_port, m->proto,
1225 fib_index, addr_only,
1230 u_key.addr = m->local_addr;
1231 u_key.fib_index = fib_index;
1232 kv.key = u_key.as_u64;
1233 snat_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
1238 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1239 if (pool_elts (m->locals))
1242 init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1243 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1246 vec_free (m->workers);
1247 /* Delete static mapping from pool */
1248 pool_put (sm->static_mappings, m);
1251 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1254 /* Add/delete external address to FIB */
1256 pool_foreach (interface, sm->interfaces,
1258 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1261 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1264 pool_foreach (interface, sm->output_feature_interfaces,
1266 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1269 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1278 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1279 nat_protocol_t proto,
1280 nat44_lb_addr_port_t * locals, u8 is_add,
1281 twice_nat_type_t twice_nat, u8 out2in_only,
1282 u8 * tag, u32 affinity)
1284 snat_main_t *sm = &snat_main;
1285 snat_static_mapping_t *m;
1286 clib_bihash_kv_8_8_t kv, value;
1287 snat_address_t *a = 0;
1289 nat44_lb_addr_port_t *local;
1290 snat_main_per_thread_data_t *tsm;
1294 if (!sm->endpoint_dependent)
1295 return VNET_API_ERROR_FEATURE_DISABLED;
1297 init_nat_k (&kv, e_addr, e_port, 0, proto);
1298 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1301 m = pool_elt_at_index (sm->static_mappings, value.value);
1306 return VNET_API_ERROR_VALUE_EXIST;
1308 if (vec_len (locals) < 2)
1309 return VNET_API_ERROR_INVALID_VALUE;
1311 /* Find external address in allocated addresses and reserve port for
1312 address and port pair mapping when dynamic translations enabled */
1313 if (!(sm->static_mapping_only || out2in_only))
1315 for (i = 0; i < vec_len (sm->addresses); i++)
1317 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1319 a = sm->addresses + i;
1320 /* External port must be unused */
1323 #define _(N, j, n, s) \
1324 case NAT_PROTOCOL_##N: \
1325 if (a->busy_##n##_port_refcounts[e_port]) \
1326 return VNET_API_ERROR_INVALID_VALUE; \
1327 ++a->busy_##n##_port_refcounts[e_port]; \
1328 if (e_port > 1024) \
1330 a->busy_##n##_ports++; \
1331 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1334 foreach_nat_protocol
1337 nat_elog_info ("unknown protocol");
1338 return VNET_API_ERROR_INVALID_VALUE_2;
1343 /* External address must be allocated */
1345 return VNET_API_ERROR_NO_SUCH_ENTRY;
1348 pool_get (sm->static_mappings, m);
1349 clib_memset (m, 0, sizeof (*m));
1350 m->tag = vec_dup (tag);
1351 m->external_addr = e_addr;
1352 m->external_port = e_port;
1354 m->twice_nat = twice_nat;
1355 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1357 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1358 m->affinity = affinity;
1361 m->affinity_per_service_list_head_index =
1362 nat_affinity_get_per_service_list_head_index ();
1364 m->affinity_per_service_list_head_index = ~0;
1366 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto,
1367 m - sm->static_mappings);
1368 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1370 nat_elog_err ("static_mapping_by_external key add failed");
1371 return VNET_API_ERROR_UNSPECIFIED;
1374 for (i = 0; i < vec_len (locals); i++)
1376 locals[i].fib_index =
1377 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1382 init_nat_kv (&kv, locals[i].addr, locals[i].port,
1383 locals[i].fib_index, m->proto,
1384 m - sm->static_mappings);
1385 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1387 locals[i].prefix = (i == 0) ? locals[i].probability :
1388 (locals[i - 1].prefix + locals[i].probability);
1389 pool_get (m->locals, local);
1391 if (sm->num_workers > 1)
1394 .src_address = locals[i].addr,
1397 clib_bitmap_set (bitmap,
1398 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1403 /* Assign workers */
1404 if (sm->num_workers > 1)
1407 clib_bitmap_foreach (i, bitmap,
1409 vec_add1(m->workers, i);
1417 return VNET_API_ERROR_NO_SUCH_ENTRY;
1419 if (!is_lb_static_mapping (m))
1420 return VNET_API_ERROR_INVALID_VALUE;
1422 /* Free external address port */
1423 if (!(sm->static_mapping_only || out2in_only))
1425 for (i = 0; i < vec_len (sm->addresses); i++)
1427 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1429 a = sm->addresses + i;
1432 #define _(N, j, n, s) \
1433 case NAT_PROTOCOL_##N: \
1434 --a->busy_##n##_port_refcounts[e_port]; \
1435 if (e_port > 1024) \
1437 a->busy_##n##_ports--; \
1438 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1441 foreach_nat_protocol
1444 nat_elog_info ("unknown protocol");
1445 return VNET_API_ERROR_INVALID_VALUE_2;
1452 init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1453 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1455 nat_elog_err ("static_mapping_by_external key del failed");
1456 return VNET_API_ERROR_UNSPECIFIED;
1460 pool_foreach (local, m->locals,
1462 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1466 init_nat_k(& kv, local->addr, local->port, local->fib_index, m->proto);
1467 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1469 nat_elog_err ("static_mapping_by_local key del failed");
1470 return VNET_API_ERROR_UNSPECIFIED;
1474 if (sm->num_workers > 1)
1477 .src_address = local->addr,
1479 tsm = vec_elt_at_index (sm->per_thread_data,
1480 sm->worker_in2out_cb (&ip, m->fib_index, 0));
1483 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1485 /* Delete sessions */
1486 pool_foreach (s, tsm->sessions, {
1487 if (!(is_lb_session (s)))
1490 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1491 s->in2out.port != local->port)
1494 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1495 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1500 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1501 pool_free (m->locals);
1503 vec_free (m->workers);
1505 pool_put (sm->static_mappings, m);
1512 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1513 ip4_address_t l_addr, u16 l_port,
1514 nat_protocol_t proto, u32 vrf_id,
1515 u8 probability, u8 is_add)
1517 snat_main_t *sm = &snat_main;
1518 snat_static_mapping_t *m = 0;
1519 clib_bihash_kv_8_8_t kv, value;
1520 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1521 snat_main_per_thread_data_t *tsm;
1527 if (!sm->endpoint_dependent)
1528 return VNET_API_ERROR_FEATURE_DISABLED;
1530 init_nat_k (&kv, e_addr, e_port, 0, proto);
1531 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1532 m = pool_elt_at_index (sm->static_mappings, value.value);
1535 return VNET_API_ERROR_NO_SUCH_ENTRY;
1537 if (!is_lb_static_mapping (m))
1538 return VNET_API_ERROR_INVALID_VALUE;
1541 pool_foreach (local, m->locals,
1543 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1544 (local->vrf_id == vrf_id))
1546 match_local = local;
1555 return VNET_API_ERROR_VALUE_EXIST;
1557 pool_get (m->locals, local);
1558 clib_memset (local, 0, sizeof (*local));
1559 local->addr.as_u32 = l_addr.as_u32;
1560 local->port = l_port;
1561 local->probability = probability;
1562 local->vrf_id = vrf_id;
1564 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1567 if (!is_out2in_only_static_mapping (m))
1569 init_nat_kv (&kv, l_addr, l_port, local->fib_index, proto,
1570 m - sm->static_mappings);
1571 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1572 nat_elog_err ("static_mapping_by_local key add failed");
1578 return VNET_API_ERROR_NO_SUCH_ENTRY;
1580 if (pool_elts (m->locals) < 3)
1581 return VNET_API_ERROR_UNSPECIFIED;
1583 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1586 if (!is_out2in_only_static_mapping (m))
1588 init_nat_k (&kv, l_addr, l_port, match_local->fib_index, proto);
1589 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1590 nat_elog_err ("static_mapping_by_local key del failed");
1593 if (sm->num_workers > 1)
1596 .src_address = local->addr,
1598 tsm = vec_elt_at_index (sm->per_thread_data,
1599 sm->worker_in2out_cb (&ip, m->fib_index,
1603 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1605 /* Delete sessions */
1607 pool_foreach (s, tsm->sessions, {
1608 if (!(is_lb_session (s)))
1611 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1612 s->in2out.port != match_local->port)
1615 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1616 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1620 pool_put (m->locals, match_local);
1623 vec_free (m->workers);
1626 pool_foreach (local, m->locals,
1628 vec_add1 (locals, local - m->locals);
1629 if (sm->num_workers > 1)
1632 ip.src_address.as_u32 = local->addr.as_u32,
1633 bitmap = clib_bitmap_set (bitmap,
1634 sm->worker_in2out_cb (&ip, local->fib_index, 0),
1640 ASSERT (vec_len (locals) > 1);
1642 local = pool_elt_at_index (m->locals, locals[0]);
1643 local->prefix = local->probability;
1644 for (i = 1; i < vec_len (locals); i++)
1646 local = pool_elt_at_index (m->locals, locals[i]);
1647 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1648 local->prefix = local->probability + prev_local->prefix;
1651 /* Assign workers */
1652 if (sm->num_workers > 1)
1655 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1663 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1666 snat_address_t *a = 0;
1667 snat_session_t *ses;
1668 u32 *ses_to_be_removed = 0, *ses_index;
1669 snat_main_per_thread_data_t *tsm;
1670 snat_static_mapping_t *m;
1671 snat_interface_t *interface;
1673 snat_address_t *addresses =
1674 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1676 /* Find SNAT address */
1677 for (i = 0; i < vec_len (addresses); i++)
1679 if (addresses[i].addr.as_u32 == addr.as_u32)
1686 return VNET_API_ERROR_NO_SUCH_ENTRY;
1691 pool_foreach (m, sm->static_mappings,
1693 if (m->external_addr.as_u32 == addr.as_u32)
1694 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1695 m->local_port, m->external_port,
1696 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1697 m->proto, 0, m->twice_nat,
1698 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1704 /* Check if address is used in some static mapping */
1705 if (is_snat_address_used_in_static_mapping (sm, addr))
1707 nat_elog_notice ("address used in static mapping");
1708 return VNET_API_ERROR_UNSPECIFIED;
1712 if (a->fib_index != ~0)
1713 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1715 /* Delete sessions using address */
1716 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1719 vec_foreach (tsm, sm->per_thread_data)
1721 pool_foreach (ses, tsm->sessions, ({
1722 if (ses->out2in.addr.as_u32 == addr.as_u32)
1724 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1725 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1729 if (sm->endpoint_dependent){
1730 vec_foreach (ses_index, ses_to_be_removed)
1732 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1733 nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1);
1736 vec_foreach (ses_index, ses_to_be_removed)
1738 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1739 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1743 vec_free (ses_to_be_removed);
1748 #define _(N, i, n, s) \
1749 vec_free (a->busy_##n##_ports_per_thread);
1750 foreach_nat_protocol
1754 vec_del1 (sm->twice_nat_addresses, i);
1758 vec_del1 (sm->addresses, i);
1760 /* Delete external address from FIB */
1762 pool_foreach (interface, sm->interfaces,
1764 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1767 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1770 pool_foreach (interface, sm->output_feature_interfaces,
1772 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1775 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1784 nat_validate_counters (snat_main_t * sm, u32 sw_if_index)
1787 vlib_validate_simple_counter (&sm->counters.fastpath.in2out.x, \
1789 vlib_zero_simple_counter (&sm->counters.fastpath.in2out.x, sw_if_index); \
1790 vlib_validate_simple_counter (&sm->counters.fastpath.out2in.x, \
1792 vlib_zero_simple_counter (&sm->counters.fastpath.out2in.x, sw_if_index); \
1793 vlib_validate_simple_counter (&sm->counters.slowpath.in2out.x, \
1795 vlib_zero_simple_counter (&sm->counters.slowpath.in2out.x, sw_if_index); \
1796 vlib_validate_simple_counter (&sm->counters.slowpath.out2in.x, \
1798 vlib_zero_simple_counter (&sm->counters.slowpath.out2in.x, sw_if_index); \
1799 vlib_validate_simple_counter (&sm->counters.fastpath.in2out_ed.x, \
1801 vlib_zero_simple_counter (&sm->counters.fastpath.in2out_ed.x, sw_if_index); \
1802 vlib_validate_simple_counter (&sm->counters.fastpath.out2in_ed.x, \
1804 vlib_zero_simple_counter (&sm->counters.fastpath.out2in_ed.x, sw_if_index); \
1805 vlib_validate_simple_counter (&sm->counters.slowpath.in2out_ed.x, \
1807 vlib_zero_simple_counter (&sm->counters.slowpath.in2out_ed.x, sw_if_index); \
1808 vlib_validate_simple_counter (&sm->counters.slowpath.out2in_ed.x, \
1810 vlib_zero_simple_counter (&sm->counters.slowpath.out2in_ed.x, sw_if_index);
1811 foreach_nat_counter;
1813 vlib_validate_simple_counter (&sm->counters.hairpinning, sw_if_index);
1814 vlib_zero_simple_counter (&sm->counters.hairpinning, sw_if_index);
1818 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1820 snat_main_t *sm = &snat_main;
1821 snat_interface_t *i;
1822 const char *feature_name, *del_feature_name;
1824 snat_static_mapping_t *m;
1825 nat_outside_fib_t *outside_fib;
1826 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1829 if (sm->out2in_dpo && !is_inside)
1830 return VNET_API_ERROR_UNSUPPORTED;
1833 pool_foreach (i, sm->output_feature_interfaces,
1835 if (i->sw_if_index == sw_if_index)
1836 return VNET_API_ERROR_VALUE_EXIST;
1840 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1841 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1844 if (sm->num_workers > 1)
1846 is_inside ? "nat44-in2out-worker-handoff" :
1847 "nat44-out2in-worker-handoff";
1848 else if (sm->endpoint_dependent)
1850 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1853 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1856 if (sm->fq_in2out_index == ~0 && sm->num_workers > 1)
1857 sm->fq_in2out_index =
1858 vlib_frame_queue_main_init (sm->in2out_node_index, NAT_FQ_NELTS);
1860 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1861 sm->fq_out2in_index =
1862 vlib_frame_queue_main_init (sm->out2in_node_index, NAT_FQ_NELTS);
1867 vec_foreach (outside_fib, sm->outside_fibs)
1869 if (outside_fib->fib_index == fib_index)
1873 outside_fib->refcount--;
1874 if (!outside_fib->refcount)
1875 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1878 outside_fib->refcount++;
1885 vec_add2 (sm->outside_fibs, outside_fib, 1);
1886 outside_fib->refcount = 1;
1887 outside_fib->fib_index = fib_index;
1892 pool_foreach (i, sm->interfaces,
1894 if (i->sw_if_index == sw_if_index)
1898 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1901 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1903 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1905 if (sm->num_workers > 1)
1907 del_feature_name = "nat44-handoff-classify";
1908 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1909 "nat44-out2in-worker-handoff";
1911 else if (sm->endpoint_dependent)
1913 del_feature_name = "nat44-ed-classify";
1914 feature_name = !is_inside ? "nat-pre-in2out" :
1919 del_feature_name = "nat44-classify";
1920 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1923 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1926 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1927 sw_if_index, 0, 0, 0);
1928 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1929 sw_if_index, 1, 0, 0);
1932 if (sm->endpoint_dependent)
1933 vnet_feature_enable_disable ("ip4-local",
1934 "nat44-ed-hairpinning",
1935 sw_if_index, 1, 0, 0);
1937 vnet_feature_enable_disable ("ip4-local",
1938 "nat44-hairpinning",
1939 sw_if_index, 1, 0, 0);
1944 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1947 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1948 sw_if_index, 0, 0, 0);
1949 pool_put (sm->interfaces, i);
1952 if (sm->endpoint_dependent)
1953 vnet_feature_enable_disable ("ip4-local",
1954 "nat44-ed-hairpinning",
1955 sw_if_index, 0, 0, 0);
1957 vnet_feature_enable_disable ("ip4-local",
1958 "nat44-hairpinning",
1959 sw_if_index, 0, 0, 0);
1965 if ((nat_interface_is_inside(i) && is_inside) ||
1966 (nat_interface_is_outside(i) && !is_inside))
1969 if (sm->num_workers > 1)
1971 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1972 "nat44-out2in-worker-handoff";
1973 feature_name = "nat44-handoff-classify";
1975 else if (sm->endpoint_dependent)
1977 del_feature_name = !is_inside ? "nat-pre-in2out" :
1980 feature_name = "nat44-ed-classify";
1984 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1985 feature_name = "nat44-classify";
1988 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1991 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1992 sw_if_index, 0, 0, 0);
1993 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1994 sw_if_index, 1, 0, 0);
1997 if (sm->endpoint_dependent)
1998 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1999 sw_if_index, 0, 0, 0);
2001 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2002 sw_if_index, 0, 0, 0);
2013 return VNET_API_ERROR_NO_SUCH_ENTRY;
2015 pool_get (sm->interfaces, i);
2016 i->sw_if_index = sw_if_index;
2018 nat_validate_counters (sm, sw_if_index);
2020 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
2023 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2027 if (is_inside && !sm->out2in_dpo)
2029 if (sm->endpoint_dependent)
2030 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2031 sw_if_index, 1, 0, 0);
2033 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2034 sw_if_index, 1, 0, 0);
2040 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2044 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2046 /* Add/delete external addresses to FIB */
2049 vec_foreach (ap, sm->addresses)
2050 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2052 pool_foreach (m, sm->static_mappings,
2054 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2057 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2065 snat_interface_add_del_output_feature (u32 sw_if_index,
2066 u8 is_inside, int is_del)
2068 snat_main_t *sm = &snat_main;
2069 snat_interface_t *i;
2071 snat_static_mapping_t *m;
2072 nat_outside_fib_t *outside_fib;
2073 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2077 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2078 return VNET_API_ERROR_UNSUPPORTED;
2081 pool_foreach (i, sm->interfaces,
2083 if (i->sw_if_index == sw_if_index)
2084 return VNET_API_ERROR_VALUE_EXIST;
2091 vec_foreach (outside_fib, sm->outside_fibs)
2093 if (outside_fib->fib_index == fib_index)
2097 outside_fib->refcount--;
2098 if (!outside_fib->refcount)
2099 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2102 outside_fib->refcount++;
2109 vec_add2 (sm->outside_fibs, outside_fib, 1);
2110 outside_fib->refcount = 1;
2111 outside_fib->fib_index = fib_index;
2118 if (sm->endpoint_dependent)
2121 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2125 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2129 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2130 sw_if_index, !is_del, 0, 0);
2131 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2132 sw_if_index, !is_del, 0, 0);
2137 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2141 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2145 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2146 sw_if_index, !is_del, 0, 0);
2147 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2148 sw_if_index, !is_del, 0, 0);
2153 if (sm->num_workers > 1)
2155 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2159 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2162 vnet_feature_enable_disable ("ip4-unicast",
2163 "nat44-out2in-worker-handoff",
2164 sw_if_index, !is_del, 0, 0);
2165 vnet_feature_enable_disable ("ip4-output",
2166 "nat44-in2out-output-worker-handoff",
2167 sw_if_index, !is_del, 0, 0);
2171 if (sm->endpoint_dependent)
2174 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2178 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2182 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2183 sw_if_index, !is_del, 0, 0);
2184 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2185 sw_if_index, !is_del, 0, 0);
2190 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2194 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2198 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2199 sw_if_index, !is_del, 0, 0);
2200 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2201 sw_if_index, !is_del, 0, 0);
2206 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2207 sm->fq_in2out_output_index =
2208 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
2210 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2211 sm->fq_out2in_index =
2212 vlib_frame_queue_main_init (sm->out2in_node_index, 0);
2215 pool_foreach (i, sm->output_feature_interfaces,
2217 if (i->sw_if_index == sw_if_index)
2220 pool_put (sm->output_feature_interfaces, i);
2222 return VNET_API_ERROR_VALUE_EXIST;
2230 return VNET_API_ERROR_NO_SUCH_ENTRY;
2232 pool_get (sm->output_feature_interfaces, i);
2233 i->sw_if_index = sw_if_index;
2235 nat_validate_counters (sm, sw_if_index);
2237 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2239 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2241 /* Add/delete external addresses to FIB */
2247 vec_foreach (ap, sm->addresses)
2248 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2250 pool_foreach (m, sm->static_mappings,
2252 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2255 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2263 snat_set_workers (uword * bitmap)
2265 snat_main_t *sm = &snat_main;
2268 if (sm->num_workers < 2)
2269 return VNET_API_ERROR_FEATURE_DISABLED;
2271 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2272 return VNET_API_ERROR_INVALID_WORKER;
2274 vec_free (sm->workers);
2276 clib_bitmap_foreach (i, bitmap,
2278 vec_add1(sm->workers, i);
2279 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2280 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2285 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2291 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2294 snat_main_t *sm = &snat_main;
2295 nat_outside_fib_t *outside_fib;
2296 snat_interface_t *i;
2300 if (new_fib_index == old_fib_index)
2303 if (!vec_len (sm->outside_fibs))
2307 pool_foreach (i, sm->interfaces,
2309 if (i->sw_if_index == sw_if_index)
2311 if (!(nat_interface_is_outside (i)))
2317 pool_foreach (i, sm->output_feature_interfaces,
2319 if (i->sw_if_index == sw_if_index)
2321 if (!(nat_interface_is_outside (i)))
2331 vec_foreach (outside_fib, sm->outside_fibs)
2333 if (outside_fib->fib_index == old_fib_index)
2335 outside_fib->refcount--;
2336 if (!outside_fib->refcount)
2337 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2342 vec_foreach (outside_fib, sm->outside_fibs)
2344 if (outside_fib->fib_index == new_fib_index)
2346 outside_fib->refcount++;
2354 vec_add2 (sm->outside_fibs, outside_fib, 1);
2355 outside_fib->refcount = 1;
2356 outside_fib->fib_index = new_fib_index;
2361 snat_ip4_table_bind (ip4_main_t * im,
2363 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2365 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2369 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2372 ip4_address_t * address,
2374 u32 if_address_index, u32 is_delete);
2377 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2380 ip4_address_t * address,
2382 u32 if_address_index, u32 is_delete);
2385 nat_alloc_addr_and_port_default (snat_address_t * addresses, u32 fib_index,
2386 u32 thread_index, nat_protocol_t proto,
2387 ip4_address_t * addr, u16 * port,
2388 u16 port_per_thread, u32 snat_thread_index);
2391 test_key_calc_split ()
2393 ip4_address_t l_addr;
2394 l_addr.as_u8[0] = 1;
2395 l_addr.as_u8[1] = 1;
2396 l_addr.as_u8[2] = 1;
2397 l_addr.as_u8[3] = 1;
2398 ip4_address_t r_addr;
2399 r_addr.as_u8[0] = 2;
2400 r_addr.as_u8[1] = 2;
2401 r_addr.as_u8[2] = 2;
2402 r_addr.as_u8[3] = 2;
2406 u32 fib_index = 9000001;
2407 u32 thread_index = 3000000001;
2408 u32 session_index = 3000000221;
2409 clib_bihash_kv_16_8_t kv;
2410 init_ed_kv (&kv, l_addr, l_port, r_addr, r_port, fib_index, proto,
2411 thread_index, session_index);
2412 ip4_address_t l_addr2;
2413 ip4_address_t r_addr2;
2414 clib_memset (&l_addr2, 0, sizeof (l_addr2));
2415 clib_memset (&r_addr2, 0, sizeof (r_addr2));
2420 split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
2422 ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2423 ASSERT (r_addr.as_u32 == r_addr2.as_u32);
2424 ASSERT (l_port == l_port2);
2425 ASSERT (r_port == r_port2);
2426 ASSERT (proto == proto2);
2427 ASSERT (fib_index == fib_index2);
2428 ASSERT (thread_index == ed_value_get_thread_index (&kv));
2429 ASSERT (session_index == ed_value_get_session_index (&kv));
2433 nat_protocol_t proto3 = ~0;
2434 u64 key = calc_nat_key (l_addr, l_port, fib_index, proto);
2435 split_nat_key (key, &l_addr2, &l_port2, &fib_index2, &proto3);
2436 ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2437 ASSERT (l_port == l_port2);
2438 ASSERT (proto == proto3);
2439 ASSERT (fib_index == fib_index2);
2442 static clib_error_t *
2443 snat_init (vlib_main_t * vm)
2445 snat_main_t *sm = &snat_main;
2446 clib_error_t *error = 0;
2447 ip4_main_t *im = &ip4_main;
2448 ip_lookup_main_t *lm = &im->lookup_main;
2450 vlib_thread_registration_t *tr;
2451 vlib_thread_main_t *tm = vlib_get_thread_main ();
2454 ip4_add_del_interface_address_callback_t cb4;
2457 sm->vnet_main = vnet_get_main ();
2459 sm->ip4_lookup_main = lm;
2460 sm->api_main = vlibapi_get_main ();
2461 sm->first_worker_index = 0;
2462 sm->num_workers = 0;
2464 sm->port_per_thread = 0xffff - 1024;
2465 sm->fq_in2out_index = ~0;
2466 sm->fq_in2out_output_index = ~0;
2467 sm->fq_out2in_index = ~0;
2469 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2470 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2471 sm->forwarding_enabled = 0;
2472 sm->log_class = vlib_log_register_class ("nat", 0);
2473 sm->log_level = SNAT_LOG_ERROR;
2474 sm->mss_clamping = 0;
2476 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2477 sm->error_node_index = node->index;
2479 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2480 sm->pre_in2out_node_index = node->index;
2481 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2482 sm->pre_out2in_node_index = node->index;
2484 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2485 sm->pre_in2out_node_index = node->index;
2487 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2488 sm->pre_out2in_node_index = node->index;
2490 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2491 sm->in2out_node_index = node->index;
2492 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2493 sm->in2out_output_node_index = node->index;
2494 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2495 sm->in2out_fast_node_index = node->index;
2496 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2497 sm->in2out_slowpath_node_index = node->index;
2498 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2499 sm->in2out_slowpath_output_node_index = node->index;
2501 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2502 sm->ed_in2out_node_index = node->index;
2503 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2504 sm->ed_in2out_slowpath_node_index = node->index;
2506 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2507 sm->out2in_node_index = node->index;
2508 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2509 sm->out2in_fast_node_index = node->index;
2511 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2512 sm->ed_out2in_node_index = node->index;
2513 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2514 sm->ed_out2in_slowpath_node_index = node->index;
2516 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2517 sm->hairpinning_node_index = node->index;
2518 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2519 sm->hairpin_dst_node_index = node->index;
2520 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2521 sm->hairpin_src_node_index = node->index;
2522 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2523 sm->ed_hairpinning_node_index = node->index;
2524 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2525 sm->ed_hairpin_dst_node_index = node->index;
2526 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2527 sm->ed_hairpin_src_node_index = node->index;
2529 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2532 tr = (vlib_thread_registration_t *) p[0];
2535 sm->num_workers = tr->count;
2536 sm->first_worker_index = tr->first_index;
2540 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2542 /* Use all available workers by default */
2543 if (sm->num_workers > 1)
2545 for (i = 0; i < sm->num_workers; i++)
2546 bitmap = clib_bitmap_set (bitmap, i, 1);
2547 snat_set_workers (bitmap);
2548 clib_bitmap_free (bitmap);
2552 sm->per_thread_data[0].snat_thread_index = 0;
2555 error = snat_api_init (vm, sm);
2559 /* Set up the interface address add/del callback */
2560 cb4.function = snat_ip4_add_del_interface_address_cb;
2561 cb4.function_opaque = 0;
2563 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2565 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2566 cb4.function_opaque = 0;
2568 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2570 nat_dpo_module_init ();
2573 sm->total_users.name = "total-users";
2574 sm->total_users.stat_segment_name = "/nat44/total-users";
2575 vlib_validate_simple_counter (&sm->total_users, 0);
2576 vlib_zero_simple_counter (&sm->total_users, 0);
2577 sm->total_sessions.name = "total-sessions";
2578 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2579 vlib_validate_simple_counter (&sm->total_sessions, 0);
2580 vlib_zero_simple_counter (&sm->total_sessions, 0);
2581 sm->user_limit_reached.name = "user-limit-reached";
2582 sm->user_limit_reached.stat_segment_name = "/nat44/user-limit-reached";
2583 vlib_validate_simple_counter (&sm->user_limit_reached, 0);
2584 vlib_zero_simple_counter (&sm->user_limit_reached, 0);
2587 sm->counters.fastpath.in2out.x.name = #x; \
2588 sm->counters.fastpath.in2out.x.stat_segment_name = \
2589 "/nat44/in2out/fastpath/" #x; \
2590 sm->counters.slowpath.in2out.x.name = #x; \
2591 sm->counters.slowpath.in2out.x.stat_segment_name = \
2592 "/nat44/in2out/slowpath/" #x; \
2593 sm->counters.fastpath.out2in.x.name = #x; \
2594 sm->counters.fastpath.out2in.x.stat_segment_name = \
2595 "/nat44/out2in/fastpath/" #x; \
2596 sm->counters.slowpath.out2in.x.name = #x; \
2597 sm->counters.slowpath.out2in.x.stat_segment_name = \
2598 "/nat44/out2in/slowpath/" #x; \
2599 sm->counters.fastpath.in2out_ed.x.name = #x; \
2600 sm->counters.fastpath.in2out_ed.x.stat_segment_name = \
2601 "/nat44/ed/in2out/fastpath/" #x; \
2602 sm->counters.slowpath.in2out_ed.x.name = #x; \
2603 sm->counters.slowpath.in2out_ed.x.stat_segment_name = \
2604 "/nat44/ed/in2out/slowpath/" #x; \
2605 sm->counters.fastpath.out2in_ed.x.name = #x; \
2606 sm->counters.fastpath.out2in_ed.x.stat_segment_name = \
2607 "/nat44/ed/out2in/fastpath/" #x; \
2608 sm->counters.slowpath.out2in_ed.x.name = #x; \
2609 sm->counters.slowpath.out2in_ed.x.stat_segment_name = \
2610 "/nat44/ed/out2in/slowpath/" #x;
2611 foreach_nat_counter;
2613 sm->counters.hairpinning.name = "hairpinning";
2614 sm->counters.hairpinning.stat_segment_name = "/nat44/hairpinning";
2616 /* Init IPFIX logging */
2617 snat_ipfix_logging_init (vm);
2620 error = nat64_init (vm);
2624 ip4_table_bind_callback_t cbt4 = {
2625 .function = snat_ip4_table_bind,
2627 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2629 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2630 FIB_SOURCE_PRIORITY_HI,
2631 FIB_SOURCE_BH_SIMPLE);
2632 nat_fib_src_low = fib_source_allocate ("nat-low",
2633 FIB_SOURCE_PRIORITY_LOW,
2634 FIB_SOURCE_BH_SIMPLE);
2636 test_key_calc_split ();
2640 VLIB_INIT_FUNCTION (snat_init);
2643 snat_free_outside_address_and_port (snat_address_t * addresses,
2645 ip4_address_t * addr,
2646 u16 port, nat_protocol_t protocol)
2650 u16 port_host_byte_order = clib_net_to_host_u16 (port);
2652 for (address_index = 0; address_index < vec_len (addresses);
2655 if (addresses[address_index].addr.as_u32 == addr->as_u32)
2659 ASSERT (address_index < vec_len (addresses));
2661 a = addresses + address_index;
2665 #define _(N, i, n, s) \
2666 case NAT_PROTOCOL_##N: \
2667 ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2668 --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2669 a->busy_##n##_ports--; \
2670 a->busy_##n##_ports_per_thread[thread_index]--; \
2672 foreach_nat_protocol
2675 nat_elog_info ("unknown protocol");
2681 nat_set_outside_address_and_port (snat_address_t * addresses,
2682 u32 thread_index, ip4_address_t addr,
2683 u16 port, nat_protocol_t protocol)
2685 snat_address_t *a = 0;
2687 u16 port_host_byte_order = clib_net_to_host_u16 (port);
2689 for (address_index = 0; address_index < vec_len (addresses);
2692 if (addresses[address_index].addr.as_u32 != addr.as_u32)
2695 a = addresses + address_index;
2698 #define _(N, j, n, s) \
2699 case NAT_PROTOCOL_##N: \
2700 if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
2701 return VNET_API_ERROR_INSTANCE_IN_USE; \
2702 ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
2703 a->busy_##n##_ports_per_thread[thread_index]++; \
2704 a->busy_##n##_ports++; \
2706 foreach_nat_protocol
2709 nat_elog_info ("unknown protocol");
2714 return VNET_API_ERROR_NO_SUCH_ENTRY;
2718 snat_static_mapping_match (snat_main_t * sm,
2719 ip4_address_t match_addr,
2721 u32 match_fib_index,
2722 nat_protocol_t match_protocol,
2723 ip4_address_t * mapping_addr,
2725 u32 * mapping_fib_index,
2728 twice_nat_type_t * twice_nat,
2729 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2730 u8 * is_identity_nat)
2732 clib_bihash_kv_8_8_t kv, value;
2733 snat_static_mapping_t *m;
2734 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2735 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2737 nat44_lb_addr_port_t *local;
2741 mapping_hash = &sm->static_mapping_by_external;
2742 init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
2743 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2745 /* Try address only mapping */
2746 init_nat_k (&kv, match_addr, 0, 0, 0);
2747 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2754 init_nat_k (&kv, match_addr, match_port, match_fib_index,
2756 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2758 /* Try address only mapping */
2759 init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
2760 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2766 m = pool_elt_at_index (sm->static_mappings, value.value);
2770 if (is_lb_static_mapping (m))
2772 if (PREDICT_FALSE (lb != 0))
2773 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2774 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2780 local = pool_elt_at_index (m->locals, backend_index);
2781 *mapping_addr = local->addr;
2782 *mapping_port = local->port;
2783 *mapping_fib_index = local->fib_index;
2786 // pick locals matching this worker
2787 if (PREDICT_FALSE (sm->num_workers > 1))
2789 u32 thread_index = vlib_get_thread_index ();
2791 pool_foreach_index (i, m->locals,
2793 local = pool_elt_at_index (m->locals, i);
2796 .src_address = local->addr,
2799 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2806 ASSERT (vec_len (tmp) != 0);
2811 pool_foreach_index (i, m->locals,
2817 hi = vec_len (tmp) - 1;
2818 local = pool_elt_at_index (m->locals, tmp[hi]);
2819 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2822 mid = ((hi - lo) >> 1) + lo;
2823 local = pool_elt_at_index (m->locals, tmp[mid]);
2824 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2826 local = pool_elt_at_index (m->locals, tmp[lo]);
2827 if (!(local->prefix >= rand))
2829 *mapping_addr = local->addr;
2830 *mapping_port = local->port;
2831 *mapping_fib_index = local->fib_index;
2834 if (nat_affinity_create_and_lock (ext_host_addr[0], match_addr,
2835 match_protocol, match_port,
2836 tmp[lo], m->affinity,
2837 m->affinity_per_service_list_head_index))
2838 nat_elog_info ("create affinity record failed");
2844 if (PREDICT_FALSE (lb != 0))
2846 *mapping_fib_index = m->fib_index;
2847 *mapping_addr = m->local_addr;
2848 /* Address only mapping doesn't change port */
2849 *mapping_port = is_addr_only_static_mapping (m) ? match_port
2855 *mapping_addr = m->external_addr;
2856 /* Address only mapping doesn't change port */
2857 *mapping_port = is_addr_only_static_mapping (m) ? match_port
2859 *mapping_fib_index = sm->outside_fib_index;
2863 if (PREDICT_FALSE (is_addr_only != 0))
2864 *is_addr_only = is_addr_only_static_mapping (m);
2866 if (PREDICT_FALSE (twice_nat != 0))
2867 *twice_nat = m->twice_nat;
2869 if (PREDICT_FALSE (is_identity_nat != 0))
2870 *is_identity_nat = is_identity_static_mapping (m);
2876 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2879 nat_protocol_t proto,
2880 ip4_address_t * addr,
2882 u16 port_per_thread,
2883 u32 snat_thread_index)
2885 snat_main_t *sm = &snat_main;
2887 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, proto,
2888 addr, port, port_per_thread,
2893 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2896 nat_protocol_t proto,
2897 ip4_address_t * addr,
2899 u16 port_per_thread, u32 snat_thread_index)
2902 snat_address_t *a, *ga = 0;
2905 for (i = 0; i < vec_len (addresses); i++)
2910 #define _(N, j, n, s) \
2911 case NAT_PROTOCOL_##N: \
2912 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2914 if (a->fib_index == fib_index) \
2918 portnum = (port_per_thread * \
2919 snat_thread_index) + \
2920 snat_random_port(0, port_per_thread - 1) + 1024; \
2921 if (a->busy_##n##_port_refcounts[portnum]) \
2923 --a->busy_##n##_port_refcounts[portnum]; \
2924 a->busy_##n##_ports_per_thread[thread_index]++; \
2925 a->busy_##n##_ports++; \
2927 *port = clib_host_to_net_u16(portnum); \
2931 else if (a->fib_index == ~0) \
2937 foreach_nat_protocol
2940 nat_elog_info ("unknown protocol");
2951 #define _(N, j, n, s) \
2952 case NAT_PROTOCOL_##N: \
2955 portnum = (port_per_thread * \
2956 snat_thread_index) + \
2957 snat_random_port(0, port_per_thread - 1) + 1024; \
2958 if (a->busy_##n##_port_refcounts[portnum]) \
2960 ++a->busy_##n##_port_refcounts[portnum]; \
2961 a->busy_##n##_ports_per_thread[thread_index]++; \
2962 a->busy_##n##_ports++; \
2964 *port = clib_host_to_net_u16(portnum); \
2968 foreach_nat_protocol
2971 nat_elog_info ("unknown protocol");
2976 /* Totally out of translations to use... */
2977 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2982 nat_alloc_addr_and_port_mape (snat_address_t * addresses, u32 fib_index,
2983 u32 thread_index, nat_protocol_t proto,
2984 ip4_address_t * addr, u16 * port,
2985 u16 port_per_thread, u32 snat_thread_index)
2987 snat_main_t *sm = &snat_main;
2988 snat_address_t *a = addresses;
2989 u16 m, ports, portnum, A, j;
2990 m = 16 - (sm->psid_offset + sm->psid_length);
2991 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2993 if (!vec_len (addresses))
2998 #define _(N, i, n, s) \
2999 case NAT_PROTOCOL_##N: \
3000 if (a->busy_##n##_ports < ports) \
3004 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
3005 j = snat_random_port(0, pow2_mask(m)); \
3006 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
3007 if (a->busy_##n##_port_refcounts[portnum]) \
3009 ++a->busy_##n##_port_refcounts[portnum]; \
3010 a->busy_##n##_ports++; \
3012 *port = clib_host_to_net_u16 (portnum); \
3017 foreach_nat_protocol
3020 nat_elog_info ("unknown protocol");
3025 /* Totally out of translations to use... */
3026 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3031 nat_alloc_addr_and_port_range (snat_address_t * addresses, u32 fib_index,
3032 u32 thread_index, nat_protocol_t proto,
3033 ip4_address_t * addr, u16 * port,
3034 u16 port_per_thread, u32 snat_thread_index)
3036 snat_main_t *sm = &snat_main;
3037 snat_address_t *a = addresses;
3040 ports = sm->end_port - sm->start_port + 1;
3042 if (!vec_len (addresses))
3047 #define _(N, i, n, s) \
3048 case NAT_PROTOCOL_##N: \
3049 if (a->busy_##n##_ports < ports) \
3053 portnum = snat_random_port(sm->start_port, sm->end_port); \
3054 if (a->busy_##n##_port_refcounts[portnum]) \
3056 ++a->busy_##n##_port_refcounts[portnum]; \
3057 a->busy_##n##_ports++; \
3059 *port = clib_host_to_net_u16 (portnum); \
3064 foreach_nat_protocol
3067 nat_elog_info ("unknown protocol");
3072 /* Totally out of translations to use... */
3073 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3078 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
3080 dpo_id_t dpo_v4 = DPO_INVALID;
3081 fib_prefix_t pfx = {
3082 .fp_proto = FIB_PROTOCOL_IP4,
3084 .fp_addr.ip4.as_u32 = addr.as_u32,
3089 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
3090 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
3091 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
3092 dpo_reset (&dpo_v4);
3096 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
3101 format_session_kvp (u8 * s, va_list * args)
3103 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3105 s = format (s, "%U session-index %llu", format_snat_key, v->key, v->value);
3111 format_static_mapping_kvp (u8 * s, va_list * args)
3113 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3115 s = format (s, "%U static-mapping-index %llu",
3116 format_snat_key, v->key, v->value);
3122 format_user_kvp (u8 * s, va_list * args)
3124 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3129 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
3130 k.fib_index, v->value);
3136 format_ed_session_kvp (u8 * s, va_list * args)
3138 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3142 ip4_address_t l_addr, r_addr;
3145 split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
3148 "local %U:%d remote %U:%d proto %U fib %d thread-index %u session-index %u",
3149 format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
3150 format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
3151 format_ip_protocol, proto, fib_index,
3152 ed_value_get_session_index (v), ed_value_get_thread_index (v));
3158 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3161 snat_main_t *sm = &snat_main;
3162 u32 next_worker_index = 0;
3165 next_worker_index = sm->first_worker_index;
3166 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3167 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3169 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3170 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3172 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3174 return next_worker_index;
3178 snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
3179 u32 rx_fib_index0, u8 is_output)
3181 snat_main_t *sm = &snat_main;
3184 clib_bihash_kv_8_8_t kv, value;
3185 snat_static_mapping_t *m;
3187 u32 next_worker_index = 0;
3189 /* first try static mappings without port */
3190 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3192 init_nat_k (&kv, ip0->dst_address, 0, rx_fib_index0, 0);
3193 if (!clib_bihash_search_8_8
3194 (&sm->static_mapping_by_external, &kv, &value))
3196 m = pool_elt_at_index (sm->static_mappings, value.value);
3197 return m->workers[0];
3201 proto = ip_proto_to_nat_proto (ip0->protocol);
3202 udp = ip4_next_header (ip0);
3203 port = udp->dst_port;
3205 /* unknown protocol */
3206 if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
3208 /* use current thread */
3209 return vlib_get_thread_index ();
3212 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3214 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3215 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3216 if (!icmp_type_is_error_message
3217 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3218 port = vnet_buffer (b)->ip.reass.l4_src_port;
3221 /* if error message, then it's not fragmented and we can access it */
3222 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3223 proto = ip_proto_to_nat_proto (inner_ip->protocol);
3224 void *l4_header = ip4_next_header (inner_ip);
3227 case NAT_PROTOCOL_ICMP:
3228 icmp = (icmp46_header_t *) l4_header;
3229 echo = (icmp_echo_header_t *) (icmp + 1);
3230 port = echo->identifier;
3232 case NAT_PROTOCOL_UDP:
3233 case NAT_PROTOCOL_TCP:
3234 port = ((tcp_udp_header_t *) l4_header)->src_port;
3237 return vlib_get_thread_index ();
3242 /* try static mappings with port */
3243 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3245 init_nat_k (&kv, ip0->dst_address, port, rx_fib_index0, proto);
3246 if (!clib_bihash_search_8_8
3247 (&sm->static_mapping_by_external, &kv, &value))
3249 m = pool_elt_at_index (sm->static_mappings, value.value);
3250 return m->workers[0];
3254 /* worker by outside port */
3255 next_worker_index = sm->first_worker_index;
3256 next_worker_index +=
3257 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3258 return next_worker_index;
3262 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3265 snat_main_t *sm = &snat_main;
3266 u32 next_worker_index = sm->first_worker_index;
3269 clib_bihash_kv_16_8_t kv16, value16;
3270 snat_main_per_thread_data_t *tsm;
3273 if (PREDICT_FALSE (is_output))
3275 u32 fib_index = sm->outside_fib_index;
3276 nat_outside_fib_t *outside_fib;
3277 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3278 fib_prefix_t pfx = {
3279 .fp_proto = FIB_PROTOCOL_IP4,
3282 .ip4.as_u32 = ip->dst_address.as_u32,
3287 udp = ip4_next_header (ip);
3289 switch (vec_len (sm->outside_fibs))
3292 fib_index = sm->outside_fib_index;
3295 fib_index = sm->outside_fibs[0].fib_index;
3299 vec_foreach (outside_fib, sm->outside_fibs)
3301 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3302 if (FIB_NODE_INDEX_INVALID != fei)
3304 if (fib_entry_get_resolving_interface (fei) != ~0)
3306 fib_index = outside_fib->fib_index;
3315 init_ed_k (&kv16, ip->src_address, udp->src_port, ip->dst_address,
3316 udp->dst_port, fib_index, ip->protocol);
3318 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
3322 vec_elt_at_index (sm->per_thread_data,
3323 ed_value_get_thread_index (&value16));
3324 next_worker_index += tsm->thread_index;
3326 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3327 next_worker_index, fib_index,
3328 clib_net_to_host_u32 (ip->
3329 src_address.as_u32),
3330 clib_net_to_host_u32 (ip->
3331 dst_address.as_u32));
3333 return next_worker_index;
3337 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3338 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3340 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3341 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3343 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3345 if (PREDICT_TRUE (!is_output))
3347 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3348 next_worker_index, rx_fib_index,
3349 clib_net_to_host_u32 (ip->src_address.as_u32),
3350 clib_net_to_host_u32 (ip->dst_address.as_u32));
3354 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3355 next_worker_index, rx_fib_index,
3356 clib_net_to_host_u32 (ip->src_address.as_u32),
3357 clib_net_to_host_u32 (ip->dst_address.as_u32));
3360 return next_worker_index;
3364 nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
3365 u32 rx_fib_index, u8 is_output)
3367 snat_main_t *sm = &snat_main;
3368 clib_bihash_kv_8_8_t kv, value;
3369 clib_bihash_kv_16_8_t kv16, value16;
3370 snat_main_per_thread_data_t *tsm;
3372 u32 proto, next_worker_index = 0;
3375 snat_static_mapping_t *m;
3378 proto = ip_proto_to_nat_proto (ip->protocol);
3380 if (PREDICT_TRUE (proto == NAT_PROTOCOL_UDP || proto == NAT_PROTOCOL_TCP))
3382 udp = ip4_next_header (ip);
3384 init_ed_k (&kv16, ip->dst_address, udp->dst_port, ip->src_address,
3385 udp->src_port, rx_fib_index, ip->protocol);
3387 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
3391 vec_elt_at_index (sm->per_thread_data,
3392 ed_value_get_thread_index (&value16));
3393 vnet_buffer2 (b)->nat.ed_out2in_nat_session_index =
3394 ed_value_get_session_index (&value16);
3395 next_worker_index = sm->first_worker_index + tsm->thread_index;
3396 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3397 next_worker_index, rx_fib_index,
3398 clib_net_to_host_u32 (ip->
3399 src_address.as_u32),
3400 clib_net_to_host_u32 (ip->
3401 dst_address.as_u32));
3402 return next_worker_index;
3405 else if (proto == NAT_PROTOCOL_ICMP)
3407 if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0, ~0, 0, 0, 0, &kv16))
3409 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&sm->out2in_ed,
3413 vec_elt_at_index (sm->per_thread_data,
3414 ed_value_get_thread_index (&value16));
3415 next_worker_index = sm->first_worker_index + tsm->thread_index;
3416 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3417 next_worker_index, rx_fib_index,
3418 clib_net_to_host_u32 (ip->
3419 src_address.as_u32),
3420 clib_net_to_host_u32 (ip->
3421 dst_address.as_u32));
3422 return next_worker_index;
3427 /* first try static mappings without port */
3428 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3430 init_nat_k (&kv, ip->dst_address, 0, 0, 0);
3431 if (!clib_bihash_search_8_8
3432 (&sm->static_mapping_by_external, &kv, &value))
3434 m = pool_elt_at_index (sm->static_mappings, value.value);
3435 next_worker_index = m->workers[0];
3440 /* unknown protocol */
3441 if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
3443 /* use current thread */
3444 next_worker_index = vlib_get_thread_index ();
3448 udp = ip4_next_header (ip);
3449 port = udp->dst_port;
3451 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3453 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3454 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3455 if (!icmp_type_is_error_message
3456 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3457 port = vnet_buffer (b)->ip.reass.l4_src_port;
3460 /* if error message, then it's not fragmented and we can access it */
3461 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3462 proto = ip_proto_to_nat_proto (inner_ip->protocol);
3463 void *l4_header = ip4_next_header (inner_ip);
3466 case NAT_PROTOCOL_ICMP:
3467 icmp = (icmp46_header_t *) l4_header;
3468 echo = (icmp_echo_header_t *) (icmp + 1);
3469 port = echo->identifier;
3471 case NAT_PROTOCOL_UDP:
3472 case NAT_PROTOCOL_TCP:
3473 port = ((tcp_udp_header_t *) l4_header)->src_port;
3476 next_worker_index = vlib_get_thread_index ();
3482 /* try static mappings with port */
3483 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3485 init_nat_k (&kv, ip->dst_address, proto, 0, port);
3486 if (!clib_bihash_search_8_8
3487 (&sm->static_mapping_by_external, &kv, &value))
3489 m = pool_elt_at_index (sm->static_mappings, value.value);
3490 if (!is_lb_static_mapping (m))
3492 next_worker_index = m->workers[0];
3496 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3497 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3499 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3501 m->workers[hash & (_vec_len (m->workers) - 1)];
3503 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3508 /* worker by outside port */
3509 next_worker_index = sm->first_worker_index;
3510 next_worker_index +=
3511 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3514 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3515 clib_net_to_host_u32 (ip->src_address.as_u32),
3516 clib_net_to_host_u32 (ip->dst_address.as_u32));
3517 return next_worker_index;
3521 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3522 ip4_address_t * out_addr, u16 out_port,
3523 ip4_address_t * eh_addr, u16 eh_port,
3524 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3525 u32 fib_index, u16 flags, u32 thread_index)
3527 snat_main_t *sm = &snat_main;
3528 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3531 clib_bihash_kv_8_8_t kv;
3532 vlib_main_t *vm = vlib_get_main ();
3533 f64 now = vlib_time_now (vm);
3534 nat_outside_fib_t *outside_fib;
3535 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3536 fib_prefix_t pfx = {
3537 .fp_proto = FIB_PROTOCOL_IP4,
3540 .ip4.as_u32 = eh_addr->as_u32,
3544 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3546 if (nat_set_outside_address_and_port
3547 (sm->addresses, thread_index, *out_addr, out_port, proto))
3551 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3555 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3559 if (sm->endpoint_dependent)
3561 nat_ed_lru_insert (tsm, s, now, nat_proto_to_ip_proto (proto));
3564 s->out2in.addr.as_u32 = out_addr->as_u32;
3565 s->out2in.port = out_port;
3566 s->nat_proto = proto;
3567 s->last_heard = now;
3569 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3570 s->ext_host_port = eh_port;
3571 user_session_increment (sm, u, snat_is_session_static (s));
3572 switch (vec_len (sm->outside_fibs))
3575 s->out2in.fib_index = sm->outside_fib_index;
3578 s->out2in.fib_index = sm->outside_fibs[0].fib_index;
3582 vec_foreach (outside_fib, sm->outside_fibs)
3584 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3585 if (FIB_NODE_INDEX_INVALID != fei)
3587 if (fib_entry_get_resolving_interface (fei) != ~0)
3589 s->out2in.fib_index = outside_fib->fib_index;
3597 init_nat_o2i_kv (&kv, s, s - tsm->sessions);
3598 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3599 nat_elog_warn ("out2in key add failed");
3601 s->in2out.addr.as_u32 = in_addr->as_u32;
3602 s->in2out.port = in_port;
3603 s->in2out.fib_index = fib_index;
3604 init_nat_i2o_kv (&kv, s, s - tsm->sessions);
3605 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3606 nat_elog_warn ("in2out key add failed");
3610 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3611 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3614 snat_main_t *sm = &snat_main;
3615 clib_bihash_kv_8_8_t kv, value;
3618 snat_main_per_thread_data_t *tsm;
3620 if (sm->num_workers > 1)
3622 sm->first_worker_index +
3623 (sm->workers[(clib_net_to_host_u16 (out_port) -
3624 1024) / sm->port_per_thread]);
3626 thread_index = sm->num_workers;
3627 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3629 init_nat_k (&kv, *out_addr, out_port, fib_index, proto);
3630 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3633 s = pool_elt_at_index (tsm->sessions, value.value);
3634 nat_free_session_data (sm, s, thread_index, 1);
3635 nat44_delete_session (sm, s, thread_index);
3639 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3640 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3641 u32 total_pkts, u64 total_bytes, u32 thread_index)
3643 snat_main_t *sm = &snat_main;
3644 clib_bihash_kv_8_8_t kv, value;
3646 snat_main_per_thread_data_t *tsm;
3648 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3650 init_nat_k (&kv, *out_addr, out_port, fib_index, proto);
3651 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3654 s = pool_elt_at_index (tsm->sessions, value.value);
3655 s->total_pkts = total_pkts;
3656 s->total_bytes = total_bytes;
3660 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3661 ip4_address_t * out_addr, u16 out_port,
3662 ip4_address_t * eh_addr, u16 eh_port,
3663 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3664 u32 fib_index, u16 flags, u32 thread_index)
3666 snat_main_t *sm = &snat_main;
3667 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3669 clib_bihash_kv_16_8_t kv;
3670 vlib_main_t *vm = vlib_get_main ();
3671 f64 now = vlib_time_now (vm);
3672 nat_outside_fib_t *outside_fib;
3673 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3674 fib_prefix_t pfx = {
3675 .fp_proto = FIB_PROTOCOL_IP4,
3678 .ip4.as_u32 = eh_addr->as_u32,
3683 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3685 if (nat_set_outside_address_and_port
3686 (sm->addresses, thread_index, *out_addr, out_port, proto))
3690 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3692 if (nat_set_outside_address_and_port
3693 (sm->addresses, thread_index, *ehn_addr, ehn_port, proto))
3697 s = nat_ed_session_alloc (sm, thread_index, now, proto);
3701 s->last_heard = now;
3703 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3704 s->ext_host_nat_port = s->ext_host_port = eh_port;
3705 if (is_twice_nat_session (s))
3707 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3708 s->ext_host_nat_port = ehn_port;
3710 switch (vec_len (sm->outside_fibs))
3713 s->out2in.fib_index = sm->outside_fib_index;
3716 s->out2in.fib_index = sm->outside_fibs[0].fib_index;
3720 vec_foreach (outside_fib, sm->outside_fibs)
3722 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3723 if (FIB_NODE_INDEX_INVALID != fei)
3725 if (fib_entry_get_resolving_interface (fei) != ~0)
3727 s->out2in.fib_index = outside_fib->fib_index;
3735 s->nat_proto = proto;
3736 s->out2in.addr.as_u32 = out_addr->as_u32;
3737 s->out2in.port = out_port;
3739 s->in2out.addr.as_u32 = in_addr->as_u32;
3740 s->in2out.port = in_port;
3741 s->in2out.fib_index = fib_index;
3743 init_ed_kv (&kv, *in_addr, in_port, s->ext_host_nat_addr,
3744 s->ext_host_nat_port, fib_index, nat_proto_to_ip_proto (proto),
3745 thread_index, s - tsm->sessions);
3746 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3747 nat_elog_warn ("in2out key add failed");
3749 init_ed_kv (&kv, *out_addr, out_port, *eh_addr, eh_port,
3750 s->out2in.fib_index, nat_proto_to_ip_proto (proto),
3751 thread_index, s - tsm->sessions);
3752 if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &kv, 1))
3753 nat_elog_warn ("out2in key add failed");
3757 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3758 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3759 u32 fib_index, u32 ti)
3761 snat_main_t *sm = &snat_main;
3762 clib_bihash_kv_16_8_t kv, value;
3765 snat_main_per_thread_data_t *tsm;
3767 if (sm->num_workers > 1)
3769 sm->first_worker_index +
3770 (sm->workers[(clib_net_to_host_u16 (out_port) -
3771 1024) / sm->port_per_thread]);
3773 thread_index = sm->num_workers;
3774 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3776 init_ed_k (&kv, *out_addr, out_port, *eh_addr, eh_port, fib_index, proto);
3777 if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
3780 s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
3781 nat_free_session_data (sm, s, thread_index, 1);
3782 nat44_delete_session (sm, s, thread_index);
3786 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3787 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3788 u32 fib_index, u32 total_pkts, u64 total_bytes,
3791 snat_main_t *sm = &snat_main;
3792 clib_bihash_kv_16_8_t kv, value;
3794 snat_main_per_thread_data_t *tsm;
3796 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3798 init_ed_k (&kv, *out_addr, out_port, *eh_addr, eh_port, fib_index, proto);
3799 if (clib_bihash_search_16_8 (&sm->out2in_ed, &kv, &value))
3802 s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
3803 s->total_pkts = total_pkts;
3804 s->total_bytes = total_bytes;
3808 nat_calc_bihash_buckets (u32 n_elts)
3810 return 1 << (max_log2 (n_elts >> 1) + 1);
3814 nat_calc_bihash_memory (u32 n_buckets, uword kv_size)
3816 return n_buckets * (8 + kv_size * 4);
3820 nat44_db_init (snat_main_per_thread_data_t * tsm)
3822 snat_main_t *sm = &snat_main;
3824 pool_alloc (tsm->sessions, sm->max_translations_per_thread);
3825 pool_alloc (tsm->lru_pool, sm->max_translations_per_thread);
3829 pool_get (tsm->lru_pool, head);
3830 tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
3831 clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
3833 pool_get (tsm->lru_pool, head);
3834 tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
3835 clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
3837 pool_get (tsm->lru_pool, head);
3838 tsm->udp_lru_head_index = head - tsm->lru_pool;
3839 clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
3841 pool_get (tsm->lru_pool, head);
3842 tsm->icmp_lru_head_index = head - tsm->lru_pool;
3843 clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
3845 pool_get (tsm->lru_pool, head);
3846 tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
3847 clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
3849 if (sm->endpoint_dependent)
3851 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3852 sm->translation_buckets,
3853 sm->translation_memory_size);
3854 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3855 format_ed_session_kvp);
3859 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3860 sm->translation_buckets,
3861 sm->translation_memory_size);
3862 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp);
3863 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3864 sm->translation_buckets,
3865 sm->translation_memory_size);
3866 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp);
3869 // TODO: resolve static mappings (put only to !ED)
3870 pool_alloc (tsm->list_pool, sm->max_translations_per_thread);
3871 clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets,
3872 sm->user_memory_size);
3873 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
3877 nat44_db_free (snat_main_per_thread_data_t * tsm)
3879 snat_main_t *sm = &snat_main;
3881 pool_free (tsm->sessions);
3882 pool_free (tsm->lru_pool);
3884 if (sm->endpoint_dependent)
3886 clib_bihash_free_16_8 (&tsm->in2out_ed);
3890 clib_bihash_free_8_8 (&tsm->in2out);
3891 clib_bihash_free_8_8 (&tsm->out2in);
3894 // TODO: resolve static mappings (put only to !ED)
3895 pool_free (tsm->users);
3896 pool_free (tsm->list_pool);
3897 clib_bihash_free_8_8 (&tsm->user_hash);
3901 nat44_sessions_clear ()
3903 snat_main_t *sm = &snat_main;
3904 snat_main_per_thread_data_t *tsm;
3906 if (sm->endpoint_dependent)
3908 clib_bihash_free_16_8 (&sm->out2in_ed);
3909 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
3910 clib_max (1, sm->num_workers) *
3911 sm->translation_buckets,
3912 clib_max (1, sm->num_workers) *
3913 sm->translation_memory_size);
3914 clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
3915 format_ed_session_kvp);
3919 vec_foreach (tsm, sm->per_thread_data)
3923 nat44_db_free (tsm);
3924 nat44_db_init (tsm);
3926 ti = tsm->snat_thread_index;
3927 vlib_set_simple_counter (&sm->total_users, ti, 0, 0);
3928 vlib_set_simple_counter (&sm->total_sessions, ti, 0, 0);
3933 static clib_error_t *
3934 snat_config (vlib_main_t * vm, unformat_input_t * input)
3936 snat_main_t *sm = &snat_main;
3937 snat_main_per_thread_data_t *tsm;
3939 u32 static_mapping_buckets = 1024;
3940 uword static_mapping_memory_size = 64 << 20;
3942 u32 nat64_bib_buckets = 1024;
3943 u32 nat64_bib_memory_size = 128 << 20;
3945 u32 nat64_st_buckets = 2048;
3946 uword nat64_st_memory_size = 256 << 20;
3948 u32 max_users_per_thread = 0;
3949 u32 user_memory_size = 0;
3950 u32 max_translations_per_thread = 0;
3951 u32 translation_memory_size = 0;
3953 u32 max_translations_per_user = ~0;
3955 u32 outside_vrf_id = 0;
3956 u32 outside_ip6_vrf_id = 0;
3957 u32 inside_vrf_id = 0;
3958 u8 static_mapping_only = 0;
3959 u8 static_mapping_connection_tracking = 0;
3961 u32 udp_timeout = SNAT_UDP_TIMEOUT;
3962 u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
3963 u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3964 u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3967 sm->endpoint_dependent = 0;
3969 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3972 (input, "max translations per thread %d",
3973 &max_translations_per_thread))
3975 else if (unformat (input, "udp timeout %d", &udp_timeout))
3977 else if (unformat (input, "icmp timeout %d", &icmp_timeout))
3979 else if (unformat (input, "tcp transitory timeout %d",
3980 &tcp_transitory_timeout));
3981 else if (unformat (input, "tcp established timeout %d",
3982 &tcp_established_timeout));
3983 else if (unformat (input, "translation hash memory %d",
3984 &translation_memory_size));
3987 (input, "max users per thread %d", &max_users_per_thread))
3989 else if (unformat (input, "user hash memory %d", &user_memory_size))
3991 else if (unformat (input, "max translations per user %d",
3992 &max_translations_per_user))
3994 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3996 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3998 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
4000 else if (unformat (input, "static mapping only"))
4002 static_mapping_only = 1;
4003 if (unformat (input, "connection tracking"))
4004 static_mapping_connection_tracking = 1;
4006 else if (unformat (input, "nat64 bib hash buckets %d",
4007 &nat64_bib_buckets))
4009 else if (unformat (input, "nat64 bib hash memory %d",
4010 &nat64_bib_memory_size))
4013 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
4015 else if (unformat (input, "nat64 st hash memory %d",
4016 &nat64_st_memory_size))
4018 else if (unformat (input, "out2in dpo"))
4020 else if (unformat (input, "endpoint-dependent"))
4021 sm->endpoint_dependent = 1;
4023 return clib_error_return (0, "unknown input '%U'",
4024 format_unformat_error, input);
4027 if (static_mapping_only && (sm->endpoint_dependent))
4028 return clib_error_return (0,
4029 "static mapping only mode available only for simple nat");
4031 if (sm->out2in_dpo && (sm->endpoint_dependent))
4032 return clib_error_return (0,
4033 "out2in dpo mode available only for simple nat");
4034 if (sm->endpoint_dependent && max_users_per_thread > 0)
4036 return clib_error_return (0,
4037 "setting 'max users' in endpoint-dependent mode is not supported");
4040 if (sm->endpoint_dependent && max_translations_per_user != ~0)
4042 return clib_error_return (0,
4043 "setting 'max translations per user' in endpoint-dependent mode is not supported");
4046 /* optionally configurable timeouts for testing purposes */
4047 sm->udp_timeout = udp_timeout;
4048 sm->tcp_transitory_timeout = tcp_transitory_timeout;
4049 sm->tcp_established_timeout = tcp_established_timeout;
4050 sm->icmp_timeout = icmp_timeout;
4052 if (0 == max_users_per_thread)
4054 max_users_per_thread = 1024;
4056 sm->max_users_per_thread = max_users_per_thread;
4057 sm->user_buckets = nat_calc_bihash_buckets (sm->max_users_per_thread);
4059 if (0 == max_translations_per_thread)
4061 // default value based on legacy setting of load factor 10 * default
4062 // translation buckets 1024
4063 max_translations_per_thread = 10 * 1024;
4065 sm->max_translations_per_thread = max_translations_per_thread;
4066 sm->translation_buckets =
4067 nat_calc_bihash_buckets (sm->max_translations_per_thread);
4068 if (0 == translation_memory_size)
4070 translation_memory_size =
4071 nat_calc_bihash_memory (sm->translation_buckets,
4072 sizeof (clib_bihash_16_8_t));
4074 sm->translation_memory_size = translation_memory_size;
4075 if (0 == user_memory_size)
4078 nat_calc_bihash_memory (sm->max_users_per_thread,
4079 sizeof (clib_bihash_8_8_t));
4081 sm->user_memory_size = user_memory_size;
4082 vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
4084 sm->max_translations_per_user = max_translations_per_user == ~0 ?
4085 sm->max_translations_per_thread : max_translations_per_user;
4087 sm->outside_vrf_id = outside_vrf_id;
4088 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4091 sm->inside_vrf_id = inside_vrf_id;
4092 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4095 sm->static_mapping_only = static_mapping_only;
4096 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
4098 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
4099 nat64_st_memory_size);
4101 if (sm->endpoint_dependent)
4103 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
4104 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
4106 sm->in2out_node_index = nat44_ed_in2out_node.index;
4107 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
4108 sm->out2in_node_index = nat44_ed_out2in_node.index;
4110 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
4111 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
4112 nat_affinity_init (vm);
4113 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
4115 clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
4116 clib_max (1, sm->num_workers) *
4117 sm->translation_buckets,
4118 clib_max (1, sm->num_workers) *
4119 sm->translation_memory_size);
4120 clib_bihash_set_kvp_format_fn_16_8 (&sm->out2in_ed,
4121 format_ed_session_kvp);
4125 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
4126 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
4128 sm->in2out_node_index = snat_in2out_node.index;
4129 sm->in2out_output_node_index = snat_in2out_output_node.index;
4130 sm->out2in_node_index = snat_out2in_node.index;
4132 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
4133 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
4134 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
4136 if (!static_mapping_only ||
4137 (static_mapping_only && static_mapping_connection_tracking))
4140 vec_foreach (tsm, sm->per_thread_data)
4142 nat44_db_init (tsm);
4148 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
4149 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
4151 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
4152 "static_mapping_by_local", static_mapping_buckets,
4153 static_mapping_memory_size);
4154 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
4155 format_static_mapping_kvp);
4157 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
4158 "static_mapping_by_external",
4159 static_mapping_buckets, static_mapping_memory_size);
4160 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
4161 format_static_mapping_kvp);
4166 VLIB_CONFIG_FUNCTION (snat_config, "nat");
4169 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
4172 ip4_address_t * address,
4174 u32 if_address_index, u32 is_delete)
4176 snat_main_t *sm = &snat_main;
4177 snat_static_map_resolve_t *rp;
4178 snat_static_mapping_t *m;
4179 clib_bihash_kv_8_8_t kv, value;
4181 ip4_address_t l_addr;
4183 for (i = 0; i < vec_len (sm->to_resolve); i++)
4185 rp = sm->to_resolve + i;
4186 if (rp->addr_only == 0)
4188 if (rp->sw_if_index == sw_if_index)
4195 init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
4196 sm->outside_fib_index, rp->addr_only ? 0 : rp->proto);
4197 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4200 m = pool_elt_at_index (sm->static_mappings, value.value);
4204 /* Don't trip over lease renewal, static config */
4214 /* Indetity mapping? */
4215 if (rp->l_addr.as_u32 == 0)
4216 l_addr.as_u32 = address[0].as_u32;
4218 l_addr.as_u32 = rp->l_addr.as_u32;
4219 /* Add the static mapping */
4220 rv = snat_add_static_mapping (l_addr,
4225 rp->addr_only, ~0 /* sw_if_index */ ,
4226 rp->proto, !is_delete, rp->twice_nat,
4227 rp->out2in_only, rp->tag, rp->identity_nat);
4229 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4233 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4236 ip4_address_t * address,
4238 u32 if_address_index, u32 is_delete)
4240 snat_main_t *sm = &snat_main;
4241 snat_static_map_resolve_t *rp;
4242 ip4_address_t l_addr;
4246 snat_address_t *addresses = sm->addresses;
4248 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4250 if (sw_if_index == sm->auto_add_sw_if_indices[i])
4254 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4257 addresses = sm->twice_nat_addresses;
4258 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4267 /* Don't trip over lease renewal, static config */
4268 for (j = 0; j < vec_len (addresses); j++)
4269 if (addresses[j].addr.as_u32 == address->as_u32)
4272 (void) snat_add_address (sm, address, ~0, twice_nat);
4273 /* Scan static map resolution vector */
4274 for (j = 0; j < vec_len (sm->to_resolve); j++)
4276 rp = sm->to_resolve + j;
4279 /* On this interface? */
4280 if (rp->sw_if_index == sw_if_index)
4282 /* Indetity mapping? */
4283 if (rp->l_addr.as_u32 == 0)
4284 l_addr.as_u32 = address[0].as_u32;
4286 l_addr.as_u32 = rp->l_addr.as_u32;
4287 /* Add the static mapping */
4288 rv = snat_add_static_mapping (l_addr,
4294 ~0 /* sw_if_index */ ,
4296 rp->is_add, rp->twice_nat,
4297 rp->out2in_only, rp->tag,
4300 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4308 (void) snat_del_address (sm, address[0], 1, twice_nat);
4315 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4318 ip4_main_t *ip4_main = sm->ip4_main;
4319 ip4_address_t *first_int_addr;
4320 snat_static_map_resolve_t *rp;
4321 u32 *indices_to_delete = 0;
4323 u32 *auto_add_sw_if_indices =
4325 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4327 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4330 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4332 if (auto_add_sw_if_indices[i] == sw_if_index)
4336 /* if have address remove it */
4338 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4341 for (j = 0; j < vec_len (sm->to_resolve); j++)
4343 rp = sm->to_resolve + j;
4344 if (rp->sw_if_index == sw_if_index)
4345 vec_add1 (indices_to_delete, j);
4347 if (vec_len (indices_to_delete))
4349 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4350 vec_del1 (sm->to_resolve, j);
4351 vec_free (indices_to_delete);
4355 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4357 vec_del1 (sm->auto_add_sw_if_indices, i);
4360 return VNET_API_ERROR_VALUE_EXIST;
4367 return VNET_API_ERROR_NO_SUCH_ENTRY;
4369 /* add to the auto-address list */
4371 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4373 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4375 /* If the address is already bound - or static - add it now */
4377 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4383 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4384 nat_protocol_t proto, u32 vrf_id, int is_in)
4386 snat_main_per_thread_data_t *tsm;
4387 clib_bihash_kv_8_8_t kv, value;
4389 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4391 clib_bihash_8_8_t *t;
4393 if (sm->endpoint_dependent)
4394 return VNET_API_ERROR_UNSUPPORTED;
4396 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4397 if (sm->num_workers > 1)
4399 vec_elt_at_index (sm->per_thread_data,
4400 sm->worker_in2out_cb (&ip, fib_index, 0));
4402 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4404 init_nat_k (&kv, *addr, port, fib_index, proto);
4405 t = is_in ? &tsm->in2out : &tsm->out2in;
4406 if (!clib_bihash_search_8_8 (t, &kv, &value))
4408 if (pool_is_free_index (tsm->sessions, value.value))
4409 return VNET_API_ERROR_UNSPECIFIED;
4411 s = pool_elt_at_index (tsm->sessions, value.value);
4412 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4413 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4417 return VNET_API_ERROR_NO_SUCH_ENTRY;
4421 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4422 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4423 u32 vrf_id, int is_in)
4426 clib_bihash_16_8_t *t;
4427 clib_bihash_kv_16_8_t kv, value;
4428 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4430 snat_main_per_thread_data_t *tsm;
4432 if (!sm->endpoint_dependent)
4433 return VNET_API_ERROR_FEATURE_DISABLED;
4435 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4436 if (sm->num_workers > 1)
4438 vec_elt_at_index (sm->per_thread_data,
4439 sm->worker_in2out_cb (&ip, fib_index, 0));
4441 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4443 t = is_in ? &tsm->in2out_ed : &sm->out2in_ed;
4444 init_ed_k (&kv, *addr, port, *eh_addr, eh_port, fib_index, proto);
4445 if (clib_bihash_search_16_8 (t, &kv, &value))
4447 return VNET_API_ERROR_NO_SUCH_ENTRY;
4450 if (pool_is_free_index (tsm->sessions, value.value))
4451 return VNET_API_ERROR_UNSPECIFIED;
4452 s = pool_elt_at_index (tsm->sessions, value.value);
4453 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4454 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
4459 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4461 snat_main_t *sm = &snat_main;
4463 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4464 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4466 sm->psid_offset = psid_offset;
4467 sm->psid_length = psid_length;
4471 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4473 snat_main_t *sm = &snat_main;
4475 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4476 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4477 sm->start_port = start_port;
4478 sm->end_port = end_port;
4482 nat_set_alloc_addr_and_port_default (void)
4484 snat_main_t *sm = &snat_main;
4486 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4487 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4490 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4491 vlib_node_runtime_t * node,
4492 vlib_frame_t * frame)
4498 VLIB_REGISTER_NODE (nat_default_node) = {
4499 .name = "nat-default",
4500 .vector_size = sizeof (u32),
4502 .type = VLIB_NODE_TYPE_INTERNAL,
4504 .n_next_nodes = NAT_N_NEXT,
4506 [NAT_NEXT_DROP] = "error-drop",
4507 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4508 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4509 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4510 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4511 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4512 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4513 [NAT_NEXT_IN2OUT_CLASSIFY] = "nat44-in2out-worker-handoff",
4514 [NAT_NEXT_OUT2IN_CLASSIFY] = "nat44-out2in-worker-handoff",
4520 * fd.io coding-style-patch-verification: ON
4523 * eval: (c-set-style "gnu")