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);
465 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
466 if (now >= sess_timeout_time)
468 clib_dlist_addtail (tsm->list_pool,
469 u->sessions_per_user_list_head_index, oldest_index);
470 nat_free_session_data (sm, s, thread_index, 0);
471 if (snat_is_session_static (s))
472 u->nstaticsessions--;
479 s->ext_host_addr.as_u32 = 0;
480 s->ext_host_port = 0;
481 s->ext_host_nat_addr.as_u32 = 0;
482 s->ext_host_nat_port = 0;
486 clib_dlist_addhead (tsm->list_pool,
487 u->sessions_per_user_list_head_index, oldest_index);
488 if ((u->nsessions + u->nstaticsessions) >=
489 sm->max_translations_per_user)
491 nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
492 clib_net_to_host_u32 (u->addr.as_u32));
493 snat_ipfix_logging_max_entries_per_user
494 (thread_index, sm->max_translations_per_user, u->addr.as_u32);
500 pool_get (tsm->sessions, s);
501 clib_memset (s, 0, sizeof (*s));
503 /* Create list elts */
504 pool_get (tsm->list_pool, per_user_translation_list_elt);
505 clib_dlist_init (tsm->list_pool,
506 per_user_translation_list_elt - tsm->list_pool);
508 per_user_translation_list_elt->value = s - tsm->sessions;
509 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
510 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
512 clib_dlist_addtail (tsm->list_pool,
513 s->per_user_list_head_index,
514 per_user_translation_list_elt - tsm->list_pool);
517 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
518 pool_elts (tsm->sessions));
521 s->ha_last_refreshed = now;
527 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
530 fib_prefix_t prefix = {
532 .fp_proto = FIB_PROTOCOL_IP4,
534 .ip4.as_u32 = addr->as_u32,
537 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
540 fib_table_entry_update_one_path (fib_index,
543 (FIB_ENTRY_FLAG_CONNECTED |
544 FIB_ENTRY_FLAG_LOCAL |
545 FIB_ENTRY_FLAG_EXCLUSIVE),
549 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
551 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
555 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
560 vlib_thread_main_t *tm = vlib_get_thread_main ();
562 if (twice_nat && !sm->endpoint_dependent)
563 return VNET_API_ERROR_FEATURE_DISABLED;
565 /* Check if address already exists */
567 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
569 if (ap->addr.as_u32 == addr->as_u32)
570 return VNET_API_ERROR_VALUE_EXIST;
575 vec_add2 (sm->twice_nat_addresses, ap, 1);
577 vec_add2 (sm->addresses, ap, 1);
582 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
586 #define _(N, i, n, s) \
587 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
588 ap->busy_##n##_ports = 0; \
589 ap->busy_##n##_ports_per_thread = 0;\
590 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
591 foreach_snat_protocol
596 /* Add external address to FIB */
598 pool_foreach (i, sm->interfaces,
600 if (nat_interface_is_inside(i) || sm->out2in_dpo)
603 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
606 pool_foreach (i, sm->output_feature_interfaces,
608 if (nat_interface_is_inside(i) || sm->out2in_dpo)
611 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
620 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
622 snat_static_mapping_t *m;
624 pool_foreach (m, sm->static_mappings,
626 if (is_addr_only_static_mapping (m) ||
627 is_out2in_only_static_mapping (m) ||
628 is_identity_static_mapping (m))
630 if (m->external_addr.as_u32 == addr.as_u32)
639 increment_v4_address (ip4_address_t * a)
643 v = clib_net_to_host_u32 (a->as_u32) + 1;
644 a->as_u32 = clib_host_to_net_u32 (v);
648 snat_add_static_mapping_when_resolved (snat_main_t * sm,
649 ip4_address_t l_addr,
654 snat_protocol_t proto,
655 int addr_only, int is_add, u8 * tag,
656 int twice_nat, int out2in_only,
659 snat_static_map_resolve_t *rp;
661 vec_add2 (sm->to_resolve, rp, 1);
662 rp->l_addr.as_u32 = l_addr.as_u32;
664 rp->sw_if_index = sw_if_index;
668 rp->addr_only = addr_only;
670 rp->twice_nat = twice_nat;
671 rp->out2in_only = out2in_only;
672 rp->identity_nat = identity_nat;
673 rp->tag = vec_dup (tag);
677 get_thread_idx_by_port (u16 e_port)
679 snat_main_t *sm = &snat_main;
680 u32 thread_idx = sm->num_workers;
681 if (sm->num_workers > 1)
684 sm->first_worker_index +
685 sm->workers[(e_port - 1024) / sm->port_per_thread];
691 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
692 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
693 u32 sw_if_index, snat_protocol_t proto, int is_add,
694 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
697 snat_main_t *sm = &snat_main;
698 snat_static_mapping_t *m;
699 snat_session_key_t m_key;
700 clib_bihash_kv_8_8_t kv, value;
701 snat_address_t *a = 0;
703 snat_interface_t *interface;
705 snat_main_per_thread_data_t *tsm;
706 snat_user_key_t u_key;
708 dlist_elt_t *head, *elt;
709 u32 elt_index, head_index;
713 snat_static_map_resolve_t *rp, *rp_match = 0;
714 nat44_lb_addr_port_t *local;
717 if (!sm->endpoint_dependent)
719 if (twice_nat || out2in_only)
720 return VNET_API_ERROR_FEATURE_DISABLED;
723 /* If the external address is a specific interface address */
724 if (sw_if_index != ~0)
726 ip4_address_t *first_int_addr;
728 for (i = 0; i < vec_len (sm->to_resolve); i++)
730 rp = sm->to_resolve + i;
731 if (rp->sw_if_index != sw_if_index ||
732 rp->l_addr.as_u32 != l_addr.as_u32 ||
733 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
738 if ((rp->l_port != l_port && rp->e_port != e_port)
739 || rp->proto != proto)
747 /* Might be already set... */
748 first_int_addr = ip4_interface_first_address
749 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
754 return VNET_API_ERROR_VALUE_EXIST;
756 snat_add_static_mapping_when_resolved
757 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
758 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
760 /* DHCP resolution required? */
761 if (first_int_addr == 0)
767 e_addr.as_u32 = first_int_addr->as_u32;
768 /* Identity mapping? */
769 if (l_addr.as_u32 == 0)
770 l_addr.as_u32 = e_addr.as_u32;
776 return VNET_API_ERROR_NO_SUCH_ENTRY;
778 vec_del1 (sm->to_resolve, i);
782 e_addr.as_u32 = first_int_addr->as_u32;
783 /* Identity mapping? */
784 if (l_addr.as_u32 == 0)
785 l_addr.as_u32 = e_addr.as_u32;
793 m_key.port = addr_only ? 0 : e_port;
794 m_key.protocol = addr_only ? 0 : proto;
796 kv.key = m_key.as_u64;
797 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
800 m = pool_elt_at_index (sm->static_mappings, value.value);
806 if (is_identity_static_mapping (m))
809 pool_foreach (local, m->locals,
811 if (local->vrf_id == vrf_id)
812 return VNET_API_ERROR_VALUE_EXIST;
815 pool_get (m->locals, local);
816 local->vrf_id = vrf_id;
818 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
820 m_key.addr = m->local_addr;
821 m_key.port = m->local_port;
822 m_key.protocol = m->proto;
823 m_key.fib_index = local->fib_index;
824 kv.key = m_key.as_u64;
825 kv.value = m - sm->static_mappings;
826 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
830 return VNET_API_ERROR_VALUE_EXIST;
833 if (twice_nat && addr_only)
834 return VNET_API_ERROR_UNSUPPORTED;
836 /* Convert VRF id to FIB index */
839 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
841 /* If not specified use inside VRF id from SNAT plugin startup config */
844 fib_index = sm->inside_fib_index;
845 vrf_id = sm->inside_vrf_id;
846 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
849 if (!(out2in_only || identity_nat))
852 m_key.port = addr_only ? 0 : l_port;
853 m_key.protocol = addr_only ? 0 : proto;
854 m_key.fib_index = fib_index;
855 kv.key = m_key.as_u64;
856 if (!clib_bihash_search_8_8
857 (&sm->static_mapping_by_local, &kv, &value))
858 return VNET_API_ERROR_VALUE_EXIST;
861 /* Find external address in allocated addresses and reserve port for
862 address and port pair mapping when dynamic translations enabled */
863 if (!(addr_only || sm->static_mapping_only || out2in_only))
865 for (i = 0; i < vec_len (sm->addresses); i++)
867 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
869 a = sm->addresses + i;
870 /* External port must be unused */
873 #define _(N, j, n, s) \
874 case SNAT_PROTOCOL_##N: \
875 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
876 return VNET_API_ERROR_INVALID_VALUE; \
877 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
880 a->busy_##n##_ports++; \
881 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
884 foreach_snat_protocol
887 nat_elog_info ("unknown protocol");
888 return VNET_API_ERROR_INVALID_VALUE_2;
893 /* External address must be allocated */
894 if (!a && (l_addr.as_u32 != e_addr.as_u32))
896 if (sw_if_index != ~0)
898 for (i = 0; i < vec_len (sm->to_resolve); i++)
900 rp = sm->to_resolve + i;
903 if (rp->sw_if_index != sw_if_index &&
904 rp->l_addr.as_u32 != l_addr.as_u32 &&
905 rp->vrf_id != vrf_id && rp->l_port != l_port &&
906 rp->e_port != e_port && rp->proto != proto)
909 vec_del1 (sm->to_resolve, i);
913 return VNET_API_ERROR_NO_SUCH_ENTRY;
917 pool_get (sm->static_mappings, m);
918 clib_memset (m, 0, sizeof (*m));
919 m->tag = vec_dup (tag);
920 m->local_addr = l_addr;
921 m->external_addr = e_addr;
922 m->twice_nat = twice_nat;
924 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
926 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
929 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
930 pool_get (m->locals, local);
931 local->vrf_id = vrf_id;
932 local->fib_index = fib_index;
937 m->fib_index = fib_index;
941 m->local_port = l_port;
942 m->external_port = e_port;
946 if (sm->num_workers > 1)
949 .src_address = m->local_addr,
951 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
952 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
955 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
957 m_key.addr = m->local_addr;
958 m_key.port = m->local_port;
959 m_key.protocol = m->proto;
960 m_key.fib_index = fib_index;
961 kv.key = m_key.as_u64;
962 kv.value = m - sm->static_mappings;
964 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
966 m_key.addr = m->external_addr;
967 m_key.port = m->external_port;
969 kv.key = m_key.as_u64;
970 kv.value = m - sm->static_mappings;
971 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
973 /* Delete dynamic sessions matching local address (+ local port) */
974 if (!(sm->static_mapping_only))
976 u_key.addr = m->local_addr;
977 u_key.fib_index = m->fib_index;
978 kv.key = u_key.as_u64;
979 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
981 user_index = value.value;
982 u = pool_elt_at_index (tsm->users, user_index);
985 head_index = u->sessions_per_user_list_head_index;
986 head = pool_elt_at_index (tsm->list_pool, head_index);
987 elt_index = head->next;
988 elt = pool_elt_at_index (tsm->list_pool, elt_index);
989 ses_index = elt->value;
990 while (ses_index != ~0)
992 s = pool_elt_at_index (tsm->sessions, ses_index);
993 elt = pool_elt_at_index (tsm->list_pool, elt->next);
994 ses_index = elt->value;
996 if (snat_is_session_static (s))
1000 && (clib_net_to_host_u16 (s->in2out.port) !=
1004 nat_free_session_data (sm, s,
1005 tsm - sm->per_thread_data, 0);
1006 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1008 if (!addr_only && !sm->endpoint_dependent)
1019 if (sw_if_index != ~0)
1022 return VNET_API_ERROR_NO_SUCH_ENTRY;
1028 vrf_id = sm->inside_vrf_id;
1031 pool_foreach (local, m->locals,
1033 if (local->vrf_id == vrf_id)
1034 find = local - m->locals;
1038 return VNET_API_ERROR_NO_SUCH_ENTRY;
1040 local = pool_elt_at_index (m->locals, find);
1041 fib_index = local->fib_index;
1042 pool_put (m->locals, local);
1045 fib_index = m->fib_index;
1047 /* Free external address port */
1048 if (!(addr_only || sm->static_mapping_only || out2in_only))
1050 for (i = 0; i < vec_len (sm->addresses); i++)
1052 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1054 a = sm->addresses + i;
1057 #define _(N, j, n, s) \
1058 case SNAT_PROTOCOL_##N: \
1059 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1060 if (e_port > 1024) \
1062 a->busy_##n##_ports--; \
1063 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1066 foreach_snat_protocol
1069 nat_elog_info ("unknown protocol");
1070 return VNET_API_ERROR_INVALID_VALUE_2;
1077 if (sm->num_workers > 1)
1078 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1080 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1082 m_key.addr = m->local_addr;
1083 m_key.port = m->local_port;
1084 m_key.protocol = m->proto;
1085 m_key.fib_index = fib_index;
1086 kv.key = m_key.as_u64;
1088 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1090 /* Delete session(s) for static mapping if exist */
1091 if (!(sm->static_mapping_only) ||
1092 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1094 u_key.addr = m->local_addr;
1095 u_key.fib_index = fib_index;
1096 kv.key = u_key.as_u64;
1097 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1099 user_index = value.value;
1100 u = pool_elt_at_index (tsm->users, user_index);
1101 if (u->nstaticsessions)
1103 head_index = u->sessions_per_user_list_head_index;
1104 head = pool_elt_at_index (tsm->list_pool, head_index);
1105 elt_index = head->next;
1106 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1107 ses_index = elt->value;
1108 while (ses_index != ~0)
1110 s = pool_elt_at_index (tsm->sessions, ses_index);
1111 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1112 ses_index = elt->value;
1116 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1117 (clib_net_to_host_u16 (s->out2in.port) !=
1122 if (is_lb_session (s))
1125 if (!snat_is_session_static (s))
1128 nat_free_session_data (sm, s,
1129 tsm - sm->per_thread_data, 0);
1130 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1132 if (!addr_only && !sm->endpoint_dependent)
1139 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1140 if (pool_elts (m->locals))
1143 m_key.addr = m->external_addr;
1144 m_key.port = m->external_port;
1145 m_key.fib_index = 0;
1146 kv.key = m_key.as_u64;
1147 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1150 vec_free (m->workers);
1151 /* Delete static mapping from pool */
1152 pool_put (sm->static_mappings, m);
1155 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1158 /* Add/delete external address to FIB */
1160 pool_foreach (interface, sm->interfaces,
1162 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1165 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1168 pool_foreach (interface, sm->output_feature_interfaces,
1170 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1173 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1182 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1183 snat_protocol_t proto,
1184 nat44_lb_addr_port_t * locals, u8 is_add,
1185 twice_nat_type_t twice_nat, u8 out2in_only,
1186 u8 * tag, u32 affinity)
1188 snat_main_t *sm = &snat_main;
1189 snat_static_mapping_t *m;
1190 snat_session_key_t m_key;
1191 clib_bihash_kv_8_8_t kv, value;
1192 snat_address_t *a = 0;
1194 nat44_lb_addr_port_t *local;
1195 u32 elt_index, head_index, ses_index;
1196 snat_main_per_thread_data_t *tsm;
1197 snat_user_key_t u_key;
1200 dlist_elt_t *head, *elt;
1203 if (!sm->endpoint_dependent)
1204 return VNET_API_ERROR_FEATURE_DISABLED;
1206 m_key.addr = e_addr;
1207 m_key.port = e_port;
1208 m_key.protocol = proto;
1209 m_key.fib_index = 0;
1210 kv.key = m_key.as_u64;
1211 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1214 m = pool_elt_at_index (sm->static_mappings, value.value);
1219 return VNET_API_ERROR_VALUE_EXIST;
1221 if (vec_len (locals) < 2)
1222 return VNET_API_ERROR_INVALID_VALUE;
1224 /* Find external address in allocated addresses and reserve port for
1225 address and port pair mapping when dynamic translations enabled */
1226 if (!(sm->static_mapping_only || out2in_only))
1228 for (i = 0; i < vec_len (sm->addresses); i++)
1230 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1232 a = sm->addresses + i;
1233 /* External port must be unused */
1236 #define _(N, j, n, s) \
1237 case SNAT_PROTOCOL_##N: \
1238 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1239 return VNET_API_ERROR_INVALID_VALUE; \
1240 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1241 if (e_port > 1024) \
1243 a->busy_##n##_ports++; \
1244 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1247 foreach_snat_protocol
1250 nat_elog_info ("unknown protocol");
1251 return VNET_API_ERROR_INVALID_VALUE_2;
1256 /* External address must be allocated */
1258 return VNET_API_ERROR_NO_SUCH_ENTRY;
1261 pool_get (sm->static_mappings, m);
1262 clib_memset (m, 0, sizeof (*m));
1263 m->tag = vec_dup (tag);
1264 m->external_addr = e_addr;
1265 m->external_port = e_port;
1267 m->twice_nat = twice_nat;
1268 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1270 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1271 m->affinity = affinity;
1274 m->affinity_per_service_list_head_index =
1275 nat_affinity_get_per_service_list_head_index ();
1277 m->affinity_per_service_list_head_index = ~0;
1279 m_key.addr = m->external_addr;
1280 m_key.port = m->external_port;
1281 m_key.protocol = m->proto;
1282 m_key.fib_index = 0;
1283 kv.key = m_key.as_u64;
1284 kv.value = m - sm->static_mappings;
1285 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1287 nat_elog_err ("static_mapping_by_external key add failed");
1288 return VNET_API_ERROR_UNSPECIFIED;
1291 m_key.fib_index = m->fib_index;
1292 for (i = 0; i < vec_len (locals); i++)
1294 locals[i].fib_index =
1295 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1298 m_key.addr = locals[i].addr;
1299 m_key.fib_index = locals[i].fib_index;
1302 m_key.port = locals[i].port;
1303 kv.key = m_key.as_u64;
1304 kv.value = m - sm->static_mappings;
1305 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1307 locals[i].prefix = (i == 0) ? locals[i].probability :
1308 (locals[i - 1].prefix + locals[i].probability);
1309 pool_get (m->locals, local);
1311 if (sm->num_workers > 1)
1314 .src_address = locals[i].addr,
1317 clib_bitmap_set (bitmap,
1318 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1323 /* Assign workers */
1324 if (sm->num_workers > 1)
1327 clib_bitmap_foreach (i, bitmap,
1329 vec_add1(m->workers, i);
1337 return VNET_API_ERROR_NO_SUCH_ENTRY;
1339 if (!is_lb_static_mapping (m))
1340 return VNET_API_ERROR_INVALID_VALUE;
1342 /* Free external address port */
1343 if (!(sm->static_mapping_only || out2in_only))
1345 for (i = 0; i < vec_len (sm->addresses); i++)
1347 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1349 a = sm->addresses + i;
1352 #define _(N, j, n, s) \
1353 case SNAT_PROTOCOL_##N: \
1354 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1355 if (e_port > 1024) \
1357 a->busy_##n##_ports--; \
1358 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1361 foreach_snat_protocol
1364 nat_elog_info ("unknown protocol");
1365 return VNET_API_ERROR_INVALID_VALUE_2;
1372 m_key.addr = m->external_addr;
1373 m_key.port = m->external_port;
1374 m_key.protocol = m->proto;
1375 m_key.fib_index = 0;
1376 kv.key = m_key.as_u64;
1377 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1379 nat_elog_err ("static_mapping_by_external key del failed");
1380 return VNET_API_ERROR_UNSPECIFIED;
1384 pool_foreach (local, m->locals,
1386 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1388 m_key.addr = local->addr;
1391 m_key.port = local->port;
1392 m_key.fib_index = local->fib_index;
1393 kv.key = m_key.as_u64;
1394 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1396 nat_elog_err ("static_mapping_by_local key del failed");
1397 return VNET_API_ERROR_UNSPECIFIED;
1401 if (sm->num_workers > 1)
1404 .src_address = local->addr,
1406 tsm = vec_elt_at_index (sm->per_thread_data,
1407 sm->worker_in2out_cb (&ip, m->fib_index, 0));
1410 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1412 /* Delete sessions */
1413 u_key.addr = local->addr;
1414 u_key.fib_index = local->fib_index;
1415 kv.key = u_key.as_u64;
1416 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1418 u = pool_elt_at_index (tsm->users, value.value);
1419 if (u->nstaticsessions)
1421 head_index = u->sessions_per_user_list_head_index;
1422 head = pool_elt_at_index (tsm->list_pool, head_index);
1423 elt_index = head->next;
1424 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1425 ses_index = elt->value;
1426 while (ses_index != ~0)
1428 s = pool_elt_at_index (tsm->sessions, ses_index);
1429 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1430 ses_index = elt->value;
1432 if (!(is_lb_session (s)))
1435 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1436 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1439 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1440 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1447 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1448 pool_free (m->locals);
1450 vec_free (m->workers);
1452 pool_put (sm->static_mappings, m);
1459 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1460 ip4_address_t l_addr, u16 l_port,
1461 snat_protocol_t proto, u32 vrf_id,
1462 u8 probability, u8 is_add)
1464 snat_main_t *sm = &snat_main;
1465 snat_static_mapping_t *m = 0;
1466 snat_session_key_t m_key;
1467 clib_bihash_kv_8_8_t kv, value;
1468 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1469 snat_main_per_thread_data_t *tsm;
1470 snat_user_key_t u_key;
1473 dlist_elt_t *head, *elt;
1474 u32 elt_index, head_index, ses_index, *locals = 0;
1478 if (!sm->endpoint_dependent)
1479 return VNET_API_ERROR_FEATURE_DISABLED;
1481 m_key.addr = e_addr;
1482 m_key.port = e_port;
1483 m_key.protocol = proto;
1484 m_key.fib_index = 0;
1485 kv.key = m_key.as_u64;
1486 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1487 m = pool_elt_at_index (sm->static_mappings, value.value);
1490 return VNET_API_ERROR_NO_SUCH_ENTRY;
1492 if (!is_lb_static_mapping (m))
1493 return VNET_API_ERROR_INVALID_VALUE;
1496 pool_foreach (local, m->locals,
1498 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1499 (local->vrf_id == vrf_id))
1501 match_local = local;
1510 return VNET_API_ERROR_VALUE_EXIST;
1512 pool_get (m->locals, local);
1513 clib_memset (local, 0, sizeof (*local));
1514 local->addr.as_u32 = l_addr.as_u32;
1515 local->port = l_port;
1516 local->probability = probability;
1517 local->vrf_id = vrf_id;
1519 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1522 if (!is_out2in_only_static_mapping (m))
1524 m_key.addr = l_addr;
1525 m_key.port = l_port;
1526 m_key.fib_index = local->fib_index;
1527 kv.key = m_key.as_u64;
1528 kv.value = m - sm->static_mappings;
1529 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1530 nat_elog_err ("static_mapping_by_local key add failed");
1536 return VNET_API_ERROR_NO_SUCH_ENTRY;
1538 if (pool_elts (m->locals) < 3)
1539 return VNET_API_ERROR_UNSPECIFIED;
1541 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1544 if (!is_out2in_only_static_mapping (m))
1546 m_key.addr = l_addr;
1547 m_key.port = l_port;
1548 m_key.fib_index = match_local->fib_index;
1549 kv.key = m_key.as_u64;
1550 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1551 nat_elog_err ("static_mapping_by_local key del failed");
1554 if (sm->num_workers > 1)
1557 .src_address = local->addr,
1559 tsm = vec_elt_at_index (sm->per_thread_data,
1560 sm->worker_in2out_cb (&ip, m->fib_index,
1564 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1566 /* Delete sessions */
1567 u_key.addr = match_local->addr;
1568 u_key.fib_index = match_local->fib_index;
1569 kv.key = u_key.as_u64;
1570 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1572 u = pool_elt_at_index (tsm->users, value.value);
1573 if (u->nstaticsessions)
1575 head_index = u->sessions_per_user_list_head_index;
1576 head = pool_elt_at_index (tsm->list_pool, head_index);
1577 elt_index = head->next;
1578 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1579 ses_index = elt->value;
1580 while (ses_index != ~0)
1582 s = pool_elt_at_index (tsm->sessions, ses_index);
1583 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1584 ses_index = elt->value;
1586 if (!(is_lb_session (s)))
1589 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1590 (clib_net_to_host_u16 (s->in2out.port) !=
1594 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1595 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1600 pool_put (m->locals, match_local);
1603 vec_free (m->workers);
1606 pool_foreach (local, m->locals,
1608 vec_add1 (locals, local - m->locals);
1609 if (sm->num_workers > 1)
1612 ip.src_address.as_u32 = local->addr.as_u32,
1613 bitmap = clib_bitmap_set (bitmap,
1614 sm->worker_in2out_cb (&ip, local->fib_index, 0),
1620 ASSERT (vec_len (locals) > 1);
1622 local = pool_elt_at_index (m->locals, locals[0]);
1623 local->prefix = local->probability;
1624 for (i = 1; i < vec_len (locals); i++)
1626 local = pool_elt_at_index (m->locals, locals[i]);
1627 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1628 local->prefix = local->probability + prev_local->prefix;
1631 /* Assign workers */
1632 if (sm->num_workers > 1)
1635 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1643 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1646 snat_address_t *a = 0;
1647 snat_session_t *ses;
1648 u32 *ses_to_be_removed = 0, *ses_index;
1649 snat_main_per_thread_data_t *tsm;
1650 snat_static_mapping_t *m;
1651 snat_interface_t *interface;
1653 snat_address_t *addresses =
1654 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1656 /* Find SNAT address */
1657 for (i = 0; i < vec_len (addresses); i++)
1659 if (addresses[i].addr.as_u32 == addr.as_u32)
1666 return VNET_API_ERROR_NO_SUCH_ENTRY;
1671 pool_foreach (m, sm->static_mappings,
1673 if (m->external_addr.as_u32 == addr.as_u32)
1674 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1675 m->local_port, m->external_port,
1676 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1677 m->proto, 0, m->twice_nat,
1678 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1684 /* Check if address is used in some static mapping */
1685 if (is_snat_address_used_in_static_mapping (sm, addr))
1687 nat_elog_notice ("address used in static mapping");
1688 return VNET_API_ERROR_UNSPECIFIED;
1692 if (a->fib_index != ~0)
1693 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1695 /* Delete sessions using address */
1696 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1699 vec_foreach (tsm, sm->per_thread_data)
1701 pool_foreach (ses, tsm->sessions, ({
1702 if (ses->out2in.addr.as_u32 == addr.as_u32)
1704 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1705 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1709 vec_foreach (ses_index, ses_to_be_removed)
1711 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1712 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1715 vec_free (ses_to_be_removed);
1720 #define _(N, i, n, s) \
1721 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1722 vec_free (a->busy_##n##_ports_per_thread);
1723 foreach_snat_protocol
1727 vec_del1 (sm->twice_nat_addresses, i);
1731 vec_del1 (sm->addresses, i);
1733 /* Delete external address from FIB */
1735 pool_foreach (interface, sm->interfaces,
1737 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1740 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1743 pool_foreach (interface, sm->output_feature_interfaces,
1745 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1748 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1757 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1759 snat_main_t *sm = &snat_main;
1760 snat_interface_t *i;
1761 const char *feature_name, *del_feature_name;
1763 snat_static_mapping_t *m;
1765 nat_outside_fib_t *outside_fib;
1766 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1769 if (sm->out2in_dpo && !is_inside)
1770 return VNET_API_ERROR_UNSUPPORTED;
1773 pool_foreach (i, sm->output_feature_interfaces,
1775 if (i->sw_if_index == sw_if_index)
1776 return VNET_API_ERROR_VALUE_EXIST;
1780 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1781 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1784 if (sm->num_workers > 1 && !sm->deterministic)
1786 is_inside ? "nat44-in2out-worker-handoff" :
1787 "nat44-out2in-worker-handoff";
1788 else if (sm->deterministic)
1789 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1790 else if (sm->endpoint_dependent)
1792 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1795 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1798 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1799 sm->fq_in2out_index =
1800 vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
1802 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1803 sm->fq_out2in_index =
1804 vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
1809 vec_foreach (outside_fib, sm->outside_fibs)
1811 if (outside_fib->fib_index == fib_index)
1815 outside_fib->refcount--;
1816 if (!outside_fib->refcount)
1817 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1820 outside_fib->refcount++;
1827 vec_add2 (sm->outside_fibs, outside_fib, 1);
1828 outside_fib->refcount = 1;
1829 outside_fib->fib_index = fib_index;
1834 pool_foreach (i, sm->interfaces,
1836 if (i->sw_if_index == sw_if_index)
1840 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1843 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1845 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1847 if (sm->num_workers > 1 && !sm->deterministic)
1849 del_feature_name = "nat44-handoff-classify";
1850 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1851 "nat44-out2in-worker-handoff";
1853 else if (sm->deterministic)
1855 del_feature_name = "nat44-det-classify";
1856 feature_name = !is_inside ? "nat44-det-in2out" :
1859 else if (sm->endpoint_dependent)
1861 del_feature_name = "nat44-ed-classify";
1862 feature_name = !is_inside ? "nat-pre-in2out" :
1867 del_feature_name = "nat44-classify";
1868 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1871 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1872 sw_if_index, 0, 0, 0);
1873 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1874 sw_if_index, 1, 0, 0);
1877 if (sm->endpoint_dependent)
1878 vnet_feature_enable_disable ("ip4-local",
1879 "nat44-ed-hairpinning",
1880 sw_if_index, 1, 0, 0);
1881 else if (!sm->deterministic)
1882 vnet_feature_enable_disable ("ip4-local",
1883 "nat44-hairpinning",
1884 sw_if_index, 1, 0, 0);
1889 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1890 sw_if_index, 0, 0, 0);
1891 pool_put (sm->interfaces, i);
1894 if (sm->endpoint_dependent)
1895 vnet_feature_enable_disable ("ip4-local",
1896 "nat44-ed-hairpinning",
1897 sw_if_index, 0, 0, 0);
1898 else if (!sm->deterministic)
1899 vnet_feature_enable_disable ("ip4-local",
1900 "nat44-hairpinning",
1901 sw_if_index, 0, 0, 0);
1907 if ((nat_interface_is_inside(i) && is_inside) ||
1908 (nat_interface_is_outside(i) && !is_inside))
1911 if (sm->num_workers > 1 && !sm->deterministic)
1913 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1914 "nat44-out2in-worker-handoff";
1915 feature_name = "nat44-handoff-classify";
1917 else if (sm->deterministic)
1919 del_feature_name = !is_inside ? "nat44-det-in2out" :
1921 feature_name = "nat44-det-classify";
1923 else if (sm->endpoint_dependent)
1925 del_feature_name = !is_inside ? "nat-pre-in2out" :
1928 feature_name = "nat44-ed-classify";
1932 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1933 feature_name = "nat44-classify";
1936 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1937 sw_if_index, 0, 0, 0);
1938 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1939 sw_if_index, 1, 0, 0);
1942 if (sm->endpoint_dependent)
1943 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1944 sw_if_index, 0, 0, 0);
1945 else if (!sm->deterministic)
1946 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1947 sw_if_index, 0, 0, 0);
1958 return VNET_API_ERROR_NO_SUCH_ENTRY;
1960 pool_get (sm->interfaces, i);
1961 i->sw_if_index = sw_if_index;
1963 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1966 if (is_inside && !sm->out2in_dpo)
1968 if (sm->endpoint_dependent)
1969 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1970 sw_if_index, 1, 0, 0);
1971 else if (!sm->deterministic)
1972 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1973 sw_if_index, 1, 0, 0);
1979 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1983 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1985 /* Add/delete external addresses to FIB */
1988 vec_foreach (ap, sm->addresses)
1989 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1991 pool_foreach (m, sm->static_mappings,
1993 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1996 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1999 pool_foreach (dm, sm->det_maps,
2001 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2009 snat_interface_add_del_output_feature (u32 sw_if_index,
2010 u8 is_inside, int is_del)
2012 snat_main_t *sm = &snat_main;
2013 snat_interface_t *i;
2015 snat_static_mapping_t *m;
2016 nat_outside_fib_t *outside_fib;
2017 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2021 if (sm->deterministic ||
2022 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2023 return VNET_API_ERROR_UNSUPPORTED;
2026 pool_foreach (i, sm->interfaces,
2028 if (i->sw_if_index == sw_if_index)
2029 return VNET_API_ERROR_VALUE_EXIST;
2036 vec_foreach (outside_fib, sm->outside_fibs)
2038 if (outside_fib->fib_index == fib_index)
2042 outside_fib->refcount--;
2043 if (!outside_fib->refcount)
2044 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2047 outside_fib->refcount++;
2054 vec_add2 (sm->outside_fibs, outside_fib, 1);
2055 outside_fib->refcount = 1;
2056 outside_fib->fib_index = fib_index;
2063 if (sm->endpoint_dependent)
2065 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2066 sw_if_index, !is_del, 0, 0);
2067 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2068 sw_if_index, !is_del, 0, 0);
2072 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2073 sw_if_index, !is_del, 0, 0);
2074 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2075 sw_if_index, !is_del, 0, 0);
2080 if (sm->num_workers > 1)
2082 vnet_feature_enable_disable ("ip4-unicast",
2083 "nat44-out2in-worker-handoff",
2084 sw_if_index, !is_del, 0, 0);
2085 vnet_feature_enable_disable ("ip4-output",
2086 "nat44-in2out-output-worker-handoff",
2087 sw_if_index, !is_del, 0, 0);
2091 if (sm->endpoint_dependent)
2093 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2094 sw_if_index, !is_del, 0, 0);
2095 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2096 sw_if_index, !is_del, 0, 0);
2100 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2101 sw_if_index, !is_del, 0, 0);
2102 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2103 sw_if_index, !is_del, 0, 0);
2108 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2109 sm->fq_in2out_output_index =
2110 vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
2112 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2113 sm->fq_out2in_index =
2114 vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
2117 pool_foreach (i, sm->output_feature_interfaces,
2119 if (i->sw_if_index == sw_if_index)
2122 pool_put (sm->output_feature_interfaces, i);
2124 return VNET_API_ERROR_VALUE_EXIST;
2132 return VNET_API_ERROR_NO_SUCH_ENTRY;
2134 pool_get (sm->output_feature_interfaces, i);
2135 i->sw_if_index = sw_if_index;
2138 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2140 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2142 /* Add/delete external addresses to FIB */
2148 vec_foreach (ap, sm->addresses)
2149 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2151 pool_foreach (m, sm->static_mappings,
2153 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2156 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2164 snat_set_workers (uword * bitmap)
2166 snat_main_t *sm = &snat_main;
2169 if (sm->num_workers < 2)
2170 return VNET_API_ERROR_FEATURE_DISABLED;
2172 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2173 return VNET_API_ERROR_INVALID_WORKER;
2175 vec_free (sm->workers);
2177 clib_bitmap_foreach (i, bitmap,
2179 vec_add1(sm->workers, i);
2180 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2181 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2186 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2187 sm->num_snat_thread = _vec_len (sm->workers);
2193 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2196 snat_main_t *sm = &snat_main;
2197 nat_outside_fib_t *outside_fib;
2198 snat_interface_t *i;
2202 if (new_fib_index == old_fib_index)
2205 if (!vec_len (sm->outside_fibs))
2209 pool_foreach (i, sm->interfaces,
2211 if (i->sw_if_index == sw_if_index)
2213 if (!(nat_interface_is_outside (i)))
2219 pool_foreach (i, sm->output_feature_interfaces,
2221 if (i->sw_if_index == sw_if_index)
2223 if (!(nat_interface_is_outside (i)))
2233 vec_foreach (outside_fib, sm->outside_fibs)
2235 if (outside_fib->fib_index == old_fib_index)
2237 outside_fib->refcount--;
2238 if (!outside_fib->refcount)
2239 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2244 vec_foreach (outside_fib, sm->outside_fibs)
2246 if (outside_fib->fib_index == new_fib_index)
2248 outside_fib->refcount++;
2256 vec_add2 (sm->outside_fibs, outside_fib, 1);
2257 outside_fib->refcount = 1;
2258 outside_fib->fib_index = new_fib_index;
2263 snat_ip4_table_bind (ip4_main_t * im,
2265 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2267 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2271 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2274 ip4_address_t * address,
2276 u32 if_address_index, u32 is_delete);
2279 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2282 ip4_address_t * address,
2284 u32 if_address_index, u32 is_delete);
2287 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2290 snat_session_key_t * k,
2291 u16 port_per_thread, u32 snat_thread_index);
2293 static clib_error_t *
2294 snat_init (vlib_main_t * vm)
2296 snat_main_t *sm = &snat_main;
2297 clib_error_t *error = 0;
2298 ip4_main_t *im = &ip4_main;
2299 ip_lookup_main_t *lm = &im->lookup_main;
2301 vlib_thread_registration_t *tr;
2302 vlib_thread_main_t *tm = vlib_get_thread_main ();
2305 ip4_add_del_interface_address_callback_t cb4;
2309 sm->vnet_main = vnet_get_main ();
2311 sm->ip4_lookup_main = lm;
2312 sm->api_main = &api_main;
2313 sm->first_worker_index = 0;
2314 sm->num_workers = 0;
2315 sm->num_snat_thread = 1;
2317 sm->port_per_thread = 0xffff - 1024;
2318 sm->fq_in2out_index = ~0;
2319 sm->fq_in2out_output_index = ~0;
2320 sm->fq_out2in_index = ~0;
2321 sm->udp_timeout = SNAT_UDP_TIMEOUT;
2322 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
2323 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
2324 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
2325 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2326 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2327 sm->forwarding_enabled = 0;
2328 sm->log_class = vlib_log_register_class ("nat", 0);
2329 sm->log_level = SNAT_LOG_ERROR;
2330 sm->mss_clamping = 0;
2332 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2333 sm->error_node_index = node->index;
2335 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2336 sm->pre_in2out_node_index = node->index;
2337 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2338 sm->pre_out2in_node_index = node->index;
2340 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2341 sm->pre_in2out_node_index = node->index;
2343 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2344 sm->pre_out2in_node_index = node->index;
2346 // TODO: output ?? (special node)
2348 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2349 sm->in2out_node_index = node->index;
2350 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2351 sm->in2out_output_node_index = node->index;
2352 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2353 sm->in2out_fast_node_index = node->index;
2354 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2355 sm->in2out_slowpath_node_index = node->index;
2356 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2357 sm->in2out_slowpath_output_node_index = node->index;
2358 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-reass");
2359 sm->in2out_reass_node_index = node->index;
2361 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2362 sm->ed_in2out_node_index = node->index;
2363 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2364 sm->ed_in2out_slowpath_node_index = node->index;
2365 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-reass");
2366 sm->ed_in2out_reass_node_index = node->index;
2368 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2369 sm->out2in_node_index = node->index;
2370 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2371 sm->out2in_fast_node_index = node->index;
2372 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-reass");
2373 sm->out2in_reass_node_index = node->index;
2375 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2376 sm->ed_out2in_node_index = node->index;
2377 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2378 sm->ed_out2in_slowpath_node_index = node->index;
2379 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-reass");
2380 sm->ed_out2in_reass_node_index = node->index;
2382 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2383 sm->det_in2out_node_index = node->index;
2384 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2385 sm->det_out2in_node_index = node->index;
2387 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2388 sm->hairpinning_node_index = node->index;
2389 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2390 sm->hairpin_dst_node_index = node->index;
2391 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2392 sm->hairpin_src_node_index = node->index;
2393 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2394 sm->ed_hairpinning_node_index = node->index;
2395 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2396 sm->ed_hairpin_dst_node_index = node->index;
2397 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2398 sm->ed_hairpin_src_node_index = node->index;
2400 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2403 tr = (vlib_thread_registration_t *) p[0];
2406 sm->num_workers = tr->count;
2407 sm->first_worker_index = tr->first_index;
2411 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2413 /* Use all available workers by default */
2414 if (sm->num_workers > 1)
2416 for (i = 0; i < sm->num_workers; i++)
2417 bitmap = clib_bitmap_set (bitmap, i, 1);
2418 snat_set_workers (bitmap);
2419 clib_bitmap_free (bitmap);
2423 sm->per_thread_data[0].snat_thread_index = 0;
2426 error = snat_api_init (vm, sm);
2430 /* Set up the interface address add/del callback */
2431 cb4.function = snat_ip4_add_del_interface_address_cb;
2432 cb4.function_opaque = 0;
2434 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2436 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2437 cb4.function_opaque = 0;
2439 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2441 nat_dpo_module_init ();
2444 sm->total_users.name = "total-users";
2445 sm->total_users.stat_segment_name = "/nat44/total-users";
2446 vlib_validate_simple_counter (&sm->total_users, 0);
2447 vlib_zero_simple_counter (&sm->total_users, 0);
2448 sm->total_sessions.name = "total-sessions";
2449 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2450 vlib_validate_simple_counter (&sm->total_sessions, 0);
2451 vlib_zero_simple_counter (&sm->total_sessions, 0);
2453 /* Init IPFIX logging */
2454 snat_ipfix_logging_init (vm);
2457 error = nat64_init (vm);
2465 ip4_table_bind_callback_t cbt4 = {
2466 .function = snat_ip4_table_bind,
2468 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2470 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2471 FIB_SOURCE_PRIORITY_HI,
2472 FIB_SOURCE_BH_SIMPLE);
2473 nat_fib_src_low = fib_source_allocate ("nat-low",
2474 FIB_SOURCE_PRIORITY_LOW,
2475 FIB_SOURCE_BH_SIMPLE);
2477 /* Init virtual fragmenentation reassembly */
2478 return nat_reass_init (vm);
2481 VLIB_INIT_FUNCTION (snat_init);
2484 snat_free_outside_address_and_port (snat_address_t * addresses,
2485 u32 thread_index, snat_session_key_t * k)
2489 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2491 for (address_index = 0; address_index < vec_len (addresses);
2494 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2498 ASSERT (address_index < vec_len (addresses));
2500 a = addresses + address_index;
2502 switch (k->protocol)
2504 #define _(N, i, n, s) \
2505 case SNAT_PROTOCOL_##N: \
2506 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2507 port_host_byte_order) == 1); \
2508 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2509 port_host_byte_order, 0); \
2510 a->busy_##n##_ports--; \
2511 a->busy_##n##_ports_per_thread[thread_index]--; \
2513 foreach_snat_protocol
2516 nat_elog_info ("unknown protocol");
2522 nat_set_outside_address_and_port (snat_address_t * addresses,
2523 u32 thread_index, snat_session_key_t * k)
2525 snat_address_t *a = 0;
2527 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2529 for (address_index = 0; address_index < vec_len (addresses);
2532 if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2535 a = addresses + address_index;
2536 switch (k->protocol)
2538 #define _(N, j, n, s) \
2539 case SNAT_PROTOCOL_##N: \
2540 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
2541 return VNET_API_ERROR_INSTANCE_IN_USE; \
2542 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
2543 a->busy_##n##_ports_per_thread[thread_index]++; \
2544 a->busy_##n##_ports++; \
2546 foreach_snat_protocol
2549 nat_elog_info ("unknown protocol");
2554 return VNET_API_ERROR_NO_SUCH_ENTRY;
2558 snat_static_mapping_match (snat_main_t * sm,
2559 snat_session_key_t match,
2560 snat_session_key_t * mapping,
2563 twice_nat_type_t * twice_nat,
2564 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2565 u8 * is_identity_nat)
2567 clib_bihash_kv_8_8_t kv, value;
2568 snat_static_mapping_t *m;
2569 snat_session_key_t m_key;
2570 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2571 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2573 nat44_lb_addr_port_t *local;
2575 m_key.fib_index = match.fib_index;
2578 mapping_hash = &sm->static_mapping_by_external;
2579 m_key.fib_index = 0;
2582 m_key.addr = match.addr;
2583 m_key.port = clib_net_to_host_u16 (match.port);
2584 m_key.protocol = match.protocol;
2586 kv.key = m_key.as_u64;
2588 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2590 /* Try address only mapping */
2593 kv.key = m_key.as_u64;
2594 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2598 m = pool_elt_at_index (sm->static_mappings, value.value);
2602 if (is_lb_static_mapping (m))
2604 if (PREDICT_FALSE (lb != 0))
2605 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2606 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2612 local = pool_elt_at_index (m->locals, backend_index);
2613 mapping->addr = local->addr;
2614 mapping->port = clib_host_to_net_u16 (local->port);
2615 mapping->fib_index = local->fib_index;
2618 // pick locals matching this worker
2619 if (PREDICT_FALSE (sm->num_workers > 1))
2621 u32 thread_index = vlib_get_thread_index ();
2623 pool_foreach_index (i, m->locals,
2625 local = pool_elt_at_index (m->locals, i);
2628 .src_address = local->addr,
2631 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2638 ASSERT (vec_len (tmp) != 0);
2643 pool_foreach_index (i, m->locals,
2649 hi = vec_len (tmp) - 1;
2650 local = pool_elt_at_index (m->locals, tmp[hi]);
2651 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2654 mid = ((hi - lo) >> 1) + lo;
2655 local = pool_elt_at_index (m->locals, tmp[mid]);
2656 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2658 local = pool_elt_at_index (m->locals, tmp[lo]);
2659 if (!(local->prefix >= rand))
2661 mapping->addr = local->addr;
2662 mapping->port = clib_host_to_net_u16 (local->port);
2663 mapping->fib_index = local->fib_index;
2666 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2667 match.protocol, match.port,
2668 tmp[lo], m->affinity,
2669 m->affinity_per_service_list_head_index))
2670 nat_elog_info ("create affinity record failed");
2676 if (PREDICT_FALSE (lb != 0))
2678 mapping->fib_index = m->fib_index;
2679 mapping->addr = m->local_addr;
2680 /* Address only mapping doesn't change port */
2681 mapping->port = is_addr_only_static_mapping (m) ? match.port
2682 : clib_host_to_net_u16 (m->local_port);
2684 mapping->protocol = m->proto;
2688 mapping->addr = m->external_addr;
2689 /* Address only mapping doesn't change port */
2690 mapping->port = is_addr_only_static_mapping (m) ? match.port
2691 : clib_host_to_net_u16 (m->external_port);
2692 mapping->fib_index = sm->outside_fib_index;
2696 if (PREDICT_FALSE (is_addr_only != 0))
2697 *is_addr_only = is_addr_only_static_mapping (m);
2699 if (PREDICT_FALSE (twice_nat != 0))
2700 *twice_nat = m->twice_nat;
2702 if (PREDICT_FALSE (is_identity_nat != 0))
2703 *is_identity_nat = is_identity_static_mapping (m);
2708 static_always_inline u16
2709 snat_random_port (u16 min, u16 max)
2711 snat_main_t *sm = &snat_main;
2712 return min + random_u32 (&sm->random_seed) /
2713 (random_u32_max () / (max - min + 1) + 1);
2717 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2720 snat_session_key_t * k,
2721 u16 port_per_thread,
2722 u32 snat_thread_index)
2724 snat_main_t *sm = &snat_main;
2726 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2727 port_per_thread, snat_thread_index);
2731 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2734 snat_session_key_t * k,
2735 u16 port_per_thread, u32 snat_thread_index)
2738 snat_address_t *a, *ga = 0;
2741 for (i = 0; i < vec_len (addresses); i++)
2744 switch (k->protocol)
2746 #define _(N, j, n, s) \
2747 case SNAT_PROTOCOL_##N: \
2748 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2750 if (a->fib_index == fib_index) \
2754 portnum = (port_per_thread * \
2755 snat_thread_index) + \
2756 snat_random_port(1, port_per_thread) + 1024; \
2757 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2759 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2760 a->busy_##n##_ports_per_thread[thread_index]++; \
2761 a->busy_##n##_ports++; \
2762 k->addr = a->addr; \
2763 k->port = clib_host_to_net_u16(portnum); \
2767 else if (a->fib_index == ~0) \
2773 foreach_snat_protocol
2776 nat_elog_info ("unknown protocol");
2785 switch (k->protocol)
2787 #define _(N, j, n, s) \
2788 case SNAT_PROTOCOL_##N: \
2791 portnum = (port_per_thread * \
2792 snat_thread_index) + \
2793 snat_random_port(1, port_per_thread) + 1024; \
2794 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2796 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2797 a->busy_##n##_ports_per_thread[thread_index]++; \
2798 a->busy_##n##_ports++; \
2799 k->addr = a->addr; \
2800 k->port = clib_host_to_net_u16(portnum); \
2804 foreach_snat_protocol
2807 nat_elog_info ("unknown protocol");
2812 /* Totally out of translations to use... */
2813 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2818 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2821 snat_session_key_t * k,
2822 u16 port_per_thread, u32 snat_thread_index)
2824 snat_main_t *sm = &snat_main;
2825 snat_address_t *a = addresses;
2826 u16 m, ports, portnum, A, j;
2827 m = 16 - (sm->psid_offset + sm->psid_length);
2828 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2830 if (!vec_len (addresses))
2833 switch (k->protocol)
2835 #define _(N, i, n, s) \
2836 case SNAT_PROTOCOL_##N: \
2837 if (a->busy_##n##_ports < ports) \
2841 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2842 j = snat_random_port(0, pow2_mask(m)); \
2843 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2844 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2846 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2847 a->busy_##n##_ports++; \
2848 k->addr = a->addr; \
2849 k->port = clib_host_to_net_u16 (portnum); \
2854 foreach_snat_protocol
2857 nat_elog_info ("unknown protocol");
2862 /* Totally out of translations to use... */
2863 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2868 nat_alloc_addr_and_port_range (snat_address_t * addresses,
2871 snat_session_key_t * k,
2872 u16 port_per_thread, u32 snat_thread_index)
2874 snat_main_t *sm = &snat_main;
2875 snat_address_t *a = addresses;
2878 ports = sm->end_port - sm->start_port + 1;
2880 if (!vec_len (addresses))
2883 switch (k->protocol)
2885 #define _(N, i, n, s) \
2886 case SNAT_PROTOCOL_##N: \
2887 if (a->busy_##n##_ports < ports) \
2891 portnum = snat_random_port(sm->start_port, sm->end_port); \
2892 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2894 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2895 a->busy_##n##_ports++; \
2896 k->addr = a->addr; \
2897 k->port = clib_host_to_net_u16 (portnum); \
2902 foreach_snat_protocol
2905 nat_elog_info ("unknown protocol");
2910 /* Totally out of translations to use... */
2911 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
2916 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2918 dpo_id_t dpo_v4 = DPO_INVALID;
2919 fib_prefix_t pfx = {
2920 .fp_proto = FIB_PROTOCOL_IP4,
2922 .fp_addr.ip4.as_u32 = addr.as_u32,
2927 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2928 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
2929 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2930 dpo_reset (&dpo_v4);
2934 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
2939 format_session_kvp (u8 * s, va_list * args)
2941 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2942 snat_session_key_t k;
2946 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2952 format_static_mapping_kvp (u8 * s, va_list * args)
2954 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2955 snat_session_key_t k;
2959 s = format (s, "%U static-mapping-index %llu",
2960 format_static_mapping_key, &k, v->value);
2966 format_user_kvp (u8 * s, va_list * args)
2968 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2973 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2974 k.fib_index, v->value);
2980 format_ed_session_kvp (u8 * s, va_list * args)
2982 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2985 k.as_u64[0] = v->key[0];
2986 k.as_u64[1] = v->key[1];
2989 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2990 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2991 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2992 format_ip_protocol, k.proto, k.fib_index, v->value);
2998 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3001 snat_main_t *sm = &snat_main;
3002 u32 next_worker_index = 0;
3005 next_worker_index = sm->first_worker_index;
3006 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3007 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3009 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3010 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3012 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3014 return next_worker_index;
3018 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3021 snat_main_t *sm = &snat_main;
3024 snat_session_key_t m_key;
3025 clib_bihash_kv_8_8_t kv, value;
3026 snat_static_mapping_t *m;
3028 u32 next_worker_index = 0;
3030 /* first try static mappings without port */
3031 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3033 m_key.addr = ip0->dst_address;
3036 m_key.fib_index = rx_fib_index0;
3037 kv.key = m_key.as_u64;
3038 if (!clib_bihash_search_8_8
3039 (&sm->static_mapping_by_external, &kv, &value))
3041 m = pool_elt_at_index (sm->static_mappings, value.value);
3042 return m->workers[0];
3046 proto = ip_proto_to_snat_proto (ip0->protocol);
3047 udp = ip4_next_header (ip0);
3048 port = udp->dst_port;
3050 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
3052 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
3053 return vlib_get_thread_index ();
3055 nat_reass_ip4_t *reass;
3056 reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
3057 ip0->fragment_id, ip0->protocol);
3059 if (reass && (reass->thread_index != (u32) ~ 0))
3060 return reass->thread_index;
3062 if (ip4_is_first_fragment (ip0))
3065 nat_ip4_reass_create (ip0->src_address, ip0->dst_address,
3066 ip0->fragment_id, ip0->protocol);
3070 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3072 m_key.addr = ip0->dst_address;
3073 m_key.port = clib_net_to_host_u16 (port);
3074 m_key.protocol = proto;
3075 m_key.fib_index = rx_fib_index0;
3076 kv.key = m_key.as_u64;
3077 if (!clib_bihash_search_8_8
3078 (&sm->static_mapping_by_external, &kv, &value))
3080 m = pool_elt_at_index (sm->static_mappings, value.value);
3081 reass->thread_index = m->workers[0];
3082 return reass->thread_index;
3085 reass->thread_index = sm->first_worker_index;
3086 reass->thread_index +=
3087 sm->workers[(clib_net_to_host_u16 (port) - 1024) /
3088 sm->port_per_thread];
3089 return reass->thread_index;
3092 return vlib_get_thread_index ();
3096 /* unknown protocol */
3097 if (PREDICT_FALSE (proto == ~0))
3099 /* use current thread */
3100 return vlib_get_thread_index ();
3103 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3105 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3106 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3107 if (!icmp_is_error_message (icmp))
3108 port = echo->identifier;
3111 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3112 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3113 void *l4_header = ip4_next_header (inner_ip);
3116 case SNAT_PROTOCOL_ICMP:
3117 icmp = (icmp46_header_t *) l4_header;
3118 echo = (icmp_echo_header_t *) (icmp + 1);
3119 port = echo->identifier;
3121 case SNAT_PROTOCOL_UDP:
3122 case SNAT_PROTOCOL_TCP:
3123 port = ((tcp_udp_header_t *) l4_header)->src_port;
3126 return vlib_get_thread_index ();
3131 /* try static mappings with port */
3132 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3134 m_key.addr = ip0->dst_address;
3135 m_key.port = clib_net_to_host_u16 (port);
3136 m_key.protocol = proto;
3137 m_key.fib_index = rx_fib_index0;
3138 kv.key = m_key.as_u64;
3139 if (!clib_bihash_search_8_8
3140 (&sm->static_mapping_by_external, &kv, &value))
3142 m = pool_elt_at_index (sm->static_mappings, value.value);
3143 return m->workers[0];
3147 /* worker by outside port */
3148 next_worker_index = sm->first_worker_index;
3149 next_worker_index +=
3150 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3151 return next_worker_index;
3155 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3158 snat_main_t *sm = &snat_main;
3159 u32 next_worker_index = sm->first_worker_index;
3162 clib_bihash_kv_16_8_t kv16, value16;
3163 snat_main_per_thread_data_t *tsm;
3166 if (PREDICT_FALSE (is_output))
3168 u32 fib_index = sm->outside_fib_index;
3169 nat_outside_fib_t *outside_fib;
3170 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3171 fib_prefix_t pfx = {
3172 .fp_proto = FIB_PROTOCOL_IP4,
3175 .ip4.as_u32 = ip->dst_address.as_u32,
3180 udp = ip4_next_header (ip);
3182 switch (vec_len (sm->outside_fibs))
3185 fib_index = sm->outside_fib_index;
3188 fib_index = sm->outside_fibs[0].fib_index;
3192 vec_foreach (outside_fib, sm->outside_fibs)
3194 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3195 if (FIB_NODE_INDEX_INVALID != fei)
3197 if (fib_entry_get_resolving_interface (fei) != ~0)
3199 fib_index = outside_fib->fib_index;
3208 make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
3209 ip->protocol, fib_index, udp->src_port, udp->dst_port);
3212 vec_foreach (tsm, sm->per_thread_data)
3214 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3217 next_worker_index += tsm->thread_index;
3219 nat_elog_debug_handoff (
3220 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3221 next_worker_index, fib_index,
3222 clib_net_to_host_u32 (ip->src_address.as_u32),
3223 clib_net_to_host_u32 (ip->dst_address.as_u32));
3225 return next_worker_index;
3231 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3232 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3234 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3235 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3237 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3239 if (PREDICT_TRUE (!is_output))
3241 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3242 next_worker_index, rx_fib_index,
3243 clib_net_to_host_u32 (ip->src_address.as_u32),
3244 clib_net_to_host_u32 (ip->dst_address.as_u32));
3248 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3249 next_worker_index, rx_fib_index,
3250 clib_net_to_host_u32 (ip->src_address.as_u32),
3251 clib_net_to_host_u32 (ip->dst_address.as_u32));
3254 return next_worker_index;
3258 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index,
3261 snat_main_t *sm = &snat_main;
3262 clib_bihash_kv_8_8_t kv, value;
3263 clib_bihash_kv_16_8_t kv16, value16;
3264 snat_main_per_thread_data_t *tsm;
3266 u32 proto, next_worker_index = 0;
3269 snat_static_mapping_t *m;
3272 proto = ip_proto_to_snat_proto (ip->protocol);
3274 if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3276 udp = ip4_next_header (ip);
3278 make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
3279 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
3282 vec_foreach (tsm, sm->per_thread_data)
3284 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3287 next_worker_index = sm->first_worker_index + tsm->thread_index;
3288 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3289 next_worker_index, rx_fib_index,
3290 clib_net_to_host_u32 (ip->src_address.as_u32),
3291 clib_net_to_host_u32 (ip->dst_address.as_u32));
3292 return next_worker_index;
3297 else if (proto == SNAT_PROTOCOL_ICMP)
3299 nat_ed_ses_key_t key;
3301 if (!get_icmp_o2i_ed_key (ip, &key))
3304 key.fib_index = rx_fib_index;
3305 kv16.key[0] = key.as_u64[0];
3306 kv16.key[1] = key.as_u64[1];
3309 vec_foreach (tsm, sm->per_thread_data)
3311 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3314 next_worker_index = sm->first_worker_index +
3316 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3317 next_worker_index, rx_fib_index,
3318 clib_net_to_host_u32 (ip->src_address.as_u32),
3319 clib_net_to_host_u32 (ip->dst_address.as_u32));
3320 return next_worker_index;
3327 /* first try static mappings without port */
3328 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3330 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3331 if (!clib_bihash_search_8_8
3332 (&sm->static_mapping_by_external, &kv, &value))
3334 m = pool_elt_at_index (sm->static_mappings, value.value);
3335 next_worker_index = m->workers[0];
3340 /* unknown protocol */
3341 if (PREDICT_FALSE (proto == ~0))
3343 /* use current thread */
3344 next_worker_index = vlib_get_thread_index ();
3348 udp = ip4_next_header (ip);
3349 port = udp->dst_port;
3351 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3353 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3354 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3355 if (!icmp_is_error_message (icmp))
3356 port = echo->identifier;
3359 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3360 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3361 void *l4_header = ip4_next_header (inner_ip);
3364 case SNAT_PROTOCOL_ICMP:
3365 icmp = (icmp46_header_t *) l4_header;
3366 echo = (icmp_echo_header_t *) (icmp + 1);
3367 port = echo->identifier;
3369 case SNAT_PROTOCOL_UDP:
3370 case SNAT_PROTOCOL_TCP:
3371 port = ((tcp_udp_header_t *) l4_header)->src_port;
3374 next_worker_index = vlib_get_thread_index ();
3380 /* try static mappings with port */
3381 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3383 make_sm_kv (&kv, &ip->dst_address, proto, 0,
3384 clib_net_to_host_u16 (port));
3385 if (!clib_bihash_search_8_8
3386 (&sm->static_mapping_by_external, &kv, &value))
3388 m = pool_elt_at_index (sm->static_mappings, value.value);
3389 if (!is_lb_static_mapping (m))
3391 next_worker_index = m->workers[0];
3395 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3396 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3398 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3400 m->workers[hash & (_vec_len (m->workers) - 1)];
3402 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3407 /* worker by outside port */
3408 next_worker_index = sm->first_worker_index;
3409 next_worker_index +=
3410 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3413 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3414 clib_net_to_host_u32 (ip->src_address.as_u32),
3415 clib_net_to_host_u32 (ip->dst_address.as_u32));
3416 return next_worker_index;
3420 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3421 ip4_address_t * out_addr, u16 out_port,
3422 ip4_address_t * eh_addr, u16 eh_port,
3423 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3424 u32 fib_index, u16 flags, u32 thread_index)
3426 snat_main_t *sm = &snat_main;
3427 snat_session_key_t key;
3430 clib_bihash_kv_8_8_t kv;
3431 f64 now = vlib_time_now (sm->vlib_main);
3432 nat_outside_fib_t *outside_fib;
3433 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3434 snat_main_per_thread_data_t *tsm;
3435 fib_prefix_t pfx = {
3436 .fp_proto = FIB_PROTOCOL_IP4,
3439 .ip4.as_u32 = eh_addr->as_u32,
3443 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3445 key.addr.as_u32 = out_addr->as_u32;
3446 key.port = out_port;
3447 key.protocol = proto;
3449 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3451 if (nat_set_outside_address_and_port
3452 (sm->addresses, thread_index, &key))
3456 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3460 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3464 s->last_heard = now;
3466 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3467 s->ext_host_port = eh_port;
3468 user_session_increment (sm, u, snat_is_session_static (s));
3469 switch (vec_len (sm->outside_fibs))
3472 key.fib_index = sm->outside_fib_index;
3475 key.fib_index = sm->outside_fibs[0].fib_index;
3479 vec_foreach (outside_fib, sm->outside_fibs)
3481 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3482 if (FIB_NODE_INDEX_INVALID != fei)
3484 if (fib_entry_get_resolving_interface (fei) != ~0)
3486 key.fib_index = outside_fib->fib_index;
3495 kv.key = key.as_u64;
3496 kv.value = s - tsm->sessions;
3497 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3498 nat_elog_warn ("out2in key add failed");
3500 key.addr.as_u32 = in_addr->as_u32;
3502 key.fib_index = fib_index;
3504 kv.key = key.as_u64;
3505 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3506 nat_elog_warn ("in2out key add failed");
3510 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3511 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3514 snat_main_t *sm = &snat_main;
3515 snat_session_key_t key;
3516 clib_bihash_kv_8_8_t kv, value;
3519 snat_main_per_thread_data_t *tsm;
3521 if (sm->num_workers > 1)
3523 sm->first_worker_index +
3524 (sm->workers[(clib_net_to_host_u16 (out_port) -
3525 1024) / sm->port_per_thread]);
3527 thread_index = sm->num_workers;
3528 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3530 key.addr.as_u32 = out_addr->as_u32;
3531 key.port = out_port;
3532 key.protocol = proto;
3533 key.fib_index = fib_index;
3534 kv.key = key.as_u64;
3535 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3538 s = pool_elt_at_index (tsm->sessions, value.value);
3539 nat_free_session_data (sm, s, thread_index, 1);
3540 nat44_delete_session (sm, s, thread_index);
3544 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3545 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3546 u32 total_pkts, u64 total_bytes, u32 thread_index)
3548 snat_main_t *sm = &snat_main;
3549 snat_session_key_t key;
3550 clib_bihash_kv_8_8_t kv, value;
3552 snat_main_per_thread_data_t *tsm;
3554 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3556 key.addr.as_u32 = out_addr->as_u32;
3557 key.port = out_port;
3558 key.protocol = proto;
3559 key.fib_index = fib_index;
3560 kv.key = key.as_u64;
3561 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3564 s = pool_elt_at_index (tsm->sessions, value.value);
3565 s->total_pkts = total_pkts;
3566 s->total_bytes = total_bytes;
3570 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3571 ip4_address_t * out_addr, u16 out_port,
3572 ip4_address_t * eh_addr, u16 eh_port,
3573 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3574 u32 fib_index, u16 flags, u32 thread_index)
3576 snat_main_t *sm = &snat_main;
3577 snat_session_key_t key;
3580 clib_bihash_kv_16_8_t kv;
3581 f64 now = vlib_time_now (sm->vlib_main);
3582 nat_outside_fib_t *outside_fib;
3583 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3584 snat_main_per_thread_data_t *tsm;
3585 fib_prefix_t pfx = {
3586 .fp_proto = FIB_PROTOCOL_IP4,
3589 .ip4.as_u32 = eh_addr->as_u32,
3593 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3595 key.addr.as_u32 = out_addr->as_u32;
3596 key.port = out_port;
3597 key.protocol = proto;
3599 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3601 if (nat_set_outside_address_and_port
3602 (sm->addresses, thread_index, &key))
3606 key.addr.as_u32 = ehn_addr->as_u32;
3607 key.port = ehn_port;
3608 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3610 if (nat_set_outside_address_and_port
3611 (sm->twice_nat_addresses, thread_index, &key))
3615 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3619 s = nat_ed_session_alloc (sm, u, thread_index, now);
3623 s->last_heard = now;
3625 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3626 s->ext_host_nat_port = s->ext_host_port = eh_port;
3627 if (is_twice_nat_session (s))
3629 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3630 s->ext_host_nat_port = ehn_port;
3632 user_session_increment (sm, u, snat_is_session_static (s));
3633 switch (vec_len (sm->outside_fibs))
3636 key.fib_index = sm->outside_fib_index;
3639 key.fib_index = sm->outside_fibs[0].fib_index;
3643 vec_foreach (outside_fib, sm->outside_fibs)
3645 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3646 if (FIB_NODE_INDEX_INVALID != fei)
3648 if (fib_entry_get_resolving_interface (fei) != ~0)
3650 key.fib_index = outside_fib->fib_index;
3658 key.addr.as_u32 = out_addr->as_u32;
3659 key.port = out_port;
3661 kv.value = s - tsm->sessions;
3663 key.addr.as_u32 = in_addr->as_u32;
3665 key.fib_index = fib_index;
3668 make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
3669 snat_proto_to_ip_proto (proto), fib_index, in_port,
3670 s->ext_host_nat_port);
3671 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3672 nat_elog_warn ("in2out key add failed");
3674 make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3675 s->out2in.fib_index, out_port, eh_port);
3676 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3677 nat_elog_warn ("out2in key add failed");
3681 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3682 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3683 u32 fib_index, u32 ti)
3685 snat_main_t *sm = &snat_main;
3686 nat_ed_ses_key_t key;
3687 clib_bihash_kv_16_8_t kv, value;
3690 snat_main_per_thread_data_t *tsm;
3692 if (sm->num_workers > 1)
3694 sm->first_worker_index +
3695 (sm->workers[(clib_net_to_host_u16 (out_port) -
3696 1024) / sm->port_per_thread]);
3698 thread_index = sm->num_workers;
3699 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3701 key.l_addr.as_u32 = out_addr->as_u32;
3702 key.l_port = out_port;
3703 key.r_addr.as_u32 = eh_addr->as_u32;
3704 key.r_port = eh_port;
3706 key.fib_index = fib_index;
3707 kv.key[0] = key.as_u64[0];
3708 kv.key[1] = key.as_u64[1];
3709 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3712 s = pool_elt_at_index (tsm->sessions, value.value);
3713 nat_free_session_data (sm, s, thread_index, 1);
3714 nat44_delete_session (sm, s, thread_index);
3718 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3719 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3720 u32 fib_index, u32 total_pkts, u64 total_bytes,
3723 snat_main_t *sm = &snat_main;
3724 nat_ed_ses_key_t key;
3725 clib_bihash_kv_16_8_t kv, value;
3727 snat_main_per_thread_data_t *tsm;
3729 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3731 key.l_addr.as_u32 = out_addr->as_u32;
3732 key.l_port = out_port;
3733 key.r_addr.as_u32 = eh_addr->as_u32;
3734 key.r_port = eh_port;
3736 key.fib_index = fib_index;
3737 kv.key[0] = key.as_u64[0];
3738 kv.key[1] = key.as_u64[1];
3739 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3742 s = pool_elt_at_index (tsm->sessions, value.value);
3743 s->total_pkts = total_pkts;
3744 s->total_bytes = total_bytes;
3747 static clib_error_t *
3748 snat_config (vlib_main_t * vm, unformat_input_t * input)
3750 snat_main_t *sm = &snat_main;
3751 nat66_main_t *nm = &nat66_main;
3752 u32 translation_buckets = 1024;
3753 u32 translation_memory_size = 128 << 20;
3754 u32 user_buckets = 128;
3755 u32 user_memory_size = 64 << 20;
3756 u32 max_translations_per_user = 100;
3757 u32 outside_vrf_id = 0;
3758 u32 outside_ip6_vrf_id = 0;
3759 u32 inside_vrf_id = 0;
3760 u32 static_mapping_buckets = 1024;
3761 u32 static_mapping_memory_size = 64 << 20;
3762 u32 nat64_bib_buckets = 1024;
3763 u32 nat64_bib_memory_size = 128 << 20;
3764 u32 nat64_st_buckets = 2048;
3765 u32 nat64_st_memory_size = 256 << 20;
3766 u8 static_mapping_only = 0;
3767 u8 static_mapping_connection_tracking = 0;
3768 snat_main_per_thread_data_t *tsm;
3769 dslite_main_t *dm = &dslite_main;
3771 sm->deterministic = 0;
3773 sm->endpoint_dependent = 0;
3775 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3778 (input, "translation hash buckets %d", &translation_buckets))
3780 else if (unformat (input, "translation hash memory %d",
3781 &translation_memory_size));
3782 else if (unformat (input, "user hash buckets %d", &user_buckets))
3784 else if (unformat (input, "user hash memory %d", &user_memory_size))
3786 else if (unformat (input, "max translations per user %d",
3787 &max_translations_per_user))
3789 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3791 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3793 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3795 else if (unformat (input, "static mapping only"))
3797 static_mapping_only = 1;
3798 if (unformat (input, "connection tracking"))
3799 static_mapping_connection_tracking = 1;
3801 else if (unformat (input, "deterministic"))
3802 sm->deterministic = 1;
3803 else if (unformat (input, "nat64 bib hash buckets %d",
3804 &nat64_bib_buckets))
3806 else if (unformat (input, "nat64 bib hash memory %d",
3807 &nat64_bib_memory_size))
3810 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3812 else if (unformat (input, "nat64 st hash memory %d",
3813 &nat64_st_memory_size))
3815 else if (unformat (input, "out2in dpo"))
3817 else if (unformat (input, "dslite ce"))
3818 dslite_set_ce (dm, 1);
3819 else if (unformat (input, "endpoint-dependent"))
3820 sm->endpoint_dependent = 1;
3822 return clib_error_return (0, "unknown input '%U'",
3823 format_unformat_error, input);
3826 if (sm->deterministic && sm->endpoint_dependent)
3827 return clib_error_return (0,
3828 "deterministic and endpoint-dependent modes are mutually exclusive");
3830 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
3831 return clib_error_return (0,
3832 "static mapping only mode available only for simple nat");
3834 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
3835 return clib_error_return (0,
3836 "out2in dpo mode available only for simple nat");
3838 /* for show commands, etc. */
3839 sm->translation_buckets = translation_buckets;
3840 sm->translation_memory_size = translation_memory_size;
3841 /* do not exceed load factor 10 */
3842 sm->max_translations = 10 * translation_buckets;
3843 sm->user_buckets = user_buckets;
3844 sm->user_memory_size = user_memory_size;
3845 sm->max_translations_per_user = max_translations_per_user;
3846 sm->outside_vrf_id = outside_vrf_id;
3847 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
3850 nm->outside_vrf_id = outside_ip6_vrf_id;
3851 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
3854 sm->inside_vrf_id = inside_vrf_id;
3855 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
3858 sm->static_mapping_only = static_mapping_only;
3859 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
3861 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
3862 nat64_st_memory_size);
3864 if (sm->deterministic)
3866 sm->in2out_node_index = snat_det_in2out_node.index;
3867 sm->in2out_output_node_index = ~0;
3868 sm->out2in_node_index = snat_det_out2in_node.index;
3869 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
3870 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
3874 if (sm->endpoint_dependent)
3876 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
3877 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
3879 sm->handoff_out2in_index = nat_pre_out2in_node.index;
3880 sm->handoff_in2out_index = nat_pre_in2out_node.index;
3882 sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
3884 sm->in2out_node_index = nat44_ed_in2out_node.index;
3885 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
3886 sm->out2in_node_index = nat44_ed_out2in_node.index;
3888 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
3889 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
3890 nat_affinity_init (vm);
3891 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
3896 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
3897 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
3899 sm->handoff_out2in_index = snat_in2out_node.index;
3900 sm->handoff_in2out_index = snat_out2in_node.index;
3902 sm->handoff_in2out_output_index = snat_in2out_output_node.index;
3904 sm->in2out_node_index = snat_in2out_node.index;
3905 sm->in2out_output_node_index = snat_in2out_output_node.index;
3906 sm->out2in_node_index = snat_out2in_node.index;
3907 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
3908 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
3909 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
3911 if (!static_mapping_only ||
3912 (static_mapping_only && static_mapping_connection_tracking))
3915 vec_foreach (tsm, sm->per_thread_data)
3917 if (sm->endpoint_dependent)
3919 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3920 translation_buckets,
3921 translation_memory_size);
3922 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3923 format_ed_session_kvp);
3925 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3926 translation_buckets,
3927 translation_memory_size);
3928 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3929 format_ed_session_kvp);
3933 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3934 translation_buckets,
3935 translation_memory_size);
3936 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
3937 format_session_kvp);
3939 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3940 translation_buckets,
3941 translation_memory_size);
3942 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
3943 format_session_kvp);
3946 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3948 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
3956 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
3957 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
3959 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3960 "static_mapping_by_local", static_mapping_buckets,
3961 static_mapping_memory_size);
3962 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
3963 format_static_mapping_kvp);
3965 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3966 "static_mapping_by_external",
3967 static_mapping_buckets,
3968 static_mapping_memory_size);
3969 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
3970 format_static_mapping_kvp);
3976 VLIB_CONFIG_FUNCTION (snat_config, "nat");
3979 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
3982 ip4_address_t * address,
3984 u32 if_address_index, u32 is_delete)
3986 snat_main_t *sm = &snat_main;
3987 snat_static_map_resolve_t *rp;
3988 snat_static_mapping_t *m;
3989 snat_session_key_t m_key;
3990 clib_bihash_kv_8_8_t kv, value;
3992 ip4_address_t l_addr;
3994 for (i = 0; i < vec_len (sm->to_resolve); i++)
3996 rp = sm->to_resolve + i;
3997 if (rp->addr_only == 0)
3999 if (rp->sw_if_index == sw_if_index)
4006 m_key.addr.as_u32 = address->as_u32;
4007 m_key.port = rp->addr_only ? 0 : rp->e_port;
4008 m_key.protocol = rp->addr_only ? 0 : rp->proto;
4009 m_key.fib_index = sm->outside_fib_index;
4010 kv.key = m_key.as_u64;
4011 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4014 m = pool_elt_at_index (sm->static_mappings, value.value);
4018 /* Don't trip over lease renewal, static config */
4028 /* Indetity mapping? */
4029 if (rp->l_addr.as_u32 == 0)
4030 l_addr.as_u32 = address[0].as_u32;
4032 l_addr.as_u32 = rp->l_addr.as_u32;
4033 /* Add the static mapping */
4034 rv = snat_add_static_mapping (l_addr,
4039 rp->addr_only, ~0 /* sw_if_index */ ,
4040 rp->proto, !is_delete, rp->twice_nat,
4041 rp->out2in_only, rp->tag, rp->identity_nat);
4043 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4047 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4050 ip4_address_t * address,
4052 u32 if_address_index, u32 is_delete)
4054 snat_main_t *sm = &snat_main;
4055 snat_static_map_resolve_t *rp;
4056 ip4_address_t l_addr;
4060 snat_address_t *addresses = sm->addresses;
4062 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4064 if (sw_if_index == sm->auto_add_sw_if_indices[i])
4068 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4071 addresses = sm->twice_nat_addresses;
4072 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4081 /* Don't trip over lease renewal, static config */
4082 for (j = 0; j < vec_len (addresses); j++)
4083 if (addresses[j].addr.as_u32 == address->as_u32)
4086 (void) snat_add_address (sm, address, ~0, twice_nat);
4087 /* Scan static map resolution vector */
4088 for (j = 0; j < vec_len (sm->to_resolve); j++)
4090 rp = sm->to_resolve + j;
4093 /* On this interface? */
4094 if (rp->sw_if_index == sw_if_index)
4096 /* Indetity mapping? */
4097 if (rp->l_addr.as_u32 == 0)
4098 l_addr.as_u32 = address[0].as_u32;
4100 l_addr.as_u32 = rp->l_addr.as_u32;
4101 /* Add the static mapping */
4102 rv = snat_add_static_mapping (l_addr,
4108 ~0 /* sw_if_index */ ,
4110 rp->is_add, rp->twice_nat,
4111 rp->out2in_only, rp->tag,
4114 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4122 (void) snat_del_address (sm, address[0], 1, twice_nat);
4129 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4132 ip4_main_t *ip4_main = sm->ip4_main;
4133 ip4_address_t *first_int_addr;
4134 snat_static_map_resolve_t *rp;
4135 u32 *indices_to_delete = 0;
4137 u32 *auto_add_sw_if_indices =
4139 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4141 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4144 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4146 if (auto_add_sw_if_indices[i] == sw_if_index)
4150 /* if have address remove it */
4152 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4155 for (j = 0; j < vec_len (sm->to_resolve); j++)
4157 rp = sm->to_resolve + j;
4158 if (rp->sw_if_index == sw_if_index)
4159 vec_add1 (indices_to_delete, j);
4161 if (vec_len (indices_to_delete))
4163 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4164 vec_del1 (sm->to_resolve, j);
4165 vec_free (indices_to_delete);
4169 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4171 vec_del1 (sm->auto_add_sw_if_indices, i);
4174 return VNET_API_ERROR_VALUE_EXIST;
4181 return VNET_API_ERROR_NO_SUCH_ENTRY;
4183 /* add to the auto-address list */
4185 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4187 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4189 /* If the address is already bound - or static - add it now */
4191 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4197 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4198 snat_protocol_t proto, u32 vrf_id, int is_in)
4200 snat_main_per_thread_data_t *tsm;
4201 clib_bihash_kv_8_8_t kv, value;
4203 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4204 snat_session_key_t key;
4206 clib_bihash_8_8_t *t;
4208 if (sm->endpoint_dependent)
4209 return VNET_API_ERROR_UNSUPPORTED;
4211 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4212 if (sm->num_workers > 1)
4214 vec_elt_at_index (sm->per_thread_data,
4215 sm->worker_in2out_cb (&ip, fib_index, 0));
4217 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4219 key.addr.as_u32 = addr->as_u32;
4220 key.port = clib_host_to_net_u16 (port);
4221 key.protocol = proto;
4222 key.fib_index = fib_index;
4223 kv.key = key.as_u64;
4224 t = is_in ? &tsm->in2out : &tsm->out2in;
4225 if (!clib_bihash_search_8_8 (t, &kv, &value))
4227 if (pool_is_free_index (tsm->sessions, value.value))
4228 return VNET_API_ERROR_UNSPECIFIED;
4230 s = pool_elt_at_index (tsm->sessions, value.value);
4231 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4232 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4236 return VNET_API_ERROR_NO_SUCH_ENTRY;
4240 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4241 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4242 u32 vrf_id, int is_in)
4245 clib_bihash_16_8_t *t;
4246 nat_ed_ses_key_t key;
4247 clib_bihash_kv_16_8_t kv, value;
4248 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4250 snat_main_per_thread_data_t *tsm;
4252 if (!sm->endpoint_dependent)
4253 return VNET_API_ERROR_FEATURE_DISABLED;
4255 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4256 if (sm->num_workers > 1)
4258 vec_elt_at_index (sm->per_thread_data,
4259 sm->worker_in2out_cb (&ip, fib_index, 0));
4261 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4263 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4264 key.l_addr.as_u32 = addr->as_u32;
4265 key.r_addr.as_u32 = eh_addr->as_u32;
4266 key.l_port = clib_host_to_net_u16 (port);
4267 key.r_port = clib_host_to_net_u16 (eh_port);
4269 key.fib_index = fib_index;
4270 kv.key[0] = key.as_u64[0];
4271 kv.key[1] = key.as_u64[1];
4272 if (clib_bihash_search_16_8 (t, &kv, &value))
4273 return VNET_API_ERROR_NO_SUCH_ENTRY;
4275 if (pool_is_free_index (tsm->sessions, value.value))
4276 return VNET_API_ERROR_UNSPECIFIED;
4277 s = pool_elt_at_index (tsm->sessions, value.value);
4278 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4279 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4284 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4286 snat_main_t *sm = &snat_main;
4288 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4289 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4291 sm->psid_offset = psid_offset;
4292 sm->psid_length = psid_length;
4296 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4298 snat_main_t *sm = &snat_main;
4300 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4301 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4302 sm->start_port = start_port;
4303 sm->end_port = end_port;
4307 nat_set_alloc_addr_and_port_default (void)
4309 snat_main_t *sm = &snat_main;
4311 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4312 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4315 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4316 vlib_node_runtime_t * node,
4317 vlib_frame_t * frame)
4323 VLIB_REGISTER_NODE (nat_default_node) = {
4324 .name = "nat-default",
4325 .vector_size = sizeof (u32),
4327 .type = VLIB_NODE_TYPE_INTERNAL,
4329 .n_next_nodes = NAT_N_NEXT,
4331 [NAT_NEXT_DROP] = "error-drop",
4332 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4333 [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4334 [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4335 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4336 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4337 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4338 [NAT_NEXT_IN2OUT_ED_REASS] = "nat44-ed-in2out-reass",
4339 [NAT_NEXT_IN2OUT_ED_OUTPUT_REASS] = "nat44-ed-in2out-reass-output",
4340 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4341 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4342 [NAT_NEXT_OUT2IN_ED_REASS] = "nat44-ed-out2in-reass",
4348 * fd.io coding-style-patch-verification: ON
4351 * eval: (c-set-style "gnu")