2 * snat.c - simple nat plugin
4 * Copyright (c) 2016 Cisco and/or its affiliates.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/nat_ipfix_logging.h>
25 #include <nat/nat_det.h>
26 #include <nat/nat64.h>
27 #include <nat/nat66.h>
28 #include <nat/dslite.h>
29 #include <nat/nat_reass.h>
30 #include <nat/nat_inlines.h>
31 #include <nat/nat_affinity.h>
32 #include <nat/nat_syslog.h>
33 #include <nat/nat_ha.h>
34 #include <vnet/fib/fib_table.h>
35 #include <vnet/fib/ip4_fib.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"),
51 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
52 .arc_name = "ip4-unicast",
53 .node_name = "nat-pre-out2in",
54 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
55 "ip4-dhcp-client-detect"),
57 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
58 .arc_name = "ip4-unicast",
59 .node_name = "nat44-in2out-worker-handoff",
60 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
62 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
63 .arc_name = "ip4-unicast",
64 .node_name = "nat44-out2in-worker-handoff",
65 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
66 "ip4-dhcp-client-detect"),
68 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
69 .arc_name = "ip4-unicast",
70 .node_name = "nat44-in2out",
71 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
73 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
74 .arc_name = "ip4-unicast",
75 .node_name = "nat44-out2in",
76 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
77 "ip4-dhcp-client-detect"),
79 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
80 .arc_name = "ip4-unicast",
81 .node_name = "nat44-classify",
82 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
84 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
85 .arc_name = "ip4-unicast",
86 .node_name = "nat44-det-in2out",
87 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
89 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
90 .arc_name = "ip4-unicast",
91 .node_name = "nat44-det-out2in",
92 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
93 "ip4-dhcp-client-detect"),
95 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
96 .arc_name = "ip4-unicast",
97 .node_name = "nat44-det-classify",
98 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
100 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
101 .arc_name = "ip4-unicast",
102 .node_name = "nat44-ed-in2out",
103 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
105 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
106 .arc_name = "ip4-unicast",
107 .node_name = "nat44-ed-out2in",
108 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
109 "ip4-dhcp-client-detect"),
111 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
112 .arc_name = "ip4-unicast",
113 .node_name = "nat44-ed-classify",
114 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
116 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
117 .arc_name = "ip4-unicast",
118 .node_name = "nat44-handoff-classify",
119 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
121 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
122 .arc_name = "ip4-unicast",
123 .node_name = "nat44-in2out-fast",
124 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
126 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
127 .arc_name = "ip4-unicast",
128 .node_name = "nat44-out2in-fast",
129 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
130 "ip4-dhcp-client-detect"),
132 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
133 .arc_name = "ip4-unicast",
134 .node_name = "nat44-hairpin-dst",
135 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
137 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
138 .arc_name = "ip4-unicast",
139 .node_name = "nat44-ed-hairpin-dst",
140 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
143 /* Hook up output features */
144 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
145 .arc_name = "ip4-output",
146 .node_name = "nat44-in2out-output",
147 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
149 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
150 .arc_name = "ip4-output",
151 .node_name = "nat44-in2out-output-worker-handoff",
152 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
154 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
155 .arc_name = "ip4-output",
156 .node_name = "nat44-hairpin-src",
157 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
159 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
160 .arc_name = "ip4-output",
161 .node_name = "nat44-ed-in2out-output",
162 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
164 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
165 .arc_name = "ip4-output",
166 .node_name = "nat44-ed-hairpin-src",
167 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
170 /* Hook up ip4-local features */
171 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
173 .arc_name = "ip4-local",
174 .node_name = "nat44-hairpinning",
175 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
177 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
179 .arc_name = "ip4-local",
180 .node_name = "nat44-ed-hairpinning",
181 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
185 VLIB_PLUGIN_REGISTER () = {
186 .version = VPP_BUILD_VER,
187 .description = "Network Address Translation (NAT)",
192 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
195 snat_session_key_t key;
196 clib_bihash_kv_8_8_t kv;
197 nat_ed_ses_key_t ed_key;
198 clib_bihash_kv_16_8_t ed_kv;
199 snat_main_per_thread_data_t *tsm =
200 vec_elt_at_index (sm->per_thread_data, thread_index);
202 if (is_fwd_bypass_session (s))
204 if (snat_is_unk_proto_session (s))
206 ed_key.proto = s->in2out.port;
212 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
213 ed_key.l_port = s->in2out.port;
214 ed_key.r_port = s->ext_host_port;
216 ed_key.l_addr = s->in2out.addr;
217 ed_key.r_addr = s->ext_host_addr;
218 ed_key.fib_index = 0;
219 ed_kv.key[0] = ed_key.as_u64[0];
220 ed_kv.key[1] = ed_key.as_u64[1];
221 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
222 nat_elog_warn ("in2out_ed key del failed");
226 /* session lookup tables */
227 if (is_ed_session (s))
229 if (is_affinity_sessions (s))
230 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
231 s->in2out.protocol, s->out2in.port);
232 ed_key.l_addr = s->out2in.addr;
233 ed_key.r_addr = s->ext_host_addr;
234 ed_key.fib_index = s->out2in.fib_index;
235 if (snat_is_unk_proto_session (s))
237 ed_key.proto = s->in2out.port;
243 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
244 ed_key.l_port = s->out2in.port;
245 ed_key.r_port = s->ext_host_port;
247 ed_kv.key[0] = ed_key.as_u64[0];
248 ed_kv.key[1] = ed_key.as_u64[1];
249 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
250 nat_elog_warn ("out2in_ed key del failed");
251 ed_key.l_addr = s->in2out.addr;
252 ed_key.fib_index = s->in2out.fib_index;
253 if (!snat_is_unk_proto_session (s))
254 ed_key.l_port = s->in2out.port;
255 if (is_twice_nat_session (s))
257 ed_key.r_addr = s->ext_host_nat_addr;
258 ed_key.r_port = s->ext_host_nat_port;
260 ed_kv.key[0] = ed_key.as_u64[0];
261 ed_kv.key[1] = ed_key.as_u64[1];
262 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
263 nat_elog_warn ("in2out_ed key del failed");
266 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
267 &s->in2out.addr, s->in2out.port,
268 &s->ext_host_nat_addr, s->ext_host_nat_port,
269 &s->out2in.addr, s->out2in.port,
270 &s->ext_host_addr, s->ext_host_port,
271 s->in2out.protocol, is_twice_nat_session (s));
275 kv.key = s->in2out.as_u64;
276 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
277 nat_elog_warn ("in2out key del failed");
278 kv.key = s->out2in.as_u64;
279 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
280 nat_elog_warn ("out2in key del failed");
283 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
284 &s->in2out.addr, s->in2out.port,
285 &s->out2in.addr, s->out2in.port,
289 if (snat_is_unk_proto_session (s))
295 snat_ipfix_logging_nat44_ses_delete (thread_index,
296 s->in2out.addr.as_u32,
297 s->out2in.addr.as_u32,
301 s->in2out.fib_index);
303 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
304 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
308 /* Twice NAT address and port for external host */
309 if (is_twice_nat_session (s))
311 key.protocol = s->in2out.protocol;
312 key.port = s->ext_host_nat_port;
313 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
314 snat_free_outside_address_and_port (sm->twice_nat_addresses,
318 if (snat_is_session_static (s))
321 snat_free_outside_address_and_port (sm->addresses, thread_index,
326 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
330 snat_user_key_t user_key;
331 clib_bihash_kv_8_8_t kv, value;
332 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
333 dlist_elt_t *per_user_list_head_elt;
335 user_key.addr.as_u32 = addr->as_u32;
336 user_key.fib_index = fib_index;
337 kv.key = user_key.as_u64;
339 /* Ever heard of the "user" = src ip4 address before? */
340 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
342 /* no, make a new one */
343 pool_get (tsm->users, u);
344 clib_memset (u, 0, sizeof (*u));
345 u->addr.as_u32 = addr->as_u32;
346 u->fib_index = fib_index;
348 pool_get (tsm->list_pool, per_user_list_head_elt);
350 u->sessions_per_user_list_head_index = per_user_list_head_elt -
353 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
355 kv.value = u - tsm->users;
358 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
359 nat_elog_warn ("user_hash keay add failed");
361 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
362 pool_elts (tsm->users));
366 u = pool_elt_at_index (tsm->users, value.value);
373 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
374 u32 thread_index, f64 now)
377 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
378 u32 oldest_per_user_translation_list_index, session_index;
379 dlist_elt_t *oldest_per_user_translation_list_elt;
380 dlist_elt_t *per_user_translation_list_elt;
382 /* Over quota? Recycle the least recently used translation */
383 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
385 oldest_per_user_translation_list_index =
386 clib_dlist_remove_head (tsm->list_pool,
387 u->sessions_per_user_list_head_index);
389 ASSERT (oldest_per_user_translation_list_index != ~0);
391 /* Add it back to the end of the LRU list */
392 clib_dlist_addtail (tsm->list_pool,
393 u->sessions_per_user_list_head_index,
394 oldest_per_user_translation_list_index);
395 /* Get the list element */
396 oldest_per_user_translation_list_elt =
397 pool_elt_at_index (tsm->list_pool,
398 oldest_per_user_translation_list_index);
400 /* Get the session index from the list element */
401 session_index = oldest_per_user_translation_list_elt->value;
403 /* Get the session */
404 s = pool_elt_at_index (tsm->sessions, session_index);
405 nat_free_session_data (sm, s, thread_index, 0);
406 if (snat_is_session_static (s))
407 u->nstaticsessions--;
414 s->ext_host_addr.as_u32 = 0;
415 s->ext_host_port = 0;
416 s->ext_host_nat_addr.as_u32 = 0;
417 s->ext_host_nat_port = 0;
421 pool_get (tsm->sessions, s);
422 clib_memset (s, 0, sizeof (*s));
424 /* Create list elts */
425 pool_get (tsm->list_pool, per_user_translation_list_elt);
426 clib_dlist_init (tsm->list_pool,
427 per_user_translation_list_elt - tsm->list_pool);
429 per_user_translation_list_elt->value = s - tsm->sessions;
430 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
431 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
433 clib_dlist_addtail (tsm->list_pool,
434 s->per_user_list_head_index,
435 per_user_translation_list_elt - tsm->list_pool);
437 s->user_index = u - tsm->users;
438 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
439 pool_elts (tsm->sessions));
442 s->ha_last_refreshed = now;
448 nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
452 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
453 dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
455 u64 sess_timeout_time;
457 if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
461 clib_dlist_remove_head (tsm->list_pool,
462 u->sessions_per_user_list_head_index);
463 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
464 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
466 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
467 if (now >= sess_timeout_time)
469 clib_dlist_addtail (tsm->list_pool,
470 u->sessions_per_user_list_head_index, oldest_index);
471 nat_free_session_data (sm, s, thread_index, 0);
472 if (snat_is_session_static (s))
473 u->nstaticsessions--;
480 s->ext_host_addr.as_u32 = 0;
481 s->ext_host_port = 0;
482 s->ext_host_nat_addr.as_u32 = 0;
483 s->ext_host_nat_port = 0;
487 clib_dlist_addhead (tsm->list_pool,
488 u->sessions_per_user_list_head_index, oldest_index);
489 if ((u->nsessions + u->nstaticsessions) >=
490 sm->max_translations_per_user)
492 nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
493 clib_net_to_host_u32 (u->addr.as_u32));
494 snat_ipfix_logging_max_entries_per_user
495 (thread_index, sm->max_translations_per_user, u->addr.as_u32);
501 pool_get (tsm->sessions, s);
502 clib_memset (s, 0, sizeof (*s));
504 /* Create list elts */
505 pool_get (tsm->list_pool, per_user_translation_list_elt);
506 clib_dlist_init (tsm->list_pool,
507 per_user_translation_list_elt - tsm->list_pool);
509 per_user_translation_list_elt->value = s - tsm->sessions;
510 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
511 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
513 clib_dlist_addtail (tsm->list_pool,
514 s->per_user_list_head_index,
515 per_user_translation_list_elt - tsm->list_pool);
518 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
519 pool_elts (tsm->sessions));
522 s->ha_last_refreshed = now;
528 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
531 fib_prefix_t prefix = {
533 .fp_proto = FIB_PROTOCOL_IP4,
535 .ip4.as_u32 = addr->as_u32,
538 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
541 fib_table_entry_update_one_path (fib_index,
544 (FIB_ENTRY_FLAG_CONNECTED |
545 FIB_ENTRY_FLAG_LOCAL |
546 FIB_ENTRY_FLAG_EXCLUSIVE),
550 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
552 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
556 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
561 vlib_thread_main_t *tm = vlib_get_thread_main ();
563 if (twice_nat && !sm->endpoint_dependent)
564 return VNET_API_ERROR_FEATURE_DISABLED;
566 /* Check if address already exists */
568 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
570 if (ap->addr.as_u32 == addr->as_u32)
571 return VNET_API_ERROR_VALUE_EXIST;
576 vec_add2 (sm->twice_nat_addresses, ap, 1);
578 vec_add2 (sm->addresses, ap, 1);
583 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
587 #define _(N, i, n, s) \
588 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
589 ap->busy_##n##_ports = 0; \
590 ap->busy_##n##_ports_per_thread = 0;\
591 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
592 foreach_snat_protocol
597 /* Add external address to FIB */
599 pool_foreach (i, sm->interfaces,
601 if (nat_interface_is_inside(i) || sm->out2in_dpo)
604 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
607 pool_foreach (i, sm->output_feature_interfaces,
609 if (nat_interface_is_inside(i) || sm->out2in_dpo)
612 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
621 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
623 snat_static_mapping_t *m;
625 pool_foreach (m, sm->static_mappings,
627 if (is_addr_only_static_mapping (m) ||
628 is_out2in_only_static_mapping (m) ||
629 is_identity_static_mapping (m))
631 if (m->external_addr.as_u32 == addr.as_u32)
640 increment_v4_address (ip4_address_t * a)
644 v = clib_net_to_host_u32 (a->as_u32) + 1;
645 a->as_u32 = clib_host_to_net_u32 (v);
649 snat_add_static_mapping_when_resolved (snat_main_t * sm,
650 ip4_address_t l_addr,
655 snat_protocol_t proto,
656 int addr_only, int is_add, u8 * tag,
657 int twice_nat, int out2in_only,
660 snat_static_map_resolve_t *rp;
662 vec_add2 (sm->to_resolve, rp, 1);
663 rp->l_addr.as_u32 = l_addr.as_u32;
665 rp->sw_if_index = sw_if_index;
669 rp->addr_only = addr_only;
671 rp->twice_nat = twice_nat;
672 rp->out2in_only = out2in_only;
673 rp->identity_nat = identity_nat;
674 rp->tag = vec_dup (tag);
678 get_thread_idx_by_port (u16 e_port)
680 snat_main_t *sm = &snat_main;
681 u32 thread_idx = sm->num_workers;
682 if (sm->num_workers > 1)
685 sm->first_worker_index +
686 sm->workers[(e_port - 1024) / sm->port_per_thread];
692 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
693 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
694 u32 sw_if_index, snat_protocol_t proto, int is_add,
695 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
698 snat_main_t *sm = &snat_main;
699 snat_static_mapping_t *m;
700 snat_session_key_t m_key;
701 clib_bihash_kv_8_8_t kv, value;
702 snat_address_t *a = 0;
704 snat_interface_t *interface;
706 snat_main_per_thread_data_t *tsm;
707 snat_user_key_t u_key;
709 dlist_elt_t *head, *elt;
710 u32 elt_index, head_index;
714 snat_static_map_resolve_t *rp, *rp_match = 0;
715 nat44_lb_addr_port_t *local;
718 if (!sm->endpoint_dependent)
720 if (twice_nat || out2in_only)
721 return VNET_API_ERROR_FEATURE_DISABLED;
724 /* If the external address is a specific interface address */
725 if (sw_if_index != ~0)
727 ip4_address_t *first_int_addr;
729 for (i = 0; i < vec_len (sm->to_resolve); i++)
731 rp = sm->to_resolve + i;
732 if (rp->sw_if_index != sw_if_index ||
733 rp->l_addr.as_u32 != l_addr.as_u32 ||
734 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
739 if ((rp->l_port != l_port && rp->e_port != e_port)
740 || rp->proto != proto)
748 /* Might be already set... */
749 first_int_addr = ip4_interface_first_address
750 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
755 return VNET_API_ERROR_VALUE_EXIST;
757 snat_add_static_mapping_when_resolved
758 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
759 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
761 /* DHCP resolution required? */
762 if (first_int_addr == 0)
768 e_addr.as_u32 = first_int_addr->as_u32;
769 /* Identity mapping? */
770 if (l_addr.as_u32 == 0)
771 l_addr.as_u32 = e_addr.as_u32;
777 return VNET_API_ERROR_NO_SUCH_ENTRY;
779 vec_del1 (sm->to_resolve, i);
783 e_addr.as_u32 = first_int_addr->as_u32;
784 /* Identity mapping? */
785 if (l_addr.as_u32 == 0)
786 l_addr.as_u32 = e_addr.as_u32;
794 m_key.port = addr_only ? 0 : e_port;
795 m_key.protocol = addr_only ? 0 : proto;
797 kv.key = m_key.as_u64;
798 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
801 m = pool_elt_at_index (sm->static_mappings, value.value);
807 if (is_identity_static_mapping (m))
810 pool_foreach (local, m->locals,
812 if (local->vrf_id == vrf_id)
813 return VNET_API_ERROR_VALUE_EXIST;
816 pool_get (m->locals, local);
817 local->vrf_id = vrf_id;
819 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
821 m_key.addr = m->local_addr;
822 m_key.port = m->local_port;
823 m_key.protocol = m->proto;
824 m_key.fib_index = local->fib_index;
825 kv.key = m_key.as_u64;
826 kv.value = m - sm->static_mappings;
827 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
831 return VNET_API_ERROR_VALUE_EXIST;
834 if (twice_nat && addr_only)
835 return VNET_API_ERROR_UNSUPPORTED;
837 /* Convert VRF id to FIB index */
840 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
842 /* If not specified use inside VRF id from SNAT plugin startup config */
845 fib_index = sm->inside_fib_index;
846 vrf_id = sm->inside_vrf_id;
847 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
850 if (!(out2in_only || identity_nat))
853 m_key.port = addr_only ? 0 : l_port;
854 m_key.protocol = addr_only ? 0 : proto;
855 m_key.fib_index = fib_index;
856 kv.key = m_key.as_u64;
857 if (!clib_bihash_search_8_8
858 (&sm->static_mapping_by_local, &kv, &value))
859 return VNET_API_ERROR_VALUE_EXIST;
862 /* Find external address in allocated addresses and reserve port for
863 address and port pair mapping when dynamic translations enabled */
864 if (!(addr_only || sm->static_mapping_only || out2in_only))
866 for (i = 0; i < vec_len (sm->addresses); i++)
868 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
870 a = sm->addresses + i;
871 /* External port must be unused */
874 #define _(N, j, n, s) \
875 case SNAT_PROTOCOL_##N: \
876 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
877 return VNET_API_ERROR_INVALID_VALUE; \
878 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
881 a->busy_##n##_ports++; \
882 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
885 foreach_snat_protocol
888 nat_elog_info ("unknown protocol");
889 return VNET_API_ERROR_INVALID_VALUE_2;
894 /* External address must be allocated */
895 if (!a && (l_addr.as_u32 != e_addr.as_u32))
897 if (sw_if_index != ~0)
899 for (i = 0; i < vec_len (sm->to_resolve); i++)
901 rp = sm->to_resolve + i;
904 if (rp->sw_if_index != sw_if_index &&
905 rp->l_addr.as_u32 != l_addr.as_u32 &&
906 rp->vrf_id != vrf_id && rp->l_port != l_port &&
907 rp->e_port != e_port && rp->proto != proto)
910 vec_del1 (sm->to_resolve, i);
914 return VNET_API_ERROR_NO_SUCH_ENTRY;
918 pool_get (sm->static_mappings, m);
919 clib_memset (m, 0, sizeof (*m));
920 m->tag = vec_dup (tag);
921 m->local_addr = l_addr;
922 m->external_addr = e_addr;
923 m->twice_nat = twice_nat;
925 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
927 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
930 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
931 pool_get (m->locals, local);
932 local->vrf_id = vrf_id;
933 local->fib_index = fib_index;
938 m->fib_index = fib_index;
942 m->local_port = l_port;
943 m->external_port = e_port;
947 if (sm->num_workers > 1)
950 .src_address = m->local_addr,
952 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
953 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
956 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
958 m_key.addr = m->local_addr;
959 m_key.port = m->local_port;
960 m_key.protocol = m->proto;
961 m_key.fib_index = fib_index;
962 kv.key = m_key.as_u64;
963 kv.value = m - sm->static_mappings;
965 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
967 m_key.addr = m->external_addr;
968 m_key.port = m->external_port;
970 kv.key = m_key.as_u64;
971 kv.value = m - sm->static_mappings;
972 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
974 /* Delete dynamic sessions matching local address (+ local port) */
975 if (!(sm->static_mapping_only))
977 u_key.addr = m->local_addr;
978 u_key.fib_index = m->fib_index;
979 kv.key = u_key.as_u64;
980 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
982 user_index = value.value;
983 u = pool_elt_at_index (tsm->users, user_index);
986 head_index = u->sessions_per_user_list_head_index;
987 head = pool_elt_at_index (tsm->list_pool, head_index);
988 elt_index = head->next;
989 elt = pool_elt_at_index (tsm->list_pool, elt_index);
990 ses_index = elt->value;
991 while (ses_index != ~0)
993 s = pool_elt_at_index (tsm->sessions, ses_index);
994 elt = pool_elt_at_index (tsm->list_pool, elt->next);
995 ses_index = elt->value;
997 if (snat_is_session_static (s))
1001 && (clib_net_to_host_u16 (s->in2out.port) !=
1005 nat_free_session_data (sm, s,
1006 tsm - sm->per_thread_data, 0);
1007 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1009 if (!addr_only && !sm->endpoint_dependent)
1020 if (sw_if_index != ~0)
1023 return VNET_API_ERROR_NO_SUCH_ENTRY;
1029 vrf_id = sm->inside_vrf_id;
1032 pool_foreach (local, m->locals,
1034 if (local->vrf_id == vrf_id)
1035 find = local - m->locals;
1039 return VNET_API_ERROR_NO_SUCH_ENTRY;
1041 local = pool_elt_at_index (m->locals, find);
1042 fib_index = local->fib_index;
1043 pool_put (m->locals, local);
1046 fib_index = m->fib_index;
1048 /* Free external address port */
1049 if (!(addr_only || sm->static_mapping_only || out2in_only))
1051 for (i = 0; i < vec_len (sm->addresses); i++)
1053 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1055 a = sm->addresses + i;
1058 #define _(N, j, n, s) \
1059 case SNAT_PROTOCOL_##N: \
1060 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1061 if (e_port > 1024) \
1063 a->busy_##n##_ports--; \
1064 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1067 foreach_snat_protocol
1070 nat_elog_info ("unknown protocol");
1071 return VNET_API_ERROR_INVALID_VALUE_2;
1078 if (sm->num_workers > 1)
1079 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1081 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1083 m_key.addr = m->local_addr;
1084 m_key.port = m->local_port;
1085 m_key.protocol = m->proto;
1086 m_key.fib_index = fib_index;
1087 kv.key = m_key.as_u64;
1089 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1091 /* Delete session(s) for static mapping if exist */
1092 if (!(sm->static_mapping_only) ||
1093 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1095 u_key.addr = m->local_addr;
1096 u_key.fib_index = fib_index;
1097 kv.key = u_key.as_u64;
1098 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1100 user_index = value.value;
1101 u = pool_elt_at_index (tsm->users, user_index);
1102 if (u->nstaticsessions)
1104 head_index = u->sessions_per_user_list_head_index;
1105 head = pool_elt_at_index (tsm->list_pool, head_index);
1106 elt_index = head->next;
1107 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1108 ses_index = elt->value;
1109 while (ses_index != ~0)
1111 s = pool_elt_at_index (tsm->sessions, ses_index);
1112 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1113 ses_index = elt->value;
1117 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1118 (clib_net_to_host_u16 (s->out2in.port) !=
1123 if (is_lb_session (s))
1126 if (!snat_is_session_static (s))
1129 nat_free_session_data (sm, s,
1130 tsm - sm->per_thread_data, 0);
1131 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1133 if (!addr_only && !sm->endpoint_dependent)
1140 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1141 if (pool_elts (m->locals))
1144 m_key.addr = m->external_addr;
1145 m_key.port = m->external_port;
1146 m_key.fib_index = 0;
1147 kv.key = m_key.as_u64;
1148 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1151 vec_free (m->workers);
1152 /* Delete static mapping from pool */
1153 pool_put (sm->static_mappings, m);
1156 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1159 /* Add/delete external address to FIB */
1161 pool_foreach (interface, sm->interfaces,
1163 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1166 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1169 pool_foreach (interface, sm->output_feature_interfaces,
1171 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1174 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1183 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1184 snat_protocol_t proto,
1185 nat44_lb_addr_port_t * locals, u8 is_add,
1186 twice_nat_type_t twice_nat, u8 out2in_only,
1187 u8 * tag, u32 affinity)
1189 snat_main_t *sm = &snat_main;
1190 snat_static_mapping_t *m;
1191 snat_session_key_t m_key;
1192 clib_bihash_kv_8_8_t kv, value;
1193 snat_address_t *a = 0;
1195 nat44_lb_addr_port_t *local;
1196 u32 elt_index, head_index, ses_index;
1197 snat_main_per_thread_data_t *tsm;
1198 snat_user_key_t u_key;
1201 dlist_elt_t *head, *elt;
1204 if (!sm->endpoint_dependent)
1205 return VNET_API_ERROR_FEATURE_DISABLED;
1207 m_key.addr = e_addr;
1208 m_key.port = e_port;
1209 m_key.protocol = proto;
1210 m_key.fib_index = 0;
1211 kv.key = m_key.as_u64;
1212 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1215 m = pool_elt_at_index (sm->static_mappings, value.value);
1220 return VNET_API_ERROR_VALUE_EXIST;
1222 if (vec_len (locals) < 2)
1223 return VNET_API_ERROR_INVALID_VALUE;
1225 /* Find external address in allocated addresses and reserve port for
1226 address and port pair mapping when dynamic translations enabled */
1227 if (!(sm->static_mapping_only || out2in_only))
1229 for (i = 0; i < vec_len (sm->addresses); i++)
1231 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1233 a = sm->addresses + i;
1234 /* External port must be unused */
1237 #define _(N, j, n, s) \
1238 case SNAT_PROTOCOL_##N: \
1239 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1240 return VNET_API_ERROR_INVALID_VALUE; \
1241 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1242 if (e_port > 1024) \
1244 a->busy_##n##_ports++; \
1245 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1248 foreach_snat_protocol
1251 nat_elog_info ("unknown protocol");
1252 return VNET_API_ERROR_INVALID_VALUE_2;
1257 /* External address must be allocated */
1259 return VNET_API_ERROR_NO_SUCH_ENTRY;
1262 pool_get (sm->static_mappings, m);
1263 clib_memset (m, 0, sizeof (*m));
1264 m->tag = vec_dup (tag);
1265 m->external_addr = e_addr;
1266 m->external_port = e_port;
1268 m->twice_nat = twice_nat;
1269 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1271 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1272 m->affinity = affinity;
1275 m->affinity_per_service_list_head_index =
1276 nat_affinity_get_per_service_list_head_index ();
1278 m->affinity_per_service_list_head_index = ~0;
1280 m_key.addr = m->external_addr;
1281 m_key.port = m->external_port;
1282 m_key.protocol = m->proto;
1283 m_key.fib_index = 0;
1284 kv.key = m_key.as_u64;
1285 kv.value = m - sm->static_mappings;
1286 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1288 nat_elog_err ("static_mapping_by_external key add failed");
1289 return VNET_API_ERROR_UNSPECIFIED;
1292 m_key.fib_index = m->fib_index;
1293 for (i = 0; i < vec_len (locals); i++)
1295 locals[i].fib_index =
1296 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1299 m_key.addr = locals[i].addr;
1300 m_key.fib_index = locals[i].fib_index;
1303 m_key.port = locals[i].port;
1304 kv.key = m_key.as_u64;
1305 kv.value = m - sm->static_mappings;
1306 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1308 locals[i].prefix = (i == 0) ? locals[i].probability :
1309 (locals[i - 1].prefix + locals[i].probability);
1310 pool_get (m->locals, local);
1312 if (sm->num_workers > 1)
1315 .src_address = locals[i].addr,
1318 clib_bitmap_set (bitmap,
1319 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1324 /* Assign workers */
1325 if (sm->num_workers > 1)
1328 clib_bitmap_foreach (i, bitmap,
1330 vec_add1(m->workers, i);
1338 return VNET_API_ERROR_NO_SUCH_ENTRY;
1340 if (!is_lb_static_mapping (m))
1341 return VNET_API_ERROR_INVALID_VALUE;
1343 /* Free external address port */
1344 if (!(sm->static_mapping_only || out2in_only))
1346 for (i = 0; i < vec_len (sm->addresses); i++)
1348 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1350 a = sm->addresses + i;
1353 #define _(N, j, n, s) \
1354 case SNAT_PROTOCOL_##N: \
1355 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1356 if (e_port > 1024) \
1358 a->busy_##n##_ports--; \
1359 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1362 foreach_snat_protocol
1365 nat_elog_info ("unknown protocol");
1366 return VNET_API_ERROR_INVALID_VALUE_2;
1373 m_key.addr = m->external_addr;
1374 m_key.port = m->external_port;
1375 m_key.protocol = m->proto;
1376 m_key.fib_index = 0;
1377 kv.key = m_key.as_u64;
1378 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1380 nat_elog_err ("static_mapping_by_external key del failed");
1381 return VNET_API_ERROR_UNSPECIFIED;
1385 pool_foreach (local, m->locals,
1387 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1389 m_key.addr = local->addr;
1392 m_key.port = local->port;
1393 m_key.fib_index = local->fib_index;
1394 kv.key = m_key.as_u64;
1395 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1397 nat_elog_err ("static_mapping_by_local key del failed");
1398 return VNET_API_ERROR_UNSPECIFIED;
1402 if (sm->num_workers > 1)
1405 .src_address = local->addr,
1407 tsm = vec_elt_at_index (sm->per_thread_data,
1408 sm->worker_in2out_cb (&ip, m->fib_index, 0));
1411 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1413 /* Delete sessions */
1414 u_key.addr = local->addr;
1415 u_key.fib_index = local->fib_index;
1416 kv.key = u_key.as_u64;
1417 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1419 u = pool_elt_at_index (tsm->users, value.value);
1420 if (u->nstaticsessions)
1422 head_index = u->sessions_per_user_list_head_index;
1423 head = pool_elt_at_index (tsm->list_pool, head_index);
1424 elt_index = head->next;
1425 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1426 ses_index = elt->value;
1427 while (ses_index != ~0)
1429 s = pool_elt_at_index (tsm->sessions, ses_index);
1430 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1431 ses_index = elt->value;
1433 if (!(is_lb_session (s)))
1436 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1437 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1440 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1441 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1448 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1449 pool_free (m->locals);
1451 vec_free (m->workers);
1453 pool_put (sm->static_mappings, m);
1460 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1461 ip4_address_t l_addr, u16 l_port,
1462 snat_protocol_t proto, u32 vrf_id,
1463 u8 probability, u8 is_add)
1465 snat_main_t *sm = &snat_main;
1466 snat_static_mapping_t *m = 0;
1467 snat_session_key_t m_key;
1468 clib_bihash_kv_8_8_t kv, value;
1469 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1470 snat_main_per_thread_data_t *tsm;
1471 snat_user_key_t u_key;
1474 dlist_elt_t *head, *elt;
1475 u32 elt_index, head_index, ses_index, *locals = 0;
1479 if (!sm->endpoint_dependent)
1480 return VNET_API_ERROR_FEATURE_DISABLED;
1482 m_key.addr = e_addr;
1483 m_key.port = e_port;
1484 m_key.protocol = proto;
1485 m_key.fib_index = 0;
1486 kv.key = m_key.as_u64;
1487 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1488 m = pool_elt_at_index (sm->static_mappings, value.value);
1491 return VNET_API_ERROR_NO_SUCH_ENTRY;
1493 if (!is_lb_static_mapping (m))
1494 return VNET_API_ERROR_INVALID_VALUE;
1497 pool_foreach (local, m->locals,
1499 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1500 (local->vrf_id == vrf_id))
1502 match_local = local;
1511 return VNET_API_ERROR_VALUE_EXIST;
1513 pool_get (m->locals, local);
1514 clib_memset (local, 0, sizeof (*local));
1515 local->addr.as_u32 = l_addr.as_u32;
1516 local->port = l_port;
1517 local->probability = probability;
1518 local->vrf_id = vrf_id;
1520 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1523 if (!is_out2in_only_static_mapping (m))
1525 m_key.addr = l_addr;
1526 m_key.port = l_port;
1527 m_key.fib_index = local->fib_index;
1528 kv.key = m_key.as_u64;
1529 kv.value = m - sm->static_mappings;
1530 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1531 nat_elog_err ("static_mapping_by_local key add failed");
1537 return VNET_API_ERROR_NO_SUCH_ENTRY;
1539 if (pool_elts (m->locals) < 3)
1540 return VNET_API_ERROR_UNSPECIFIED;
1542 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1545 if (!is_out2in_only_static_mapping (m))
1547 m_key.addr = l_addr;
1548 m_key.port = l_port;
1549 m_key.fib_index = match_local->fib_index;
1550 kv.key = m_key.as_u64;
1551 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1552 nat_elog_err ("static_mapping_by_local key del failed");
1555 if (sm->num_workers > 1)
1558 .src_address = local->addr,
1560 tsm = vec_elt_at_index (sm->per_thread_data,
1561 sm->worker_in2out_cb (&ip, m->fib_index,
1565 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1567 /* Delete sessions */
1568 u_key.addr = match_local->addr;
1569 u_key.fib_index = match_local->fib_index;
1570 kv.key = u_key.as_u64;
1571 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1573 u = pool_elt_at_index (tsm->users, value.value);
1574 if (u->nstaticsessions)
1576 head_index = u->sessions_per_user_list_head_index;
1577 head = pool_elt_at_index (tsm->list_pool, head_index);
1578 elt_index = head->next;
1579 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1580 ses_index = elt->value;
1581 while (ses_index != ~0)
1583 s = pool_elt_at_index (tsm->sessions, ses_index);
1584 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1585 ses_index = elt->value;
1587 if (!(is_lb_session (s)))
1590 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1591 (clib_net_to_host_u16 (s->in2out.port) !=
1595 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1596 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1601 pool_put (m->locals, match_local);
1604 vec_free (m->workers);
1607 pool_foreach (local, m->locals,
1609 vec_add1 (locals, local - m->locals);
1610 if (sm->num_workers > 1)
1613 ip.src_address.as_u32 = local->addr.as_u32,
1614 bitmap = clib_bitmap_set (bitmap,
1615 sm->worker_in2out_cb (&ip, local->fib_index, 0),
1621 ASSERT (vec_len (locals) > 1);
1623 local = pool_elt_at_index (m->locals, locals[0]);
1624 local->prefix = local->probability;
1625 for (i = 1; i < vec_len (locals); i++)
1627 local = pool_elt_at_index (m->locals, locals[i]);
1628 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1629 local->prefix = local->probability + prev_local->prefix;
1632 /* Assign workers */
1633 if (sm->num_workers > 1)
1636 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1644 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1647 snat_address_t *a = 0;
1648 snat_session_t *ses;
1649 u32 *ses_to_be_removed = 0, *ses_index;
1650 snat_main_per_thread_data_t *tsm;
1651 snat_static_mapping_t *m;
1652 snat_interface_t *interface;
1654 snat_address_t *addresses =
1655 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1657 /* Find SNAT address */
1658 for (i = 0; i < vec_len (addresses); i++)
1660 if (addresses[i].addr.as_u32 == addr.as_u32)
1667 return VNET_API_ERROR_NO_SUCH_ENTRY;
1672 pool_foreach (m, sm->static_mappings,
1674 if (m->external_addr.as_u32 == addr.as_u32)
1675 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1676 m->local_port, m->external_port,
1677 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1678 m->proto, 0, m->twice_nat,
1679 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1685 /* Check if address is used in some static mapping */
1686 if (is_snat_address_used_in_static_mapping (sm, addr))
1688 nat_elog_notice ("address used in static mapping");
1689 return VNET_API_ERROR_UNSPECIFIED;
1693 if (a->fib_index != ~0)
1694 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1696 /* Delete sessions using address */
1697 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1700 vec_foreach (tsm, sm->per_thread_data)
1702 pool_foreach (ses, tsm->sessions, ({
1703 if (ses->out2in.addr.as_u32 == addr.as_u32)
1705 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1706 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1710 vec_foreach (ses_index, ses_to_be_removed)
1712 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1713 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1716 vec_free (ses_to_be_removed);
1721 #define _(N, i, n, s) \
1722 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1723 vec_free (a->busy_##n##_ports_per_thread);
1724 foreach_snat_protocol
1728 vec_del1 (sm->twice_nat_addresses, i);
1732 vec_del1 (sm->addresses, i);
1734 /* Delete external address from FIB */
1736 pool_foreach (interface, sm->interfaces,
1738 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1741 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1744 pool_foreach (interface, sm->output_feature_interfaces,
1746 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1749 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1758 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1760 snat_main_t *sm = &snat_main;
1761 snat_interface_t *i;
1762 const char *feature_name, *del_feature_name;
1764 snat_static_mapping_t *m;
1766 nat_outside_fib_t *outside_fib;
1767 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1770 if (sm->out2in_dpo && !is_inside)
1771 return VNET_API_ERROR_UNSUPPORTED;
1774 pool_foreach (i, sm->output_feature_interfaces,
1776 if (i->sw_if_index == sw_if_index)
1777 return VNET_API_ERROR_VALUE_EXIST;
1781 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1782 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1785 if (sm->num_workers > 1 && !sm->deterministic)
1787 is_inside ? "nat44-in2out-worker-handoff" :
1788 "nat44-out2in-worker-handoff";
1789 else if (sm->deterministic)
1790 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1791 else if (sm->endpoint_dependent)
1793 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1796 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1799 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1800 sm->fq_in2out_index =
1801 vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
1803 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1804 sm->fq_out2in_index =
1805 vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
1810 vec_foreach (outside_fib, sm->outside_fibs)
1812 if (outside_fib->fib_index == fib_index)
1816 outside_fib->refcount--;
1817 if (!outside_fib->refcount)
1818 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1821 outside_fib->refcount++;
1828 vec_add2 (sm->outside_fibs, outside_fib, 1);
1829 outside_fib->refcount = 1;
1830 outside_fib->fib_index = fib_index;
1835 pool_foreach (i, sm->interfaces,
1837 if (i->sw_if_index == sw_if_index)
1841 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1844 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1846 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1848 if (sm->num_workers > 1 && !sm->deterministic)
1850 del_feature_name = "nat44-handoff-classify";
1851 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1852 "nat44-out2in-worker-handoff";
1854 else if (sm->deterministic)
1856 del_feature_name = "nat44-det-classify";
1857 feature_name = !is_inside ? "nat44-det-in2out" :
1860 else if (sm->endpoint_dependent)
1862 del_feature_name = "nat44-ed-classify";
1863 feature_name = !is_inside ? "nat-pre-in2out" :
1868 del_feature_name = "nat44-classify";
1869 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1872 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1873 sw_if_index, 0, 0, 0);
1874 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1875 sw_if_index, 1, 0, 0);
1878 if (sm->endpoint_dependent)
1879 vnet_feature_enable_disable ("ip4-local",
1880 "nat44-ed-hairpinning",
1881 sw_if_index, 1, 0, 0);
1882 else if (!sm->deterministic)
1883 vnet_feature_enable_disable ("ip4-local",
1884 "nat44-hairpinning",
1885 sw_if_index, 1, 0, 0);
1890 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1891 sw_if_index, 0, 0, 0);
1892 pool_put (sm->interfaces, i);
1895 if (sm->endpoint_dependent)
1896 vnet_feature_enable_disable ("ip4-local",
1897 "nat44-ed-hairpinning",
1898 sw_if_index, 0, 0, 0);
1899 else if (!sm->deterministic)
1900 vnet_feature_enable_disable ("ip4-local",
1901 "nat44-hairpinning",
1902 sw_if_index, 0, 0, 0);
1908 if ((nat_interface_is_inside(i) && is_inside) ||
1909 (nat_interface_is_outside(i) && !is_inside))
1912 if (sm->num_workers > 1 && !sm->deterministic)
1914 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1915 "nat44-out2in-worker-handoff";
1916 feature_name = "nat44-handoff-classify";
1918 else if (sm->deterministic)
1920 del_feature_name = !is_inside ? "nat44-det-in2out" :
1922 feature_name = "nat44-det-classify";
1924 else if (sm->endpoint_dependent)
1926 del_feature_name = !is_inside ? "nat-pre-in2out" :
1929 feature_name = "nat44-ed-classify";
1933 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1934 feature_name = "nat44-classify";
1937 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1938 sw_if_index, 0, 0, 0);
1939 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1940 sw_if_index, 1, 0, 0);
1943 if (sm->endpoint_dependent)
1944 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1945 sw_if_index, 0, 0, 0);
1946 else if (!sm->deterministic)
1947 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1948 sw_if_index, 0, 0, 0);
1959 return VNET_API_ERROR_NO_SUCH_ENTRY;
1961 pool_get (sm->interfaces, i);
1962 i->sw_if_index = sw_if_index;
1964 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1967 if (is_inside && !sm->out2in_dpo)
1969 if (sm->endpoint_dependent)
1970 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1971 sw_if_index, 1, 0, 0);
1972 else if (!sm->deterministic)
1973 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1974 sw_if_index, 1, 0, 0);
1980 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1984 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1986 /* Add/delete external addresses to FIB */
1989 vec_foreach (ap, sm->addresses)
1990 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1992 pool_foreach (m, sm->static_mappings,
1994 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1997 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2000 pool_foreach (dm, sm->det_maps,
2002 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2010 snat_interface_add_del_output_feature (u32 sw_if_index,
2011 u8 is_inside, int is_del)
2013 snat_main_t *sm = &snat_main;
2014 snat_interface_t *i;
2016 snat_static_mapping_t *m;
2017 nat_outside_fib_t *outside_fib;
2018 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2022 if (sm->deterministic ||
2023 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2024 return VNET_API_ERROR_UNSUPPORTED;
2027 pool_foreach (i, sm->interfaces,
2029 if (i->sw_if_index == sw_if_index)
2030 return VNET_API_ERROR_VALUE_EXIST;
2037 vec_foreach (outside_fib, sm->outside_fibs)
2039 if (outside_fib->fib_index == fib_index)
2043 outside_fib->refcount--;
2044 if (!outside_fib->refcount)
2045 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2048 outside_fib->refcount++;
2055 vec_add2 (sm->outside_fibs, outside_fib, 1);
2056 outside_fib->refcount = 1;
2057 outside_fib->fib_index = fib_index;
2064 if (sm->endpoint_dependent)
2066 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2067 sw_if_index, !is_del, 0, 0);
2068 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2069 sw_if_index, !is_del, 0, 0);
2073 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2074 sw_if_index, !is_del, 0, 0);
2075 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2076 sw_if_index, !is_del, 0, 0);
2081 if (sm->num_workers > 1)
2083 vnet_feature_enable_disable ("ip4-unicast",
2084 "nat44-out2in-worker-handoff",
2085 sw_if_index, !is_del, 0, 0);
2086 vnet_feature_enable_disable ("ip4-output",
2087 "nat44-in2out-output-worker-handoff",
2088 sw_if_index, !is_del, 0, 0);
2092 if (sm->endpoint_dependent)
2094 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2095 sw_if_index, !is_del, 0, 0);
2096 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2097 sw_if_index, !is_del, 0, 0);
2101 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2102 sw_if_index, !is_del, 0, 0);
2103 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2104 sw_if_index, !is_del, 0, 0);
2109 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2110 sm->fq_in2out_output_index =
2111 vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
2113 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2114 sm->fq_out2in_index =
2115 vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
2118 pool_foreach (i, sm->output_feature_interfaces,
2120 if (i->sw_if_index == sw_if_index)
2123 pool_put (sm->output_feature_interfaces, i);
2125 return VNET_API_ERROR_VALUE_EXIST;
2133 return VNET_API_ERROR_NO_SUCH_ENTRY;
2135 pool_get (sm->output_feature_interfaces, i);
2136 i->sw_if_index = sw_if_index;
2139 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2141 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2143 /* Add/delete external addresses to FIB */
2149 vec_foreach (ap, sm->addresses)
2150 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2152 pool_foreach (m, sm->static_mappings,
2154 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2157 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2165 snat_set_workers (uword * bitmap)
2167 snat_main_t *sm = &snat_main;
2170 if (sm->num_workers < 2)
2171 return VNET_API_ERROR_FEATURE_DISABLED;
2173 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2174 return VNET_API_ERROR_INVALID_WORKER;
2176 vec_free (sm->workers);
2178 clib_bitmap_foreach (i, bitmap,
2180 vec_add1(sm->workers, i);
2181 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2182 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2187 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2188 sm->num_snat_thread = _vec_len (sm->workers);
2194 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2197 snat_main_t *sm = &snat_main;
2198 nat_outside_fib_t *outside_fib;
2199 snat_interface_t *i;
2203 if (new_fib_index == old_fib_index)
2206 if (!vec_len (sm->outside_fibs))
2210 pool_foreach (i, sm->interfaces,
2212 if (i->sw_if_index == sw_if_index)
2214 if (!(nat_interface_is_outside (i)))
2220 pool_foreach (i, sm->output_feature_interfaces,
2222 if (i->sw_if_index == sw_if_index)
2224 if (!(nat_interface_is_outside (i)))
2234 vec_foreach (outside_fib, sm->outside_fibs)
2236 if (outside_fib->fib_index == old_fib_index)
2238 outside_fib->refcount--;
2239 if (!outside_fib->refcount)
2240 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2245 vec_foreach (outside_fib, sm->outside_fibs)
2247 if (outside_fib->fib_index == new_fib_index)
2249 outside_fib->refcount++;
2257 vec_add2 (sm->outside_fibs, outside_fib, 1);
2258 outside_fib->refcount = 1;
2259 outside_fib->fib_index = new_fib_index;
2264 snat_ip4_table_bind (ip4_main_t * im,
2266 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2268 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2272 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2275 ip4_address_t * address,
2277 u32 if_address_index, u32 is_delete);
2280 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2283 ip4_address_t * address,
2285 u32 if_address_index, u32 is_delete);
2288 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2291 snat_session_key_t * k,
2292 u16 port_per_thread, u32 snat_thread_index);
2294 static clib_error_t *
2295 snat_init (vlib_main_t * vm)
2297 snat_main_t *sm = &snat_main;
2298 clib_error_t *error = 0;
2299 ip4_main_t *im = &ip4_main;
2300 ip_lookup_main_t *lm = &im->lookup_main;
2302 vlib_thread_registration_t *tr;
2303 vlib_thread_main_t *tm = vlib_get_thread_main ();
2306 ip4_add_del_interface_address_callback_t cb4;
2310 sm->vnet_main = vnet_get_main ();
2312 sm->ip4_lookup_main = lm;
2313 sm->api_main = vlibapi_get_main ();
2314 sm->first_worker_index = 0;
2315 sm->num_workers = 0;
2316 sm->num_snat_thread = 1;
2318 sm->port_per_thread = 0xffff - 1024;
2319 sm->fq_in2out_index = ~0;
2320 sm->fq_in2out_output_index = ~0;
2321 sm->fq_out2in_index = ~0;
2324 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2325 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2326 sm->forwarding_enabled = 0;
2327 sm->log_class = vlib_log_register_class ("nat", 0);
2328 sm->log_level = SNAT_LOG_ERROR;
2329 sm->mss_clamping = 0;
2331 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2332 sm->error_node_index = node->index;
2334 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2335 sm->pre_in2out_node_index = node->index;
2336 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2337 sm->pre_out2in_node_index = node->index;
2339 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2340 sm->pre_in2out_node_index = node->index;
2342 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2343 sm->pre_out2in_node_index = node->index;
2345 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2346 sm->in2out_node_index = node->index;
2347 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2348 sm->in2out_output_node_index = node->index;
2349 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2350 sm->in2out_fast_node_index = node->index;
2351 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2352 sm->in2out_slowpath_node_index = node->index;
2353 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2354 sm->in2out_slowpath_output_node_index = node->index;
2355 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-reass");
2356 sm->in2out_reass_node_index = node->index;
2358 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2359 sm->ed_in2out_node_index = node->index;
2360 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2361 sm->ed_in2out_slowpath_node_index = node->index;
2362 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-reass");
2363 sm->ed_in2out_reass_node_index = node->index;
2365 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2366 sm->out2in_node_index = node->index;
2367 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2368 sm->out2in_fast_node_index = node->index;
2369 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-reass");
2370 sm->out2in_reass_node_index = node->index;
2372 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2373 sm->ed_out2in_node_index = node->index;
2374 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2375 sm->ed_out2in_slowpath_node_index = node->index;
2376 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-reass");
2377 sm->ed_out2in_reass_node_index = node->index;
2379 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2380 sm->det_in2out_node_index = node->index;
2381 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2382 sm->det_out2in_node_index = node->index;
2384 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2385 sm->hairpinning_node_index = node->index;
2386 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2387 sm->hairpin_dst_node_index = node->index;
2388 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2389 sm->hairpin_src_node_index = node->index;
2390 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2391 sm->ed_hairpinning_node_index = node->index;
2392 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2393 sm->ed_hairpin_dst_node_index = node->index;
2394 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2395 sm->ed_hairpin_src_node_index = node->index;
2397 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2400 tr = (vlib_thread_registration_t *) p[0];
2403 sm->num_workers = tr->count;
2404 sm->first_worker_index = tr->first_index;
2408 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2410 /* Use all available workers by default */
2411 if (sm->num_workers > 1)
2413 for (i = 0; i < sm->num_workers; i++)
2414 bitmap = clib_bitmap_set (bitmap, i, 1);
2415 snat_set_workers (bitmap);
2416 clib_bitmap_free (bitmap);
2420 sm->per_thread_data[0].snat_thread_index = 0;
2423 error = snat_api_init (vm, sm);
2427 /* Set up the interface address add/del callback */
2428 cb4.function = snat_ip4_add_del_interface_address_cb;
2429 cb4.function_opaque = 0;
2431 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2433 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2434 cb4.function_opaque = 0;
2436 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2438 nat_dpo_module_init ();
2441 sm->total_users.name = "total-users";
2442 sm->total_users.stat_segment_name = "/nat44/total-users";
2443 vlib_validate_simple_counter (&sm->total_users, 0);
2444 vlib_zero_simple_counter (&sm->total_users, 0);
2445 sm->total_sessions.name = "total-sessions";
2446 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2447 vlib_validate_simple_counter (&sm->total_sessions, 0);
2448 vlib_zero_simple_counter (&sm->total_sessions, 0);
2450 /* Init IPFIX logging */
2451 snat_ipfix_logging_init (vm);
2454 error = nat64_init (vm);
2462 ip4_table_bind_callback_t cbt4 = {
2463 .function = snat_ip4_table_bind,
2465 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2467 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2468 FIB_SOURCE_PRIORITY_HI,
2469 FIB_SOURCE_BH_SIMPLE);
2470 nat_fib_src_low = fib_source_allocate ("nat-low",
2471 FIB_SOURCE_PRIORITY_LOW,
2472 FIB_SOURCE_BH_SIMPLE);
2474 /* Init virtual fragmenentation reassembly */
2475 return nat_reass_init (vm);
2478 VLIB_INIT_FUNCTION (snat_init);
2481 snat_free_outside_address_and_port (snat_address_t * addresses,
2482 u32 thread_index, snat_session_key_t * k)
2486 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2488 for (address_index = 0; address_index < vec_len (addresses);
2491 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2495 ASSERT (address_index < vec_len (addresses));
2497 a = addresses + address_index;
2499 switch (k->protocol)
2501 #define _(N, i, n, s) \
2502 case SNAT_PROTOCOL_##N: \
2503 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2504 port_host_byte_order) == 1); \
2505 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2506 port_host_byte_order, 0); \
2507 a->busy_##n##_ports--; \
2508 a->busy_##n##_ports_per_thread[thread_index]--; \
2510 foreach_snat_protocol
2513 nat_elog_info ("unknown protocol");
2519 nat_set_outside_address_and_port (snat_address_t * addresses,
2520 u32 thread_index, snat_session_key_t * k)
2522 snat_address_t *a = 0;
2524 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2526 for (address_index = 0; address_index < vec_len (addresses);
2529 if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2532 a = addresses + address_index;
2533 switch (k->protocol)
2535 #define _(N, j, n, s) \
2536 case SNAT_PROTOCOL_##N: \
2537 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
2538 return VNET_API_ERROR_INSTANCE_IN_USE; \
2539 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
2540 a->busy_##n##_ports_per_thread[thread_index]++; \
2541 a->busy_##n##_ports++; \
2543 foreach_snat_protocol
2546 nat_elog_info ("unknown protocol");
2551 return VNET_API_ERROR_NO_SUCH_ENTRY;
2555 snat_static_mapping_match (snat_main_t * sm,
2556 snat_session_key_t match,
2557 snat_session_key_t * mapping,
2560 twice_nat_type_t * twice_nat,
2561 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2562 u8 * is_identity_nat)
2564 clib_bihash_kv_8_8_t kv, value;
2565 snat_static_mapping_t *m;
2566 snat_session_key_t m_key;
2567 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2568 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2570 nat44_lb_addr_port_t *local;
2572 m_key.fib_index = match.fib_index;
2575 mapping_hash = &sm->static_mapping_by_external;
2576 m_key.fib_index = 0;
2579 m_key.addr = match.addr;
2580 m_key.port = clib_net_to_host_u16 (match.port);
2581 m_key.protocol = match.protocol;
2583 kv.key = m_key.as_u64;
2585 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2587 /* Try address only mapping */
2590 kv.key = m_key.as_u64;
2591 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2595 m = pool_elt_at_index (sm->static_mappings, value.value);
2599 if (is_lb_static_mapping (m))
2601 if (PREDICT_FALSE (lb != 0))
2602 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2603 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2609 local = pool_elt_at_index (m->locals, backend_index);
2610 mapping->addr = local->addr;
2611 mapping->port = clib_host_to_net_u16 (local->port);
2612 mapping->fib_index = local->fib_index;
2615 // pick locals matching this worker
2616 if (PREDICT_FALSE (sm->num_workers > 1))
2618 u32 thread_index = vlib_get_thread_index ();
2620 pool_foreach_index (i, m->locals,
2622 local = pool_elt_at_index (m->locals, i);
2625 .src_address = local->addr,
2628 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2635 ASSERT (vec_len (tmp) != 0);
2640 pool_foreach_index (i, m->locals,
2646 hi = vec_len (tmp) - 1;
2647 local = pool_elt_at_index (m->locals, tmp[hi]);
2648 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2651 mid = ((hi - lo) >> 1) + lo;
2652 local = pool_elt_at_index (m->locals, tmp[mid]);
2653 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2655 local = pool_elt_at_index (m->locals, tmp[lo]);
2656 if (!(local->prefix >= rand))
2658 mapping->addr = local->addr;
2659 mapping->port = clib_host_to_net_u16 (local->port);
2660 mapping->fib_index = local->fib_index;
2663 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2664 match.protocol, match.port,
2665 tmp[lo], m->affinity,
2666 m->affinity_per_service_list_head_index))
2667 nat_elog_info ("create affinity record failed");
2673 if (PREDICT_FALSE (lb != 0))
2675 mapping->fib_index = m->fib_index;
2676 mapping->addr = m->local_addr;
2677 /* Address only mapping doesn't change port */
2678 mapping->port = is_addr_only_static_mapping (m) ? match.port
2679 : clib_host_to_net_u16 (m->local_port);
2681 mapping->protocol = m->proto;
2685 mapping->addr = m->external_addr;
2686 /* Address only mapping doesn't change port */
2687 mapping->port = is_addr_only_static_mapping (m) ? match.port
2688 : clib_host_to_net_u16 (m->external_port);
2689 mapping->fib_index = sm->outside_fib_index;
2693 if (PREDICT_FALSE (is_addr_only != 0))
2694 *is_addr_only = is_addr_only_static_mapping (m);
2696 if (PREDICT_FALSE (twice_nat != 0))
2697 *twice_nat = m->twice_nat;
2699 if (PREDICT_FALSE (is_identity_nat != 0))
2700 *is_identity_nat = is_identity_static_mapping (m);
2705 static_always_inline u16
2706 snat_random_port (u16 min, u16 max)
2708 snat_main_t *sm = &snat_main;
2709 return min + random_u32 (&sm->random_seed) /
2710 (random_u32_max () / (max - min + 1) + 1);
2714 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2717 snat_session_key_t * k,
2718 u16 port_per_thread,
2719 u32 snat_thread_index)
2721 snat_main_t *sm = &snat_main;
2723 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2724 port_per_thread, snat_thread_index);
2728 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2731 snat_session_key_t * k,
2732 u16 port_per_thread, u32 snat_thread_index)
2735 snat_address_t *a, *ga = 0;
2738 for (i = 0; i < vec_len (addresses); i++)
2741 switch (k->protocol)
2743 #define _(N, j, n, s) \
2744 case SNAT_PROTOCOL_##N: \
2745 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2747 if (a->fib_index == fib_index) \
2751 portnum = (port_per_thread * \
2752 snat_thread_index) + \
2753 snat_random_port(1, port_per_thread) + 1024; \
2754 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2756 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2757 a->busy_##n##_ports_per_thread[thread_index]++; \
2758 a->busy_##n##_ports++; \
2759 k->addr = a->addr; \
2760 k->port = clib_host_to_net_u16(portnum); \
2764 else if (a->fib_index == ~0) \
2770 foreach_snat_protocol
2773 nat_elog_info ("unknown protocol");
2782 switch (k->protocol)
2784 #define _(N, j, n, s) \
2785 case SNAT_PROTOCOL_##N: \
2788 portnum = (port_per_thread * \
2789 snat_thread_index) + \
2790 snat_random_port(1, port_per_thread) + 1024; \
2791 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2793 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2794 a->busy_##n##_ports_per_thread[thread_index]++; \
2795 a->busy_##n##_ports++; \
2796 k->addr = a->addr; \
2797 k->port = clib_host_to_net_u16(portnum); \
2801 foreach_snat_protocol
2804 nat_elog_info ("unknown protocol");
2809 /* Totally out of translations to use... */
2810 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2815 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2818 snat_session_key_t * k,
2819 u16 port_per_thread, u32 snat_thread_index)
2821 snat_main_t *sm = &snat_main;
2822 snat_address_t *a = addresses;
2823 u16 m, ports, portnum, A, j;
2824 m = 16 - (sm->psid_offset + sm->psid_length);
2825 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2827 if (!vec_len (addresses))
2830 switch (k->protocol)
2832 #define _(N, i, n, s) \
2833 case SNAT_PROTOCOL_##N: \
2834 if (a->busy_##n##_ports < ports) \
2838 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2839 j = snat_random_port(0, pow2_mask(m)); \
2840 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2841 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2843 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2844 a->busy_##n##_ports++; \
2845 k->addr = a->addr; \
2846 k->port = clib_host_to_net_u16 (portnum); \
2851 foreach_snat_protocol
2854 nat_elog_info ("unknown protocol");
2859 /* Totally out of translations to use... */
2860 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2865 nat_alloc_addr_and_port_range (snat_address_t * addresses,
2868 snat_session_key_t * k,
2869 u16 port_per_thread, u32 snat_thread_index)
2871 snat_main_t *sm = &snat_main;
2872 snat_address_t *a = addresses;
2875 ports = sm->end_port - sm->start_port + 1;
2877 if (!vec_len (addresses))
2880 switch (k->protocol)
2882 #define _(N, i, n, s) \
2883 case SNAT_PROTOCOL_##N: \
2884 if (a->busy_##n##_ports < ports) \
2888 portnum = snat_random_port(sm->start_port, sm->end_port); \
2889 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2891 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2892 a->busy_##n##_ports++; \
2893 k->addr = a->addr; \
2894 k->port = clib_host_to_net_u16 (portnum); \
2899 foreach_snat_protocol
2902 nat_elog_info ("unknown protocol");
2907 /* Totally out of translations to use... */
2908 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2913 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2915 dpo_id_t dpo_v4 = DPO_INVALID;
2916 fib_prefix_t pfx = {
2917 .fp_proto = FIB_PROTOCOL_IP4,
2919 .fp_addr.ip4.as_u32 = addr.as_u32,
2924 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2925 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
2926 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2927 dpo_reset (&dpo_v4);
2931 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
2936 format_session_kvp (u8 * s, va_list * args)
2938 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2939 snat_session_key_t k;
2943 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2949 format_static_mapping_kvp (u8 * s, va_list * args)
2951 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2952 snat_session_key_t k;
2956 s = format (s, "%U static-mapping-index %llu",
2957 format_static_mapping_key, &k, v->value);
2963 format_user_kvp (u8 * s, va_list * args)
2965 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2970 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2971 k.fib_index, v->value);
2977 format_ed_session_kvp (u8 * s, va_list * args)
2979 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2982 k.as_u64[0] = v->key[0];
2983 k.as_u64[1] = v->key[1];
2986 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2987 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2988 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2989 format_ip_protocol, k.proto, k.fib_index, v->value);
2995 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
2998 snat_main_t *sm = &snat_main;
2999 u32 next_worker_index = 0;
3002 next_worker_index = sm->first_worker_index;
3003 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3004 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3006 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3007 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3009 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3011 return next_worker_index;
3015 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3018 snat_main_t *sm = &snat_main;
3021 snat_session_key_t m_key;
3022 clib_bihash_kv_8_8_t kv, value;
3023 snat_static_mapping_t *m;
3025 u32 next_worker_index = 0;
3027 /* first try static mappings without port */
3028 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3030 m_key.addr = ip0->dst_address;
3033 m_key.fib_index = rx_fib_index0;
3034 kv.key = m_key.as_u64;
3035 if (!clib_bihash_search_8_8
3036 (&sm->static_mapping_by_external, &kv, &value))
3038 m = pool_elt_at_index (sm->static_mappings, value.value);
3039 return m->workers[0];
3043 proto = ip_proto_to_snat_proto (ip0->protocol);
3044 udp = ip4_next_header (ip0);
3045 port = udp->dst_port;
3047 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
3049 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
3050 return vlib_get_thread_index ();
3052 nat_reass_ip4_t *reass;
3053 reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
3054 ip0->fragment_id, ip0->protocol);
3056 if (reass && (reass->thread_index != (u32) ~ 0))
3057 return reass->thread_index;
3059 if (ip4_is_first_fragment (ip0))
3062 nat_ip4_reass_create (ip0->src_address, ip0->dst_address,
3063 ip0->fragment_id, ip0->protocol);
3067 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3069 m_key.addr = ip0->dst_address;
3070 m_key.port = clib_net_to_host_u16 (port);
3071 m_key.protocol = proto;
3072 m_key.fib_index = rx_fib_index0;
3073 kv.key = m_key.as_u64;
3074 if (!clib_bihash_search_8_8
3075 (&sm->static_mapping_by_external, &kv, &value))
3077 m = pool_elt_at_index (sm->static_mappings, value.value);
3078 reass->thread_index = m->workers[0];
3079 return reass->thread_index;
3082 reass->thread_index = sm->first_worker_index;
3083 reass->thread_index +=
3084 sm->workers[(clib_net_to_host_u16 (port) - 1024) /
3085 sm->port_per_thread];
3086 return reass->thread_index;
3089 return vlib_get_thread_index ();
3093 /* unknown protocol */
3094 if (PREDICT_FALSE (proto == ~0))
3096 /* use current thread */
3097 return vlib_get_thread_index ();
3100 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3102 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3103 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3104 if (!icmp_is_error_message (icmp))
3105 port = echo->identifier;
3108 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3109 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3110 void *l4_header = ip4_next_header (inner_ip);
3113 case SNAT_PROTOCOL_ICMP:
3114 icmp = (icmp46_header_t *) l4_header;
3115 echo = (icmp_echo_header_t *) (icmp + 1);
3116 port = echo->identifier;
3118 case SNAT_PROTOCOL_UDP:
3119 case SNAT_PROTOCOL_TCP:
3120 port = ((tcp_udp_header_t *) l4_header)->src_port;
3123 return vlib_get_thread_index ();
3128 /* try static mappings with port */
3129 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3131 m_key.addr = ip0->dst_address;
3132 m_key.port = clib_net_to_host_u16 (port);
3133 m_key.protocol = proto;
3134 m_key.fib_index = rx_fib_index0;
3135 kv.key = m_key.as_u64;
3136 if (!clib_bihash_search_8_8
3137 (&sm->static_mapping_by_external, &kv, &value))
3139 m = pool_elt_at_index (sm->static_mappings, value.value);
3140 return m->workers[0];
3144 /* worker by outside port */
3145 next_worker_index = sm->first_worker_index;
3146 next_worker_index +=
3147 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3148 return next_worker_index;
3152 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3155 snat_main_t *sm = &snat_main;
3156 u32 next_worker_index = sm->first_worker_index;
3159 clib_bihash_kv_16_8_t kv16, value16;
3160 snat_main_per_thread_data_t *tsm;
3163 if (PREDICT_FALSE (is_output))
3165 u32 fib_index = sm->outside_fib_index;
3166 nat_outside_fib_t *outside_fib;
3167 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3168 fib_prefix_t pfx = {
3169 .fp_proto = FIB_PROTOCOL_IP4,
3172 .ip4.as_u32 = ip->dst_address.as_u32,
3177 udp = ip4_next_header (ip);
3179 switch (vec_len (sm->outside_fibs))
3182 fib_index = sm->outside_fib_index;
3185 fib_index = sm->outside_fibs[0].fib_index;
3189 vec_foreach (outside_fib, sm->outside_fibs)
3191 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3192 if (FIB_NODE_INDEX_INVALID != fei)
3194 if (fib_entry_get_resolving_interface (fei) != ~0)
3196 fib_index = outside_fib->fib_index;
3205 make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
3206 ip->protocol, fib_index, udp->src_port, udp->dst_port);
3209 vec_foreach (tsm, sm->per_thread_data)
3211 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3214 next_worker_index += tsm->thread_index;
3216 nat_elog_debug_handoff (
3217 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3218 next_worker_index, fib_index,
3219 clib_net_to_host_u32 (ip->src_address.as_u32),
3220 clib_net_to_host_u32 (ip->dst_address.as_u32));
3222 return next_worker_index;
3228 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3229 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3231 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3232 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3234 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3236 if (PREDICT_TRUE (!is_output))
3238 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3239 next_worker_index, rx_fib_index,
3240 clib_net_to_host_u32 (ip->src_address.as_u32),
3241 clib_net_to_host_u32 (ip->dst_address.as_u32));
3245 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3246 next_worker_index, rx_fib_index,
3247 clib_net_to_host_u32 (ip->src_address.as_u32),
3248 clib_net_to_host_u32 (ip->dst_address.as_u32));
3251 return next_worker_index;
3255 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index,
3258 snat_main_t *sm = &snat_main;
3259 clib_bihash_kv_8_8_t kv, value;
3260 clib_bihash_kv_16_8_t kv16, value16;
3261 snat_main_per_thread_data_t *tsm;
3263 u32 proto, next_worker_index = 0;
3266 snat_static_mapping_t *m;
3269 proto = ip_proto_to_snat_proto (ip->protocol);
3271 if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3273 udp = ip4_next_header (ip);
3275 make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
3276 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
3279 vec_foreach (tsm, sm->per_thread_data)
3281 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3284 next_worker_index = sm->first_worker_index + tsm->thread_index;
3285 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3286 next_worker_index, rx_fib_index,
3287 clib_net_to_host_u32 (ip->src_address.as_u32),
3288 clib_net_to_host_u32 (ip->dst_address.as_u32));
3289 return next_worker_index;
3294 else if (proto == SNAT_PROTOCOL_ICMP)
3296 nat_ed_ses_key_t key;
3298 if (!get_icmp_o2i_ed_key (ip, &key))
3301 key.fib_index = rx_fib_index;
3302 kv16.key[0] = key.as_u64[0];
3303 kv16.key[1] = key.as_u64[1];
3306 vec_foreach (tsm, sm->per_thread_data)
3308 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3311 next_worker_index = sm->first_worker_index +
3313 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3314 next_worker_index, rx_fib_index,
3315 clib_net_to_host_u32 (ip->src_address.as_u32),
3316 clib_net_to_host_u32 (ip->dst_address.as_u32));
3317 return next_worker_index;
3324 /* first try static mappings without port */
3325 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3327 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3328 if (!clib_bihash_search_8_8
3329 (&sm->static_mapping_by_external, &kv, &value))
3331 m = pool_elt_at_index (sm->static_mappings, value.value);
3332 next_worker_index = m->workers[0];
3337 /* unknown protocol */
3338 if (PREDICT_FALSE (proto == ~0))
3340 /* use current thread */
3341 next_worker_index = vlib_get_thread_index ();
3345 udp = ip4_next_header (ip);
3346 port = udp->dst_port;
3348 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3350 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3351 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3352 if (!icmp_is_error_message (icmp))
3353 port = echo->identifier;
3356 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3357 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3358 void *l4_header = ip4_next_header (inner_ip);
3361 case SNAT_PROTOCOL_ICMP:
3362 icmp = (icmp46_header_t *) l4_header;
3363 echo = (icmp_echo_header_t *) (icmp + 1);
3364 port = echo->identifier;
3366 case SNAT_PROTOCOL_UDP:
3367 case SNAT_PROTOCOL_TCP:
3368 port = ((tcp_udp_header_t *) l4_header)->src_port;
3371 next_worker_index = vlib_get_thread_index ();
3377 /* try static mappings with port */
3378 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3380 make_sm_kv (&kv, &ip->dst_address, proto, 0,
3381 clib_net_to_host_u16 (port));
3382 if (!clib_bihash_search_8_8
3383 (&sm->static_mapping_by_external, &kv, &value))
3385 m = pool_elt_at_index (sm->static_mappings, value.value);
3386 if (!is_lb_static_mapping (m))
3388 next_worker_index = m->workers[0];
3392 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3393 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3395 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3397 m->workers[hash & (_vec_len (m->workers) - 1)];
3399 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3404 /* worker by outside port */
3405 next_worker_index = sm->first_worker_index;
3406 next_worker_index +=
3407 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3410 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3411 clib_net_to_host_u32 (ip->src_address.as_u32),
3412 clib_net_to_host_u32 (ip->dst_address.as_u32));
3413 return next_worker_index;
3417 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3418 ip4_address_t * out_addr, u16 out_port,
3419 ip4_address_t * eh_addr, u16 eh_port,
3420 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3421 u32 fib_index, u16 flags, u32 thread_index)
3423 snat_main_t *sm = &snat_main;
3424 snat_session_key_t key;
3427 clib_bihash_kv_8_8_t kv;
3428 f64 now = vlib_time_now (sm->vlib_main);
3429 nat_outside_fib_t *outside_fib;
3430 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3431 snat_main_per_thread_data_t *tsm;
3432 fib_prefix_t pfx = {
3433 .fp_proto = FIB_PROTOCOL_IP4,
3436 .ip4.as_u32 = eh_addr->as_u32,
3440 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3442 key.addr.as_u32 = out_addr->as_u32;
3443 key.port = out_port;
3444 key.protocol = proto;
3446 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3448 if (nat_set_outside_address_and_port
3449 (sm->addresses, thread_index, &key))
3453 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3457 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3461 s->last_heard = now;
3463 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3464 s->ext_host_port = eh_port;
3465 user_session_increment (sm, u, snat_is_session_static (s));
3466 switch (vec_len (sm->outside_fibs))
3469 key.fib_index = sm->outside_fib_index;
3472 key.fib_index = sm->outside_fibs[0].fib_index;
3476 vec_foreach (outside_fib, sm->outside_fibs)
3478 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3479 if (FIB_NODE_INDEX_INVALID != fei)
3481 if (fib_entry_get_resolving_interface (fei) != ~0)
3483 key.fib_index = outside_fib->fib_index;
3492 kv.key = key.as_u64;
3493 kv.value = s - tsm->sessions;
3494 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3495 nat_elog_warn ("out2in key add failed");
3497 key.addr.as_u32 = in_addr->as_u32;
3499 key.fib_index = fib_index;
3501 kv.key = key.as_u64;
3502 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3503 nat_elog_warn ("in2out key add failed");
3507 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3508 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3511 snat_main_t *sm = &snat_main;
3512 snat_session_key_t key;
3513 clib_bihash_kv_8_8_t kv, value;
3516 snat_main_per_thread_data_t *tsm;
3518 if (sm->num_workers > 1)
3520 sm->first_worker_index +
3521 (sm->workers[(clib_net_to_host_u16 (out_port) -
3522 1024) / sm->port_per_thread]);
3524 thread_index = sm->num_workers;
3525 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3527 key.addr.as_u32 = out_addr->as_u32;
3528 key.port = out_port;
3529 key.protocol = proto;
3530 key.fib_index = fib_index;
3531 kv.key = key.as_u64;
3532 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3535 s = pool_elt_at_index (tsm->sessions, value.value);
3536 nat_free_session_data (sm, s, thread_index, 1);
3537 nat44_delete_session (sm, s, thread_index);
3541 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3542 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3543 u32 total_pkts, u64 total_bytes, u32 thread_index)
3545 snat_main_t *sm = &snat_main;
3546 snat_session_key_t key;
3547 clib_bihash_kv_8_8_t kv, value;
3549 snat_main_per_thread_data_t *tsm;
3551 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3553 key.addr.as_u32 = out_addr->as_u32;
3554 key.port = out_port;
3555 key.protocol = proto;
3556 key.fib_index = fib_index;
3557 kv.key = key.as_u64;
3558 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3561 s = pool_elt_at_index (tsm->sessions, value.value);
3562 s->total_pkts = total_pkts;
3563 s->total_bytes = total_bytes;
3567 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3568 ip4_address_t * out_addr, u16 out_port,
3569 ip4_address_t * eh_addr, u16 eh_port,
3570 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3571 u32 fib_index, u16 flags, u32 thread_index)
3573 snat_main_t *sm = &snat_main;
3574 snat_session_key_t key;
3577 clib_bihash_kv_16_8_t kv;
3578 f64 now = vlib_time_now (sm->vlib_main);
3579 nat_outside_fib_t *outside_fib;
3580 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3581 snat_main_per_thread_data_t *tsm;
3582 fib_prefix_t pfx = {
3583 .fp_proto = FIB_PROTOCOL_IP4,
3586 .ip4.as_u32 = eh_addr->as_u32,
3590 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3592 key.addr.as_u32 = out_addr->as_u32;
3593 key.port = out_port;
3594 key.protocol = proto;
3596 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3598 if (nat_set_outside_address_and_port
3599 (sm->addresses, thread_index, &key))
3603 key.addr.as_u32 = ehn_addr->as_u32;
3604 key.port = ehn_port;
3605 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3607 if (nat_set_outside_address_and_port
3608 (sm->twice_nat_addresses, thread_index, &key))
3612 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3616 s = nat_ed_session_alloc (sm, u, thread_index, now);
3620 s->last_heard = now;
3622 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3623 s->ext_host_nat_port = s->ext_host_port = eh_port;
3624 if (is_twice_nat_session (s))
3626 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3627 s->ext_host_nat_port = ehn_port;
3629 user_session_increment (sm, u, snat_is_session_static (s));
3630 switch (vec_len (sm->outside_fibs))
3633 key.fib_index = sm->outside_fib_index;
3636 key.fib_index = sm->outside_fibs[0].fib_index;
3640 vec_foreach (outside_fib, sm->outside_fibs)
3642 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3643 if (FIB_NODE_INDEX_INVALID != fei)
3645 if (fib_entry_get_resolving_interface (fei) != ~0)
3647 key.fib_index = outside_fib->fib_index;
3655 key.addr.as_u32 = out_addr->as_u32;
3656 key.port = out_port;
3658 kv.value = s - tsm->sessions;
3660 key.addr.as_u32 = in_addr->as_u32;
3662 key.fib_index = fib_index;
3665 make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
3666 snat_proto_to_ip_proto (proto), fib_index, in_port,
3667 s->ext_host_nat_port);
3668 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3669 nat_elog_warn ("in2out key add failed");
3671 make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3672 s->out2in.fib_index, out_port, eh_port);
3673 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3674 nat_elog_warn ("out2in key add failed");
3678 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3679 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3680 u32 fib_index, u32 ti)
3682 snat_main_t *sm = &snat_main;
3683 nat_ed_ses_key_t key;
3684 clib_bihash_kv_16_8_t kv, value;
3687 snat_main_per_thread_data_t *tsm;
3689 if (sm->num_workers > 1)
3691 sm->first_worker_index +
3692 (sm->workers[(clib_net_to_host_u16 (out_port) -
3693 1024) / sm->port_per_thread]);
3695 thread_index = sm->num_workers;
3696 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3698 key.l_addr.as_u32 = out_addr->as_u32;
3699 key.l_port = out_port;
3700 key.r_addr.as_u32 = eh_addr->as_u32;
3701 key.r_port = eh_port;
3703 key.fib_index = fib_index;
3704 kv.key[0] = key.as_u64[0];
3705 kv.key[1] = key.as_u64[1];
3706 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3709 s = pool_elt_at_index (tsm->sessions, value.value);
3710 nat_free_session_data (sm, s, thread_index, 1);
3711 nat44_delete_session (sm, s, thread_index);
3715 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3716 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3717 u32 fib_index, u32 total_pkts, u64 total_bytes,
3720 snat_main_t *sm = &snat_main;
3721 nat_ed_ses_key_t key;
3722 clib_bihash_kv_16_8_t kv, value;
3724 snat_main_per_thread_data_t *tsm;
3726 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3728 key.l_addr.as_u32 = out_addr->as_u32;
3729 key.l_port = out_port;
3730 key.r_addr.as_u32 = eh_addr->as_u32;
3731 key.r_port = eh_port;
3733 key.fib_index = fib_index;
3734 kv.key[0] = key.as_u64[0];
3735 kv.key[1] = key.as_u64[1];
3736 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3739 s = pool_elt_at_index (tsm->sessions, value.value);
3740 s->total_pkts = total_pkts;
3741 s->total_bytes = total_bytes;
3744 static clib_error_t *
3745 snat_config (vlib_main_t * vm, unformat_input_t * input)
3747 snat_main_t *sm = &snat_main;
3748 nat66_main_t *nm = &nat66_main;
3749 dslite_main_t *dm = &dslite_main;
3750 snat_main_per_thread_data_t *tsm;
3752 u32 static_mapping_buckets = 1024;
3753 u32 static_mapping_memory_size = 64 << 20;
3755 u32 nat64_bib_buckets = 1024;
3756 u32 nat64_bib_memory_size = 128 << 20;
3758 u32 nat64_st_buckets = 2048;
3759 u32 nat64_st_memory_size = 256 << 20;
3761 u32 user_buckets = 128;
3762 u32 user_memory_size = 64 << 20;
3763 u32 translation_buckets = 1024;
3764 u32 translation_memory_size = 128 << 20;
3766 u32 max_translations_per_user = ~0;
3768 u32 outside_vrf_id = 0;
3769 u32 outside_ip6_vrf_id = 0;
3770 u32 inside_vrf_id = 0;
3771 u8 static_mapping_only = 0;
3772 u8 static_mapping_connection_tracking = 0;
3774 u32 udp_timeout = SNAT_UDP_TIMEOUT;
3775 u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
3777 u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3778 u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3780 sm->deterministic = 0;
3782 sm->endpoint_dependent = 0;
3784 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3787 (input, "translation hash buckets %d", &translation_buckets))
3789 else if (unformat (input, "udp timeout %d", &udp_timeout))
3791 else if (unformat (input, "icmp timeout %d", &icmp_timeout))
3793 else if (unformat (input, "tcp transitory timeout %d",
3794 &tcp_transitory_timeout));
3795 else if (unformat (input, "tcp established timeout %d",
3796 &tcp_established_timeout));
3797 else if (unformat (input, "translation hash memory %d",
3798 &translation_memory_size));
3799 else if (unformat (input, "user hash buckets %d", &user_buckets))
3801 else if (unformat (input, "user hash memory %d", &user_memory_size))
3803 else if (unformat (input, "max translations per user %d",
3804 &max_translations_per_user))
3806 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3808 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3810 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3812 else if (unformat (input, "static mapping only"))
3814 static_mapping_only = 1;
3815 if (unformat (input, "connection tracking"))
3816 static_mapping_connection_tracking = 1;
3818 else if (unformat (input, "deterministic"))
3819 sm->deterministic = 1;
3820 else if (unformat (input, "nat64 bib hash buckets %d",
3821 &nat64_bib_buckets))
3823 else if (unformat (input, "nat64 bib hash memory %d",
3824 &nat64_bib_memory_size))
3827 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3829 else if (unformat (input, "nat64 st hash memory %d",
3830 &nat64_st_memory_size))
3832 else if (unformat (input, "out2in dpo"))
3834 else if (unformat (input, "dslite ce"))
3835 dslite_set_ce (dm, 1);
3836 else if (unformat (input, "endpoint-dependent"))
3837 sm->endpoint_dependent = 1;
3839 return clib_error_return (0, "unknown input '%U'",
3840 format_unformat_error, input);
3843 if (sm->deterministic && sm->endpoint_dependent)
3844 return clib_error_return (0,
3845 "deterministic and endpoint-dependent modes are mutually exclusive");
3847 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
3848 return clib_error_return (0,
3849 "static mapping only mode available only for simple nat");
3851 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
3852 return clib_error_return (0,
3853 "out2in dpo mode available only for simple nat");
3855 /* optionally configurable timeouts for testing purposes */
3856 sm->udp_timeout = udp_timeout;
3857 sm->icmp_timeout = icmp_timeout;
3858 sm->tcp_transitory_timeout = tcp_transitory_timeout;
3859 sm->tcp_established_timeout = tcp_established_timeout;
3861 sm->user_buckets = user_buckets;
3862 sm->user_memory_size = user_memory_size;
3864 sm->translation_buckets = translation_buckets;
3865 sm->translation_memory_size = translation_memory_size;
3867 /* do not exceed load factor 10 */
3868 sm->max_translations = 10 * translation_buckets;
3869 sm->max_translations_per_user = max_translations_per_user == ~0 ?
3870 sm->max_translations : max_translations_per_user;
3872 sm->outside_vrf_id = outside_vrf_id;
3873 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
3876 nm->outside_vrf_id = outside_ip6_vrf_id;
3877 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3880 sm->inside_vrf_id = inside_vrf_id;
3881 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
3884 sm->static_mapping_only = static_mapping_only;
3885 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
3887 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
3888 nat64_st_memory_size);
3890 if (sm->deterministic)
3892 sm->in2out_node_index = snat_det_in2out_node.index;
3893 sm->in2out_output_node_index = ~0;
3894 sm->out2in_node_index = snat_det_out2in_node.index;
3895 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
3896 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
3900 if (sm->endpoint_dependent)
3902 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
3903 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
3905 sm->handoff_out2in_index = nat_pre_out2in_node.index;
3906 sm->handoff_in2out_index = nat_pre_in2out_node.index;
3907 sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
3909 sm->in2out_node_index = nat44_ed_in2out_node.index;
3910 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
3911 sm->out2in_node_index = nat44_ed_out2in_node.index;
3913 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
3914 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
3915 nat_affinity_init (vm);
3916 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
3921 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
3922 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
3924 sm->handoff_out2in_index = snat_in2out_node.index;
3925 sm->handoff_in2out_index = snat_out2in_node.index;
3926 sm->handoff_in2out_output_index = snat_in2out_output_node.index;
3928 sm->in2out_node_index = snat_in2out_node.index;
3929 sm->in2out_output_node_index = snat_in2out_output_node.index;
3930 sm->out2in_node_index = snat_out2in_node.index;
3931 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
3932 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
3933 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
3935 if (!static_mapping_only ||
3936 (static_mapping_only && static_mapping_connection_tracking))
3939 vec_foreach (tsm, sm->per_thread_data)
3941 if (sm->endpoint_dependent)
3943 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3944 translation_buckets,
3945 translation_memory_size);
3946 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3947 format_ed_session_kvp);
3949 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3950 translation_buckets,
3951 translation_memory_size);
3952 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3953 format_ed_session_kvp);
3957 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3958 translation_buckets,
3959 translation_memory_size);
3960 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
3961 format_session_kvp);
3963 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3964 translation_buckets,
3965 translation_memory_size);
3966 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
3967 format_session_kvp);
3970 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3972 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
3980 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
3981 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
3983 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3984 "static_mapping_by_local", static_mapping_buckets,
3985 static_mapping_memory_size);
3986 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
3987 format_static_mapping_kvp);
3989 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3990 "static_mapping_by_external",
3991 static_mapping_buckets,
3992 static_mapping_memory_size);
3993 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
3994 format_static_mapping_kvp);
4000 VLIB_CONFIG_FUNCTION (snat_config, "nat");
4003 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
4006 ip4_address_t * address,
4008 u32 if_address_index, u32 is_delete)
4010 snat_main_t *sm = &snat_main;
4011 snat_static_map_resolve_t *rp;
4012 snat_static_mapping_t *m;
4013 snat_session_key_t m_key;
4014 clib_bihash_kv_8_8_t kv, value;
4016 ip4_address_t l_addr;
4018 for (i = 0; i < vec_len (sm->to_resolve); i++)
4020 rp = sm->to_resolve + i;
4021 if (rp->addr_only == 0)
4023 if (rp->sw_if_index == sw_if_index)
4030 m_key.addr.as_u32 = address->as_u32;
4031 m_key.port = rp->addr_only ? 0 : rp->e_port;
4032 m_key.protocol = rp->addr_only ? 0 : rp->proto;
4033 m_key.fib_index = sm->outside_fib_index;
4034 kv.key = m_key.as_u64;
4035 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4038 m = pool_elt_at_index (sm->static_mappings, value.value);
4042 /* Don't trip over lease renewal, static config */
4052 /* Indetity mapping? */
4053 if (rp->l_addr.as_u32 == 0)
4054 l_addr.as_u32 = address[0].as_u32;
4056 l_addr.as_u32 = rp->l_addr.as_u32;
4057 /* Add the static mapping */
4058 rv = snat_add_static_mapping (l_addr,
4063 rp->addr_only, ~0 /* sw_if_index */ ,
4064 rp->proto, !is_delete, rp->twice_nat,
4065 rp->out2in_only, rp->tag, rp->identity_nat);
4067 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4071 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4074 ip4_address_t * address,
4076 u32 if_address_index, u32 is_delete)
4078 snat_main_t *sm = &snat_main;
4079 snat_static_map_resolve_t *rp;
4080 ip4_address_t l_addr;
4084 snat_address_t *addresses = sm->addresses;
4086 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4088 if (sw_if_index == sm->auto_add_sw_if_indices[i])
4092 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4095 addresses = sm->twice_nat_addresses;
4096 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4105 /* Don't trip over lease renewal, static config */
4106 for (j = 0; j < vec_len (addresses); j++)
4107 if (addresses[j].addr.as_u32 == address->as_u32)
4110 (void) snat_add_address (sm, address, ~0, twice_nat);
4111 /* Scan static map resolution vector */
4112 for (j = 0; j < vec_len (sm->to_resolve); j++)
4114 rp = sm->to_resolve + j;
4117 /* On this interface? */
4118 if (rp->sw_if_index == sw_if_index)
4120 /* Indetity mapping? */
4121 if (rp->l_addr.as_u32 == 0)
4122 l_addr.as_u32 = address[0].as_u32;
4124 l_addr.as_u32 = rp->l_addr.as_u32;
4125 /* Add the static mapping */
4126 rv = snat_add_static_mapping (l_addr,
4132 ~0 /* sw_if_index */ ,
4134 rp->is_add, rp->twice_nat,
4135 rp->out2in_only, rp->tag,
4138 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4146 (void) snat_del_address (sm, address[0], 1, twice_nat);
4153 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4156 ip4_main_t *ip4_main = sm->ip4_main;
4157 ip4_address_t *first_int_addr;
4158 snat_static_map_resolve_t *rp;
4159 u32 *indices_to_delete = 0;
4161 u32 *auto_add_sw_if_indices =
4163 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4165 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4168 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4170 if (auto_add_sw_if_indices[i] == sw_if_index)
4174 /* if have address remove it */
4176 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4179 for (j = 0; j < vec_len (sm->to_resolve); j++)
4181 rp = sm->to_resolve + j;
4182 if (rp->sw_if_index == sw_if_index)
4183 vec_add1 (indices_to_delete, j);
4185 if (vec_len (indices_to_delete))
4187 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4188 vec_del1 (sm->to_resolve, j);
4189 vec_free (indices_to_delete);
4193 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4195 vec_del1 (sm->auto_add_sw_if_indices, i);
4198 return VNET_API_ERROR_VALUE_EXIST;
4205 return VNET_API_ERROR_NO_SUCH_ENTRY;
4207 /* add to the auto-address list */
4209 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4211 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4213 /* If the address is already bound - or static - add it now */
4215 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4221 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4222 snat_protocol_t proto, u32 vrf_id, int is_in)
4224 snat_main_per_thread_data_t *tsm;
4225 clib_bihash_kv_8_8_t kv, value;
4227 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4228 snat_session_key_t key;
4230 clib_bihash_8_8_t *t;
4232 if (sm->endpoint_dependent)
4233 return VNET_API_ERROR_UNSUPPORTED;
4235 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4236 if (sm->num_workers > 1)
4238 vec_elt_at_index (sm->per_thread_data,
4239 sm->worker_in2out_cb (&ip, fib_index, 0));
4241 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4243 key.addr.as_u32 = addr->as_u32;
4244 key.port = clib_host_to_net_u16 (port);
4245 key.protocol = proto;
4246 key.fib_index = fib_index;
4247 kv.key = key.as_u64;
4248 t = is_in ? &tsm->in2out : &tsm->out2in;
4249 if (!clib_bihash_search_8_8 (t, &kv, &value))
4251 if (pool_is_free_index (tsm->sessions, value.value))
4252 return VNET_API_ERROR_UNSPECIFIED;
4254 s = pool_elt_at_index (tsm->sessions, value.value);
4255 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4256 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4260 return VNET_API_ERROR_NO_SUCH_ENTRY;
4264 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4265 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4266 u32 vrf_id, int is_in)
4269 clib_bihash_16_8_t *t;
4270 nat_ed_ses_key_t key;
4271 clib_bihash_kv_16_8_t kv, value;
4272 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4274 snat_main_per_thread_data_t *tsm;
4276 if (!sm->endpoint_dependent)
4277 return VNET_API_ERROR_FEATURE_DISABLED;
4279 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4280 if (sm->num_workers > 1)
4282 vec_elt_at_index (sm->per_thread_data,
4283 sm->worker_in2out_cb (&ip, fib_index, 0));
4285 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4287 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4288 key.l_addr.as_u32 = addr->as_u32;
4289 key.r_addr.as_u32 = eh_addr->as_u32;
4290 key.l_port = clib_host_to_net_u16 (port);
4291 key.r_port = clib_host_to_net_u16 (eh_port);
4293 key.fib_index = fib_index;
4294 kv.key[0] = key.as_u64[0];
4295 kv.key[1] = key.as_u64[1];
4296 if (clib_bihash_search_16_8 (t, &kv, &value))
4297 return VNET_API_ERROR_NO_SUCH_ENTRY;
4299 if (pool_is_free_index (tsm->sessions, value.value))
4300 return VNET_API_ERROR_UNSPECIFIED;
4301 s = pool_elt_at_index (tsm->sessions, value.value);
4302 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4303 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4308 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4310 snat_main_t *sm = &snat_main;
4312 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4313 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4315 sm->psid_offset = psid_offset;
4316 sm->psid_length = psid_length;
4320 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4322 snat_main_t *sm = &snat_main;
4324 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4325 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4326 sm->start_port = start_port;
4327 sm->end_port = end_port;
4331 nat_set_alloc_addr_and_port_default (void)
4333 snat_main_t *sm = &snat_main;
4335 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4336 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4339 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4340 vlib_node_runtime_t * node,
4341 vlib_frame_t * frame)
4347 VLIB_REGISTER_NODE (nat_default_node) = {
4348 .name = "nat-default",
4349 .vector_size = sizeof (u32),
4351 .type = VLIB_NODE_TYPE_INTERNAL,
4353 .n_next_nodes = NAT_N_NEXT,
4355 [NAT_NEXT_DROP] = "error-drop",
4356 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4357 [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4358 [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4359 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4360 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4361 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4362 [NAT_NEXT_IN2OUT_ED_REASS] = "nat44-ed-in2out-reass",
4363 [NAT_NEXT_IN2OUT_ED_OUTPUT_REASS] = "nat44-ed-in2out-reass-output",
4364 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4365 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4366 [NAT_NEXT_OUT2IN_ED_REASS] = "nat44-ed-out2in-reass",
4372 * fd.io coding-style-patch-verification: ON
4375 * eval: (c-set-style "gnu")