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 <vnet/fib/fib_table.h>
34 #include <vnet/fib/ip4_fib.h>
36 #include <vpp/app/version.h>
38 snat_main_t snat_main;
42 /* Hook up input features */
43 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
44 .arc_name = "ip4-unicast",
45 .node_name = "nat44-in2out",
46 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
48 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
49 .arc_name = "ip4-unicast",
50 .node_name = "nat44-out2in",
51 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
52 "ip4-dhcp-client-detect"),
54 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
55 .arc_name = "ip4-unicast",
56 .node_name = "nat44-classify",
57 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
59 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
60 .arc_name = "ip4-unicast",
61 .node_name = "nat44-det-in2out",
62 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
64 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
65 .arc_name = "ip4-unicast",
66 .node_name = "nat44-det-out2in",
67 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
68 "ip4-dhcp-client-detect"),
70 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
71 .arc_name = "ip4-unicast",
72 .node_name = "nat44-det-classify",
73 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
75 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
76 .arc_name = "ip4-unicast",
77 .node_name = "nat44-ed-in2out",
78 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
80 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
81 .arc_name = "ip4-unicast",
82 .node_name = "nat44-ed-out2in",
83 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
84 "ip4-dhcp-client-detect"),
86 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
87 .arc_name = "ip4-unicast",
88 .node_name = "nat44-ed-classify",
89 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
91 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
92 .arc_name = "ip4-unicast",
93 .node_name = "nat44-in2out-worker-handoff",
94 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
96 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
97 .arc_name = "ip4-unicast",
98 .node_name = "nat44-out2in-worker-handoff",
99 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
100 "ip4-dhcp-client-detect"),
102 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
103 .arc_name = "ip4-unicast",
104 .node_name = "nat44-handoff-classify",
105 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
107 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
108 .arc_name = "ip4-unicast",
109 .node_name = "nat44-in2out-fast",
110 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
112 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
113 .arc_name = "ip4-unicast",
114 .node_name = "nat44-out2in-fast",
115 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
116 "ip4-dhcp-client-detect"),
118 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
119 .arc_name = "ip4-unicast",
120 .node_name = "nat44-hairpin-dst",
121 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
123 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
124 .arc_name = "ip4-unicast",
125 .node_name = "nat44-ed-hairpin-dst",
126 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
129 /* Hook up output features */
130 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
131 .arc_name = "ip4-output",
132 .node_name = "nat44-in2out-output",
133 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
135 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
136 .arc_name = "ip4-output",
137 .node_name = "nat44-in2out-output-worker-handoff",
138 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
140 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
141 .arc_name = "ip4-output",
142 .node_name = "nat44-hairpin-src",
143 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
145 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
146 .arc_name = "ip4-output",
147 .node_name = "nat44-ed-in2out-output",
148 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
150 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
151 .arc_name = "ip4-output",
152 .node_name = "nat44-ed-hairpin-src",
153 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
156 /* Hook up ip4-local features */
157 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
159 .arc_name = "ip4-local",
160 .node_name = "nat44-hairpinning",
161 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
163 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
165 .arc_name = "ip4-local",
166 .node_name = "nat44-ed-hairpinning",
167 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
171 VLIB_PLUGIN_REGISTER () = {
172 .version = VPP_BUILD_VER,
173 .description = "Network Address Translation",
178 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
180 snat_session_key_t key;
181 clib_bihash_kv_8_8_t kv;
182 nat_ed_ses_key_t ed_key;
183 clib_bihash_kv_16_8_t ed_kv;
184 snat_main_per_thread_data_t *tsm =
185 vec_elt_at_index (sm->per_thread_data, thread_index);
187 if (is_fwd_bypass_session (s))
189 ed_key.l_addr = s->in2out.addr;
190 ed_key.r_addr = s->ext_host_addr;
191 ed_key.l_port = s->in2out.port;
192 ed_key.r_port = s->ext_host_port;
193 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
194 ed_key.fib_index = 0;
195 ed_kv.key[0] = ed_key.as_u64[0];
196 ed_kv.key[1] = ed_key.as_u64[1];
197 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
198 nat_log_warn ("in2out_ed key del failed");
202 /* session lookup tables */
203 if (is_ed_session (s))
205 if (is_affinity_sessions (s))
206 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
207 s->in2out.protocol, s->out2in.port);
208 ed_key.l_addr = s->out2in.addr;
209 ed_key.r_addr = s->ext_host_addr;
210 ed_key.fib_index = s->out2in.fib_index;
211 if (snat_is_unk_proto_session (s))
213 ed_key.proto = s->in2out.port;
219 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
220 ed_key.l_port = s->out2in.port;
221 ed_key.r_port = s->ext_host_port;
223 ed_kv.key[0] = ed_key.as_u64[0];
224 ed_kv.key[1] = ed_key.as_u64[1];
225 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
226 nat_log_warn ("out2in_ed key del failed");
227 ed_key.l_addr = s->in2out.addr;
228 ed_key.fib_index = s->in2out.fib_index;
229 if (!snat_is_unk_proto_session (s))
230 ed_key.l_port = s->in2out.port;
231 if (is_twice_nat_session (s))
233 ed_key.r_addr = s->ext_host_nat_addr;
234 ed_key.r_port = s->ext_host_nat_port;
236 ed_kv.key[0] = ed_key.as_u64[0];
237 ed_kv.key[1] = ed_key.as_u64[1];
238 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
239 nat_log_warn ("in2out_ed key del failed");
241 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
242 &s->in2out.addr, s->in2out.port,
243 &s->ext_host_nat_addr, s->ext_host_nat_port,
244 &s->out2in.addr, s->out2in.port,
245 &s->ext_host_addr, s->ext_host_port,
246 s->in2out.protocol, is_twice_nat_session (s));
250 kv.key = s->in2out.as_u64;
251 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
252 nat_log_warn ("in2out key del failed");
253 kv.key = s->out2in.as_u64;
254 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
255 nat_log_warn ("out2in key del failed");
257 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
258 &s->in2out.addr, s->in2out.port,
259 &s->out2in.addr, s->out2in.port,
263 if (snat_is_unk_proto_session (s))
267 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
268 s->out2in.addr.as_u32,
271 s->out2in.port, s->in2out.fib_index);
273 /* Twice NAT address and port for external host */
274 if (is_twice_nat_session (s))
276 key.protocol = s->in2out.protocol;
277 key.port = s->ext_host_nat_port;
278 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
279 snat_free_outside_address_and_port (sm->twice_nat_addresses,
283 if (snat_is_session_static (s))
286 snat_free_outside_address_and_port (sm->addresses, thread_index,
291 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
295 snat_user_key_t user_key;
296 clib_bihash_kv_8_8_t kv, value;
297 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
298 dlist_elt_t *per_user_list_head_elt;
300 user_key.addr.as_u32 = addr->as_u32;
301 user_key.fib_index = fib_index;
302 kv.key = user_key.as_u64;
304 /* Ever heard of the "user" = src ip4 address before? */
305 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
307 /* no, make a new one */
308 pool_get (tsm->users, u);
309 clib_memset (u, 0, sizeof (*u));
310 u->addr.as_u32 = addr->as_u32;
311 u->fib_index = fib_index;
313 pool_get (tsm->list_pool, per_user_list_head_elt);
315 u->sessions_per_user_list_head_index = per_user_list_head_elt -
318 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
320 kv.value = u - tsm->users;
323 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
324 nat_log_warn ("user_hash keay add failed");
328 u = pool_elt_at_index (tsm->users, value.value);
335 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
339 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
340 u32 oldest_per_user_translation_list_index, session_index;
341 dlist_elt_t *oldest_per_user_translation_list_elt;
342 dlist_elt_t *per_user_translation_list_elt;
344 /* Over quota? Recycle the least recently used translation */
345 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
347 oldest_per_user_translation_list_index =
348 clib_dlist_remove_head (tsm->list_pool,
349 u->sessions_per_user_list_head_index);
351 ASSERT (oldest_per_user_translation_list_index != ~0);
353 /* Add it back to the end of the LRU list */
354 clib_dlist_addtail (tsm->list_pool,
355 u->sessions_per_user_list_head_index,
356 oldest_per_user_translation_list_index);
357 /* Get the list element */
358 oldest_per_user_translation_list_elt =
359 pool_elt_at_index (tsm->list_pool,
360 oldest_per_user_translation_list_index);
362 /* Get the session index from the list element */
363 session_index = oldest_per_user_translation_list_elt->value;
365 /* Get the session */
366 s = pool_elt_at_index (tsm->sessions, session_index);
367 nat_free_session_data (sm, s, thread_index);
368 if (snat_is_session_static (s))
369 u->nstaticsessions--;
376 s->ext_host_addr.as_u32 = 0;
377 s->ext_host_port = 0;
378 s->ext_host_nat_addr.as_u32 = 0;
379 s->ext_host_nat_port = 0;
383 pool_get (tsm->sessions, s);
384 clib_memset (s, 0, sizeof (*s));
386 /* Create list elts */
387 pool_get (tsm->list_pool, per_user_translation_list_elt);
388 clib_dlist_init (tsm->list_pool,
389 per_user_translation_list_elt - tsm->list_pool);
391 per_user_translation_list_elt->value = s - tsm->sessions;
392 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
393 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
395 clib_dlist_addtail (tsm->list_pool,
396 s->per_user_list_head_index,
397 per_user_translation_list_elt - tsm->list_pool);
399 s->user_index = u - tsm->users;
406 nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
410 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
411 dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
413 u64 sess_timeout_time;
415 if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
419 clib_dlist_remove_head (tsm->list_pool,
420 u->sessions_per_user_list_head_index);
421 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
422 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
423 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
424 if (now >= sess_timeout_time)
426 clib_dlist_addtail (tsm->list_pool,
427 u->sessions_per_user_list_head_index, oldest_index);
428 nat_free_session_data (sm, s, thread_index);
429 if (snat_is_session_static (s))
430 u->nstaticsessions--;
437 s->ext_host_addr.as_u32 = 0;
438 s->ext_host_port = 0;
439 s->ext_host_nat_addr.as_u32 = 0;
440 s->ext_host_nat_port = 0;
444 clib_dlist_addhead (tsm->list_pool,
445 u->sessions_per_user_list_head_index, oldest_index);
446 if ((u->nsessions + u->nstaticsessions) >=
447 sm->max_translations_per_user)
449 nat_log_warn ("max translations per user %U", format_ip4_address,
451 snat_ipfix_logging_max_entries_per_user
452 (sm->max_translations_per_user, u->addr.as_u32);
458 pool_get (tsm->sessions, s);
459 clib_memset (s, 0, sizeof (*s));
461 /* Create list elts */
462 pool_get (tsm->list_pool, per_user_translation_list_elt);
463 clib_dlist_init (tsm->list_pool,
464 per_user_translation_list_elt - tsm->list_pool);
466 per_user_translation_list_elt->value = s - tsm->sessions;
467 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
468 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
470 clib_dlist_addtail (tsm->list_pool,
471 s->per_user_list_head_index,
472 per_user_translation_list_elt - tsm->list_pool);
480 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
483 fib_prefix_t prefix = {
485 .fp_proto = FIB_PROTOCOL_IP4,
487 .ip4.as_u32 = addr->as_u32,
490 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
493 fib_table_entry_update_one_path (fib_index,
495 FIB_SOURCE_PLUGIN_LOW,
496 (FIB_ENTRY_FLAG_CONNECTED |
497 FIB_ENTRY_FLAG_LOCAL |
498 FIB_ENTRY_FLAG_EXCLUSIVE),
502 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
504 fib_table_entry_delete (fib_index, &prefix, FIB_SOURCE_PLUGIN_LOW);
508 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
513 vlib_thread_main_t *tm = vlib_get_thread_main ();
515 if (twice_nat && !sm->endpoint_dependent)
516 return VNET_API_ERROR_FEATURE_DISABLED;
518 /* Check if address already exists */
520 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
522 if (ap->addr.as_u32 == addr->as_u32)
523 return VNET_API_ERROR_VALUE_EXIST;
528 vec_add2 (sm->twice_nat_addresses, ap, 1);
530 vec_add2 (sm->addresses, ap, 1);
535 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
536 FIB_SOURCE_PLUGIN_LOW);
539 #define _(N, i, n, s) \
540 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
541 ap->busy_##n##_ports = 0; \
542 ap->busy_##n##_ports_per_thread = 0;\
543 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
544 foreach_snat_protocol
549 /* Add external address to FIB */
551 pool_foreach (i, sm->interfaces,
553 if (nat_interface_is_inside(i) || sm->out2in_dpo)
556 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
559 pool_foreach (i, sm->output_feature_interfaces,
561 if (nat_interface_is_inside(i) || sm->out2in_dpo)
564 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
573 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
575 snat_static_mapping_t *m;
577 pool_foreach (m, sm->static_mappings,
579 if (is_addr_only_static_mapping (m) ||
580 is_out2in_only_static_mapping (m) ||
581 is_identity_static_mapping (m))
583 if (m->external_addr.as_u32 == addr.as_u32)
592 increment_v4_address (ip4_address_t * a)
596 v = clib_net_to_host_u32 (a->as_u32) + 1;
597 a->as_u32 = clib_host_to_net_u32 (v);
601 snat_add_static_mapping_when_resolved (snat_main_t * sm,
602 ip4_address_t l_addr,
607 snat_protocol_t proto,
608 int addr_only, int is_add, u8 * tag,
609 int twice_nat, int out2in_only,
612 snat_static_map_resolve_t *rp;
614 vec_add2 (sm->to_resolve, rp, 1);
615 rp->l_addr.as_u32 = l_addr.as_u32;
617 rp->sw_if_index = sw_if_index;
621 rp->addr_only = addr_only;
623 rp->twice_nat = twice_nat;
624 rp->out2in_only = out2in_only;
625 rp->identity_nat = identity_nat;
626 rp->tag = vec_dup (tag);
630 get_thread_idx_by_port (u16 e_port)
632 snat_main_t *sm = &snat_main;
633 u32 thread_idx = sm->num_workers;
634 if (sm->num_workers > 1)
637 sm->first_worker_index +
638 sm->workers[(e_port - 1024) / sm->port_per_thread];
644 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
645 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
646 u32 sw_if_index, snat_protocol_t proto, int is_add,
647 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
650 snat_main_t *sm = &snat_main;
651 snat_static_mapping_t *m;
652 snat_session_key_t m_key;
653 clib_bihash_kv_8_8_t kv, value;
654 snat_address_t *a = 0;
656 snat_interface_t *interface;
658 snat_main_per_thread_data_t *tsm;
659 snat_user_key_t u_key;
661 dlist_elt_t *head, *elt;
662 u32 elt_index, head_index;
666 snat_static_map_resolve_t *rp, *rp_match = 0;
667 nat44_lb_addr_port_t *local;
670 if (!sm->endpoint_dependent)
672 if (twice_nat || out2in_only)
673 return VNET_API_ERROR_FEATURE_DISABLED;
676 /* If the external address is a specific interface address */
677 if (sw_if_index != ~0)
679 ip4_address_t *first_int_addr;
681 for (i = 0; i < vec_len (sm->to_resolve); i++)
683 rp = sm->to_resolve + i;
684 if (rp->sw_if_index != sw_if_index ||
685 rp->l_addr.as_u32 != l_addr.as_u32 ||
686 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
691 if (rp->l_port != l_port || rp->e_port != e_port
692 || rp->proto != proto)
700 /* Might be already set... */
701 first_int_addr = ip4_interface_first_address
702 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
707 return VNET_API_ERROR_VALUE_EXIST;
709 snat_add_static_mapping_when_resolved
710 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
711 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
713 /* DHCP resolution required? */
714 if (first_int_addr == 0)
720 e_addr.as_u32 = first_int_addr->as_u32;
721 /* Identity mapping? */
722 if (l_addr.as_u32 == 0)
723 l_addr.as_u32 = e_addr.as_u32;
729 return VNET_API_ERROR_NO_SUCH_ENTRY;
731 vec_del1 (sm->to_resolve, i);
735 e_addr.as_u32 = first_int_addr->as_u32;
736 /* Identity mapping? */
737 if (l_addr.as_u32 == 0)
738 l_addr.as_u32 = e_addr.as_u32;
746 m_key.port = addr_only ? 0 : e_port;
747 m_key.protocol = addr_only ? 0 : proto;
749 kv.key = m_key.as_u64;
750 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
753 m = pool_elt_at_index (sm->static_mappings, value.value);
759 if (is_identity_static_mapping (m))
762 vec_foreach (local, m->locals)
764 if (local->vrf_id == vrf_id)
765 return VNET_API_ERROR_VALUE_EXIST;
768 vec_add2 (m->locals, local, 1);
769 local->vrf_id = vrf_id;
771 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
772 FIB_SOURCE_PLUGIN_LOW);
773 m_key.addr = m->local_addr;
774 m_key.port = m->local_port;
775 m_key.protocol = m->proto;
776 m_key.fib_index = local->fib_index;
777 kv.key = m_key.as_u64;
778 kv.value = m - sm->static_mappings;
779 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
783 return VNET_API_ERROR_VALUE_EXIST;
786 if (twice_nat && addr_only)
787 return VNET_API_ERROR_UNSUPPORTED;
789 /* Convert VRF id to FIB index */
792 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
793 FIB_SOURCE_PLUGIN_LOW);
794 /* If not specified use inside VRF id from SNAT plugin startup config */
797 fib_index = sm->inside_fib_index;
798 vrf_id = sm->inside_vrf_id;
801 if (!(out2in_only || identity_nat))
804 m_key.port = addr_only ? 0 : l_port;
805 m_key.protocol = addr_only ? 0 : proto;
806 m_key.fib_index = fib_index;
807 kv.key = m_key.as_u64;
808 if (!clib_bihash_search_8_8
809 (&sm->static_mapping_by_local, &kv, &value))
810 return VNET_API_ERROR_VALUE_EXIST;
813 /* Find external address in allocated addresses and reserve port for
814 address and port pair mapping when dynamic translations enabled */
815 if (!(addr_only || sm->static_mapping_only || out2in_only))
817 for (i = 0; i < vec_len (sm->addresses); i++)
819 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
821 a = sm->addresses + i;
822 /* External port must be unused */
825 #define _(N, j, n, s) \
826 case SNAT_PROTOCOL_##N: \
827 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
828 return VNET_API_ERROR_INVALID_VALUE; \
829 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
832 a->busy_##n##_ports++; \
833 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
836 foreach_snat_protocol
839 nat_log_info ("unknown protocol");
840 return VNET_API_ERROR_INVALID_VALUE_2;
845 /* External address must be allocated */
846 if (!a && (l_addr.as_u32 != e_addr.as_u32))
848 if (sw_if_index != ~0)
850 for (i = 0; i < vec_len (sm->to_resolve); i++)
852 rp = sm->to_resolve + i;
855 if (rp->sw_if_index != sw_if_index &&
856 rp->l_addr.as_u32 != l_addr.as_u32 &&
857 rp->vrf_id != vrf_id && rp->l_port != l_port &&
858 rp->e_port != e_port && rp->proto != proto)
861 vec_del1 (sm->to_resolve, i);
865 return VNET_API_ERROR_NO_SUCH_ENTRY;
869 pool_get (sm->static_mappings, m);
870 clib_memset (m, 0, sizeof (*m));
871 m->tag = vec_dup (tag);
872 m->local_addr = l_addr;
873 m->external_addr = e_addr;
874 m->twice_nat = twice_nat;
876 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
878 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
881 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
882 vec_add2 (m->locals, local, 1);
883 local->vrf_id = vrf_id;
884 local->fib_index = fib_index;
889 m->fib_index = fib_index;
893 m->local_port = l_port;
894 m->external_port = e_port;
898 if (sm->num_workers > 1)
901 .src_address = m->local_addr,
903 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index));
904 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
907 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
909 m_key.addr = m->local_addr;
910 m_key.port = m->local_port;
911 m_key.protocol = m->proto;
912 m_key.fib_index = fib_index;
913 kv.key = m_key.as_u64;
914 kv.value = m - sm->static_mappings;
916 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
918 m_key.addr = m->external_addr;
919 m_key.port = m->external_port;
921 kv.key = m_key.as_u64;
922 kv.value = m - sm->static_mappings;
923 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
925 /* Delete dynamic sessions matching local address (+ local port) */
926 if (!(sm->static_mapping_only))
928 u_key.addr = m->local_addr;
929 u_key.fib_index = m->fib_index;
930 kv.key = u_key.as_u64;
931 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
933 user_index = value.value;
934 u = pool_elt_at_index (tsm->users, user_index);
937 head_index = u->sessions_per_user_list_head_index;
938 head = pool_elt_at_index (tsm->list_pool, head_index);
939 elt_index = head->next;
940 elt = pool_elt_at_index (tsm->list_pool, elt_index);
941 ses_index = elt->value;
942 while (ses_index != ~0)
944 s = pool_elt_at_index (tsm->sessions, ses_index);
945 elt = pool_elt_at_index (tsm->list_pool, elt->next);
946 ses_index = elt->value;
948 if (snat_is_session_static (s))
952 && (clib_net_to_host_u16 (s->in2out.port) !=
956 nat_free_session_data (sm, s,
957 tsm - sm->per_thread_data);
958 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
960 if (!addr_only && !sm->endpoint_dependent)
971 if (sw_if_index != ~0)
974 return VNET_API_ERROR_NO_SUCH_ENTRY;
980 vrf_id = sm->inside_vrf_id;
982 for (i = 0; i < vec_len (m->locals); i++)
984 if (m->locals[i].vrf_id == vrf_id)
991 return VNET_API_ERROR_NO_SUCH_ENTRY;
993 fib_index = m->locals[i].fib_index;
994 vec_del1 (m->locals, i);
997 fib_index = m->fib_index;
999 /* Free external address port */
1000 if (!(addr_only || sm->static_mapping_only || out2in_only))
1002 for (i = 0; i < vec_len (sm->addresses); i++)
1004 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1006 a = sm->addresses + i;
1009 #define _(N, j, n, s) \
1010 case SNAT_PROTOCOL_##N: \
1011 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1012 if (e_port > 1024) \
1014 a->busy_##n##_ports--; \
1015 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1018 foreach_snat_protocol
1021 nat_log_info ("unknown protocol");
1022 return VNET_API_ERROR_INVALID_VALUE_2;
1029 if (sm->num_workers > 1)
1030 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1032 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1034 m_key.addr = m->local_addr;
1035 m_key.port = m->local_port;
1036 m_key.protocol = m->proto;
1037 m_key.fib_index = fib_index;
1038 kv.key = m_key.as_u64;
1040 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1042 /* Delete session(s) for static mapping if exist */
1043 if (!(sm->static_mapping_only) ||
1044 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1046 u_key.addr = m->local_addr;
1047 u_key.fib_index = fib_index;
1048 kv.key = u_key.as_u64;
1049 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1051 user_index = value.value;
1052 u = pool_elt_at_index (tsm->users, user_index);
1053 if (u->nstaticsessions)
1055 head_index = u->sessions_per_user_list_head_index;
1056 head = pool_elt_at_index (tsm->list_pool, head_index);
1057 elt_index = head->next;
1058 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1059 ses_index = elt->value;
1060 while (ses_index != ~0)
1062 s = pool_elt_at_index (tsm->sessions, ses_index);
1063 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1064 ses_index = elt->value;
1068 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1069 (clib_net_to_host_u16 (s->out2in.port) !=
1074 if (is_lb_session (s))
1077 if (!snat_is_session_static (s))
1080 nat_free_session_data (sm, s,
1081 tsm - sm->per_thread_data);
1082 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1084 if (!addr_only && !sm->endpoint_dependent)
1091 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
1092 if (vec_len (m->locals))
1095 m_key.addr = m->external_addr;
1096 m_key.port = m->external_port;
1097 m_key.fib_index = 0;
1098 kv.key = m_key.as_u64;
1099 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1102 vec_free (m->workers);
1103 /* Delete static mapping from pool */
1104 pool_put (sm->static_mappings, m);
1107 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1110 /* Add/delete external address to FIB */
1112 pool_foreach (interface, sm->interfaces,
1114 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1117 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1120 pool_foreach (interface, sm->output_feature_interfaces,
1122 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1125 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1134 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1135 snat_protocol_t proto,
1136 nat44_lb_addr_port_t * locals, u8 is_add,
1137 twice_nat_type_t twice_nat, u8 out2in_only,
1138 u8 * tag, u32 affinity)
1140 snat_main_t *sm = &snat_main;
1141 snat_static_mapping_t *m;
1142 snat_session_key_t m_key;
1143 clib_bihash_kv_8_8_t kv, value;
1144 snat_address_t *a = 0;
1146 nat44_lb_addr_port_t *local;
1147 u32 elt_index, head_index, ses_index;
1148 snat_main_per_thread_data_t *tsm;
1149 snat_user_key_t u_key;
1152 dlist_elt_t *head, *elt;
1155 if (!sm->endpoint_dependent)
1156 return VNET_API_ERROR_FEATURE_DISABLED;
1158 m_key.addr = e_addr;
1159 m_key.port = e_port;
1160 m_key.protocol = proto;
1161 m_key.fib_index = 0;
1162 kv.key = m_key.as_u64;
1163 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1166 m = pool_elt_at_index (sm->static_mappings, value.value);
1171 return VNET_API_ERROR_VALUE_EXIST;
1173 if (vec_len (locals) < 2)
1174 return VNET_API_ERROR_INVALID_VALUE;
1176 /* Find external address in allocated addresses and reserve port for
1177 address and port pair mapping when dynamic translations enabled */
1178 if (!(sm->static_mapping_only || out2in_only))
1180 for (i = 0; i < vec_len (sm->addresses); i++)
1182 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1184 a = sm->addresses + i;
1185 /* External port must be unused */
1188 #define _(N, j, n, s) \
1189 case SNAT_PROTOCOL_##N: \
1190 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1191 return VNET_API_ERROR_INVALID_VALUE; \
1192 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1193 if (e_port > 1024) \
1195 a->busy_##n##_ports++; \
1196 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1199 foreach_snat_protocol
1202 nat_log_info ("unknown protocol");
1203 return VNET_API_ERROR_INVALID_VALUE_2;
1208 /* External address must be allocated */
1210 return VNET_API_ERROR_NO_SUCH_ENTRY;
1213 pool_get (sm->static_mappings, m);
1214 clib_memset (m, 0, sizeof (*m));
1215 m->tag = vec_dup (tag);
1216 m->external_addr = e_addr;
1217 m->external_port = e_port;
1219 m->twice_nat = twice_nat;
1220 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1222 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1223 m->affinity = affinity;
1226 m->affinity_per_service_list_head_index =
1227 nat_affinity_get_per_service_list_head_index ();
1229 m->affinity_per_service_list_head_index = ~0;
1231 m_key.addr = m->external_addr;
1232 m_key.port = m->external_port;
1233 m_key.protocol = m->proto;
1234 m_key.fib_index = 0;
1235 kv.key = m_key.as_u64;
1236 kv.value = m - sm->static_mappings;
1237 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1239 nat_log_err ("static_mapping_by_external key add failed");
1240 return VNET_API_ERROR_UNSPECIFIED;
1243 m_key.fib_index = m->fib_index;
1244 for (i = 0; i < vec_len (locals); i++)
1246 locals[i].fib_index =
1247 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1249 FIB_SOURCE_PLUGIN_LOW);
1250 m_key.addr = locals[i].addr;
1251 m_key.fib_index = locals[i].fib_index;
1254 m_key.port = locals[i].port;
1255 kv.key = m_key.as_u64;
1256 kv.value = m - sm->static_mappings;
1257 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1259 locals[i].prefix = (i == 0) ? locals[i].probability :
1260 (locals[i - 1].prefix + locals[i].probability);
1261 vec_add1 (m->locals, locals[i]);
1262 if (sm->num_workers > 1)
1265 .src_address = locals[i].addr,
1268 clib_bitmap_set (bitmap,
1269 sm->worker_in2out_cb (&ip, m->fib_index), 1);
1273 /* Assign workers */
1274 if (sm->num_workers > 1)
1277 clib_bitmap_foreach (i, bitmap,
1279 vec_add1(m->workers, i);
1287 return VNET_API_ERROR_NO_SUCH_ENTRY;
1289 if (!is_lb_static_mapping (m))
1290 return VNET_API_ERROR_INVALID_VALUE;
1292 /* Free external address port */
1293 if (!(sm->static_mapping_only || out2in_only))
1295 for (i = 0; i < vec_len (sm->addresses); i++)
1297 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1299 a = sm->addresses + i;
1302 #define _(N, j, n, s) \
1303 case SNAT_PROTOCOL_##N: \
1304 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1305 if (e_port > 1024) \
1307 a->busy_##n##_ports--; \
1308 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1311 foreach_snat_protocol
1314 nat_log_info ("unknown protocol");
1315 return VNET_API_ERROR_INVALID_VALUE_2;
1322 m_key.addr = m->external_addr;
1323 m_key.port = m->external_port;
1324 m_key.protocol = m->proto;
1325 m_key.fib_index = 0;
1326 kv.key = m_key.as_u64;
1327 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1329 nat_log_err ("static_mapping_by_external key del failed");
1330 return VNET_API_ERROR_UNSPECIFIED;
1334 vec_foreach (local, m->locals)
1336 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1337 FIB_SOURCE_PLUGIN_LOW);
1338 m_key.addr = local->addr;
1341 m_key.port = local->port;
1342 m_key.fib_index = local->fib_index;
1343 kv.key = m_key.as_u64;
1344 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1346 nat_log_err ("static_mapping_by_local key del failed");
1347 return VNET_API_ERROR_UNSPECIFIED;
1351 if (sm->num_workers > 1)
1354 .src_address = local->addr,
1356 tsm = vec_elt_at_index (sm->per_thread_data,
1357 sm->worker_in2out_cb (&ip, m->fib_index));
1360 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1362 /* Delete sessions */
1363 u_key.addr = local->addr;
1364 u_key.fib_index = m->fib_index;
1365 kv.key = u_key.as_u64;
1366 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1368 u = pool_elt_at_index (tsm->users, value.value);
1369 if (u->nstaticsessions)
1371 head_index = u->sessions_per_user_list_head_index;
1372 head = pool_elt_at_index (tsm->list_pool, head_index);
1373 elt_index = head->next;
1374 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1375 ses_index = elt->value;
1376 while (ses_index != ~0)
1378 s = pool_elt_at_index (tsm->sessions, ses_index);
1379 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1380 ses_index = elt->value;
1382 if (!(is_lb_session (s)))
1385 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1386 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1389 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1390 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1397 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1398 vec_free (m->locals);
1400 vec_free (m->workers);
1402 pool_put (sm->static_mappings, m);
1409 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1412 snat_address_t *a = 0;
1413 snat_session_t *ses;
1414 u32 *ses_to_be_removed = 0, *ses_index;
1415 snat_main_per_thread_data_t *tsm;
1416 snat_static_mapping_t *m;
1417 snat_interface_t *interface;
1419 snat_address_t *addresses =
1420 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1422 /* Find SNAT address */
1423 for (i = 0; i < vec_len (addresses); i++)
1425 if (addresses[i].addr.as_u32 == addr.as_u32)
1432 return VNET_API_ERROR_NO_SUCH_ENTRY;
1437 pool_foreach (m, sm->static_mappings,
1439 if (m->external_addr.as_u32 == addr.as_u32)
1440 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1441 m->local_port, m->external_port,
1442 m->vrf_id, is_addr_only_static_mapping(m), ~0,
1443 m->proto, 0, m->twice_nat,
1444 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1450 /* Check if address is used in some static mapping */
1451 if (is_snat_address_used_in_static_mapping (sm, addr))
1453 nat_log_notice ("address used in static mapping");
1454 return VNET_API_ERROR_UNSPECIFIED;
1458 if (a->fib_index != ~0)
1459 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
1461 /* Delete sessions using address */
1462 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1465 vec_foreach (tsm, sm->per_thread_data)
1467 pool_foreach (ses, tsm->sessions, ({
1468 if (ses->out2in.addr.as_u32 == addr.as_u32)
1470 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1471 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1475 vec_foreach (ses_index, ses_to_be_removed)
1477 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1478 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1481 vec_free (ses_to_be_removed);
1486 #define _(N, i, n, s) \
1487 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1488 vec_free (a->busy_##n##_ports_per_thread);
1489 foreach_snat_protocol
1493 vec_del1 (sm->twice_nat_addresses, i);
1497 vec_del1 (sm->addresses, i);
1499 /* Delete external address from FIB */
1501 pool_foreach (interface, sm->interfaces,
1503 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1506 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1509 pool_foreach (interface, sm->output_feature_interfaces,
1511 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1514 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1523 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1525 snat_main_t *sm = &snat_main;
1526 snat_interface_t *i;
1527 const char *feature_name, *del_feature_name;
1529 snat_static_mapping_t *m;
1531 nat_outside_fib_t *outside_fib;
1532 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1535 if (sm->out2in_dpo && !is_inside)
1536 return VNET_API_ERROR_UNSUPPORTED;
1539 pool_foreach (i, sm->output_feature_interfaces,
1541 if (i->sw_if_index == sw_if_index)
1542 return VNET_API_ERROR_VALUE_EXIST;
1546 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1547 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1550 if (sm->num_workers > 1 && !sm->deterministic)
1552 is_inside ? "nat44-in2out-worker-handoff" :
1553 "nat44-out2in-worker-handoff";
1554 else if (sm->deterministic)
1555 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1556 else if (sm->endpoint_dependent)
1557 feature_name = is_inside ? "nat44-ed-in2out" : "nat44-ed-out2in";
1559 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1562 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1563 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
1566 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1567 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
1573 vec_foreach (outside_fib, sm->outside_fibs)
1575 if (outside_fib->fib_index == fib_index)
1579 outside_fib->refcount--;
1580 if (!outside_fib->refcount)
1581 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1584 outside_fib->refcount++;
1591 vec_add2 (sm->outside_fibs, outside_fib, 1);
1592 outside_fib->refcount = 1;
1593 outside_fib->fib_index = fib_index;
1598 pool_foreach (i, sm->interfaces,
1600 if (i->sw_if_index == sw_if_index)
1604 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1607 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1609 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1611 if (sm->num_workers > 1 && !sm->deterministic)
1613 del_feature_name = "nat44-handoff-classify";
1614 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1615 "nat44-out2in-worker-handoff";
1617 else if (sm->deterministic)
1619 del_feature_name = "nat44-det-classify";
1620 feature_name = !is_inside ? "nat44-det-in2out" :
1623 else if (sm->endpoint_dependent)
1625 del_feature_name = "nat44-ed-classify";
1626 feature_name = !is_inside ? "nat44-ed-in2out" :
1631 del_feature_name = "nat44-classify";
1632 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1635 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1636 sw_if_index, 0, 0, 0);
1637 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1638 sw_if_index, 1, 0, 0);
1641 if (sm->endpoint_dependent)
1642 vnet_feature_enable_disable ("ip4-local",
1643 "nat44-ed-hairpinning",
1644 sw_if_index, 1, 0, 0);
1645 else if (!sm->deterministic)
1646 vnet_feature_enable_disable ("ip4-local",
1647 "nat44-hairpinning",
1648 sw_if_index, 1, 0, 0);
1653 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1654 sw_if_index, 0, 0, 0);
1655 pool_put (sm->interfaces, i);
1658 if (sm->endpoint_dependent)
1659 vnet_feature_enable_disable ("ip4-local",
1660 "nat44-ed-hairpinning",
1661 sw_if_index, 0, 0, 0);
1662 else if (!sm->deterministic)
1663 vnet_feature_enable_disable ("ip4-local",
1664 "nat44-hairpinning",
1665 sw_if_index, 0, 0, 0);
1671 if ((nat_interface_is_inside(i) && is_inside) ||
1672 (nat_interface_is_outside(i) && !is_inside))
1675 if (sm->num_workers > 1 && !sm->deterministic)
1677 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1678 "nat44-out2in-worker-handoff";
1679 feature_name = "nat44-handoff-classify";
1681 else if (sm->deterministic)
1683 del_feature_name = !is_inside ? "nat44-det-in2out" :
1685 feature_name = "nat44-det-classify";
1687 else if (sm->endpoint_dependent)
1689 del_feature_name = !is_inside ? "nat44-ed-in2out" :
1691 feature_name = "nat44-ed-classify";
1695 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1696 feature_name = "nat44-classify";
1699 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1700 sw_if_index, 0, 0, 0);
1701 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1702 sw_if_index, 1, 0, 0);
1705 if (sm->endpoint_dependent)
1706 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1707 sw_if_index, 0, 0, 0);
1708 else if (!sm->deterministic)
1709 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1710 sw_if_index, 0, 0, 0);
1721 return VNET_API_ERROR_NO_SUCH_ENTRY;
1723 pool_get (sm->interfaces, i);
1724 i->sw_if_index = sw_if_index;
1726 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1729 if (is_inside && !sm->out2in_dpo)
1731 if (sm->endpoint_dependent)
1732 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1733 sw_if_index, 1, 0, 0);
1734 else if (!sm->deterministic)
1735 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1736 sw_if_index, 1, 0, 0);
1742 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1746 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1748 /* Add/delete external addresses to FIB */
1751 vec_foreach (ap, sm->addresses)
1752 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1754 pool_foreach (m, sm->static_mappings,
1756 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1759 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1762 pool_foreach (dm, sm->det_maps,
1764 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1772 snat_interface_add_del_output_feature (u32 sw_if_index,
1773 u8 is_inside, int is_del)
1775 snat_main_t *sm = &snat_main;
1776 snat_interface_t *i;
1778 snat_static_mapping_t *m;
1780 if (sm->deterministic ||
1781 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1782 return VNET_API_ERROR_UNSUPPORTED;
1785 pool_foreach (i, sm->interfaces,
1787 if (i->sw_if_index == sw_if_index)
1788 return VNET_API_ERROR_VALUE_EXIST;
1794 if (sm->endpoint_dependent)
1796 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
1797 sw_if_index, !is_del, 0, 0);
1798 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
1799 sw_if_index, !is_del, 0, 0);
1803 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1804 sw_if_index, !is_del, 0, 0);
1805 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1806 sw_if_index, !is_del, 0, 0);
1811 if (sm->num_workers > 1)
1813 vnet_feature_enable_disable ("ip4-unicast",
1814 "nat44-out2in-worker-handoff",
1815 sw_if_index, !is_del, 0, 0);
1816 vnet_feature_enable_disable ("ip4-output",
1817 "nat44-in2out-output-worker-handoff",
1818 sw_if_index, !is_del, 0, 0);
1822 if (sm->endpoint_dependent)
1824 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
1825 sw_if_index, !is_del, 0, 0);
1826 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
1827 sw_if_index, !is_del, 0, 0);
1831 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
1832 sw_if_index, !is_del, 0, 0);
1833 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1834 sw_if_index, !is_del, 0, 0);
1839 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1840 sm->fq_in2out_output_index =
1841 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1843 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1844 sm->fq_out2in_index =
1845 vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1848 pool_foreach (i, sm->output_feature_interfaces,
1850 if (i->sw_if_index == sw_if_index)
1853 pool_put (sm->output_feature_interfaces, i);
1855 return VNET_API_ERROR_VALUE_EXIST;
1863 return VNET_API_ERROR_NO_SUCH_ENTRY;
1865 pool_get (sm->output_feature_interfaces, i);
1866 i->sw_if_index = sw_if_index;
1869 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1871 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1873 /* Add/delete external addresses to FIB */
1879 vec_foreach (ap, sm->addresses)
1880 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1882 pool_foreach (m, sm->static_mappings,
1884 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1887 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1895 snat_set_workers (uword * bitmap)
1897 snat_main_t *sm = &snat_main;
1900 if (sm->num_workers < 2)
1901 return VNET_API_ERROR_FEATURE_DISABLED;
1903 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1904 return VNET_API_ERROR_INVALID_WORKER;
1906 vec_free (sm->workers);
1908 clib_bitmap_foreach (i, bitmap,
1910 vec_add1(sm->workers, i);
1911 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1916 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1917 sm->num_snat_thread = _vec_len (sm->workers);
1924 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1927 ip4_address_t * address,
1929 u32 if_address_index, u32 is_delete);
1932 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
1935 ip4_address_t * address,
1937 u32 if_address_index, u32 is_delete);
1940 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1943 snat_session_key_t * k,
1944 u16 port_per_thread, u32 snat_thread_index);
1946 static clib_error_t *
1947 snat_init (vlib_main_t * vm)
1949 snat_main_t *sm = &snat_main;
1950 clib_error_t *error = 0;
1951 ip4_main_t *im = &ip4_main;
1952 ip_lookup_main_t *lm = &im->lookup_main;
1954 vlib_thread_registration_t *tr;
1955 vlib_thread_main_t *tm = vlib_get_thread_main ();
1958 ip4_add_del_interface_address_callback_t cb4;
1959 vlib_node_t *error_drop_node;
1962 sm->vnet_main = vnet_get_main ();
1964 sm->ip4_lookup_main = lm;
1965 sm->api_main = &api_main;
1966 sm->first_worker_index = 0;
1967 sm->num_workers = 0;
1968 sm->num_snat_thread = 1;
1970 sm->port_per_thread = 0xffff - 1024;
1971 sm->fq_in2out_index = ~0;
1972 sm->fq_out2in_index = ~0;
1973 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1974 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1975 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1976 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1977 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1978 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
1979 sm->forwarding_enabled = 0;
1980 sm->log_class = vlib_log_register_class ("nat", 0);
1981 error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
1982 sm->error_node_index = error_drop_node->index;
1983 sm->mss_clamping = 0;
1985 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1988 tr = (vlib_thread_registration_t *) p[0];
1991 sm->num_workers = tr->count;
1992 sm->first_worker_index = tr->first_index;
1996 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1998 /* Use all available workers by default */
1999 if (sm->num_workers > 1)
2001 for (i = 0; i < sm->num_workers; i++)
2002 bitmap = clib_bitmap_set (bitmap, i, 1);
2003 snat_set_workers (bitmap);
2004 clib_bitmap_free (bitmap);
2008 sm->per_thread_data[0].snat_thread_index = 0;
2011 error = snat_api_init (vm, sm);
2015 /* Set up the interface address add/del callback */
2016 cb4.function = snat_ip4_add_del_interface_address_cb;
2017 cb4.function_opaque = 0;
2019 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2021 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2022 cb4.function_opaque = 0;
2024 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2026 nat_dpo_module_init ();
2028 /* Init IPFIX logging */
2029 snat_ipfix_logging_init (vm);
2032 error = nat64_init (vm);
2040 /* Init virtual fragmenentation reassembly */
2041 return nat_reass_init (vm);
2044 VLIB_INIT_FUNCTION (snat_init);
2047 snat_free_outside_address_and_port (snat_address_t * addresses,
2048 u32 thread_index, snat_session_key_t * k)
2052 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2054 for (address_index = 0; address_index < vec_len (addresses);
2057 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2061 ASSERT (address_index < vec_len (addresses));
2063 a = addresses + address_index;
2065 switch (k->protocol)
2067 #define _(N, i, n, s) \
2068 case SNAT_PROTOCOL_##N: \
2069 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2070 port_host_byte_order) == 1); \
2071 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2072 port_host_byte_order, 0); \
2073 a->busy_##n##_ports--; \
2074 a->busy_##n##_ports_per_thread[thread_index]--; \
2076 foreach_snat_protocol
2079 nat_log_info ("unknown protocol");
2085 snat_static_mapping_match (snat_main_t * sm,
2086 snat_session_key_t match,
2087 snat_session_key_t * mapping,
2090 twice_nat_type_t * twice_nat,
2091 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2092 u8 * is_identity_nat)
2094 clib_bihash_kv_8_8_t kv, value;
2095 snat_static_mapping_t *m;
2096 snat_session_key_t m_key;
2097 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2098 u32 rand, lo = 0, hi, mid;
2101 m_key.fib_index = match.fib_index;
2104 mapping_hash = &sm->static_mapping_by_external;
2105 m_key.fib_index = 0;
2108 m_key.addr = match.addr;
2109 m_key.port = clib_net_to_host_u16 (match.port);
2110 m_key.protocol = match.protocol;
2112 kv.key = m_key.as_u64;
2114 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2116 /* Try address only mapping */
2119 kv.key = m_key.as_u64;
2120 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2124 m = pool_elt_at_index (sm->static_mappings, value.value);
2128 if (is_lb_static_mapping (m))
2130 if (PREDICT_FALSE (lb != 0))
2131 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2134 if (nat_affinity_find_and_lock (ext_host_addr[0], match.addr,
2135 match.protocol, match.port,
2139 mapping->addr = m->locals[backend_index].addr;
2141 clib_host_to_net_u16 (m->locals[backend_index].port);
2142 mapping->fib_index = m->locals[backend_index].fib_index;
2146 hi = vec_len (m->locals) - 1;
2147 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2150 mid = ((hi - lo) >> 1) + lo;
2151 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2153 if (!(m->locals[lo].prefix >= rand))
2155 if (PREDICT_FALSE (sm->num_workers > 1))
2158 .src_address = m->locals[lo].addr,
2160 if (sm->worker_in2out_cb (&ip, m->fib_index) !=
2161 vlib_get_thread_index ())
2164 mapping->addr = m->locals[lo].addr;
2165 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2166 mapping->fib_index = m->locals[lo].fib_index;
2169 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2170 match.protocol, match.port,
2172 m->affinity_per_service_list_head_index))
2173 nat_log_info ("create affinity record failed");
2178 if (PREDICT_FALSE (lb != 0))
2180 mapping->fib_index = m->fib_index;
2181 mapping->addr = m->local_addr;
2182 /* Address only mapping doesn't change port */
2183 mapping->port = is_addr_only_static_mapping (m) ? match.port
2184 : clib_host_to_net_u16 (m->local_port);
2186 mapping->protocol = m->proto;
2190 mapping->addr = m->external_addr;
2191 /* Address only mapping doesn't change port */
2192 mapping->port = is_addr_only_static_mapping (m) ? match.port
2193 : clib_host_to_net_u16 (m->external_port);
2194 mapping->fib_index = sm->outside_fib_index;
2198 if (PREDICT_FALSE (is_addr_only != 0))
2199 *is_addr_only = is_addr_only_static_mapping (m);
2201 if (PREDICT_FALSE (twice_nat != 0))
2202 *twice_nat = m->twice_nat;
2204 if (PREDICT_FALSE (is_identity_nat != 0))
2205 *is_identity_nat = is_identity_static_mapping (m);
2210 static_always_inline u16
2211 snat_random_port (u16 min, u16 max)
2213 snat_main_t *sm = &snat_main;
2214 return min + random_u32 (&sm->random_seed) /
2215 (random_u32_max () / (max - min + 1) + 1);
2219 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2222 snat_session_key_t * k,
2223 u16 port_per_thread,
2224 u32 snat_thread_index)
2226 snat_main_t *sm = &snat_main;
2228 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2229 port_per_thread, snat_thread_index);
2233 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2236 snat_session_key_t * k,
2237 u16 port_per_thread, u32 snat_thread_index)
2240 snat_address_t *a, *ga = 0;
2243 for (i = 0; i < vec_len (addresses); i++)
2246 switch (k->protocol)
2248 #define _(N, j, n, s) \
2249 case SNAT_PROTOCOL_##N: \
2250 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2252 if (a->fib_index == fib_index) \
2256 portnum = (port_per_thread * \
2257 snat_thread_index) + \
2258 snat_random_port(1, port_per_thread) + 1024; \
2259 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2261 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2262 a->busy_##n##_ports_per_thread[thread_index]++; \
2263 a->busy_##n##_ports++; \
2264 k->addr = a->addr; \
2265 k->port = clib_host_to_net_u16(portnum); \
2269 else if (a->fib_index == ~0) \
2275 foreach_snat_protocol
2278 nat_log_info ("unknown protocol");
2287 switch (k->protocol)
2289 #define _(N, j, n, s) \
2290 case SNAT_PROTOCOL_##N: \
2293 portnum = (port_per_thread * \
2294 snat_thread_index) + \
2295 snat_random_port(1, port_per_thread) + 1024; \
2296 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2298 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2299 a->busy_##n##_ports_per_thread[thread_index]++; \
2300 a->busy_##n##_ports++; \
2301 k->addr = a->addr; \
2302 k->port = clib_host_to_net_u16(portnum); \
2306 foreach_snat_protocol
2309 nat_log_info ("unknown protocol");
2314 /* Totally out of translations to use... */
2315 snat_ipfix_logging_addresses_exhausted (0);
2320 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2323 snat_session_key_t * k,
2324 u16 port_per_thread, u32 snat_thread_index)
2326 snat_main_t *sm = &snat_main;
2327 snat_address_t *a = addresses;
2328 u16 m, ports, portnum, A, j;
2329 m = 16 - (sm->psid_offset + sm->psid_length);
2330 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2332 if (!vec_len (addresses))
2335 switch (k->protocol)
2337 #define _(N, i, n, s) \
2338 case SNAT_PROTOCOL_##N: \
2339 if (a->busy_##n##_ports < ports) \
2343 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2344 j = snat_random_port(0, pow2_mask(m)); \
2345 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2346 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2348 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2349 a->busy_##n##_ports++; \
2350 k->addr = a->addr; \
2351 k->port = clib_host_to_net_u16 (portnum); \
2356 foreach_snat_protocol
2359 nat_log_info ("unknown protocol");
2364 /* Totally out of translations to use... */
2365 snat_ipfix_logging_addresses_exhausted (0);
2370 nat_alloc_addr_and_port_range (snat_address_t * addresses,
2373 snat_session_key_t * k,
2374 u16 port_per_thread, u32 snat_thread_index)
2376 snat_main_t *sm = &snat_main;
2377 snat_address_t *a = addresses;
2380 ports = sm->end_port - sm->start_port + 1;
2382 if (!vec_len (addresses))
2385 switch (k->protocol)
2387 #define _(N, i, n, s) \
2388 case SNAT_PROTOCOL_##N: \
2389 if (a->busy_##n##_ports < ports) \
2393 portnum = snat_random_port(sm->start_port, sm->end_port); \
2394 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2396 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2397 a->busy_##n##_ports++; \
2398 k->addr = a->addr; \
2399 k->port = clib_host_to_net_u16 (portnum); \
2404 foreach_snat_protocol
2407 nat_log_info ("unknown protocol");
2412 /* Totally out of translations to use... */
2413 snat_ipfix_logging_addresses_exhausted (0);
2418 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2420 dpo_id_t dpo_v4 = DPO_INVALID;
2421 fib_prefix_t pfx = {
2422 .fp_proto = FIB_PROTOCOL_IP4,
2424 .fp_addr.ip4.as_u32 = addr.as_u32,
2429 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2430 fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2431 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2432 dpo_reset (&dpo_v4);
2436 fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2441 format_session_kvp (u8 * s, va_list * args)
2443 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2444 snat_session_key_t k;
2448 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2454 format_static_mapping_kvp (u8 * s, va_list * args)
2456 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2457 snat_session_key_t k;
2461 s = format (s, "%U static-mapping-index %llu",
2462 format_static_mapping_key, &k, v->value);
2468 format_user_kvp (u8 * s, va_list * args)
2470 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2475 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2476 k.fib_index, v->value);
2482 format_ed_session_kvp (u8 * s, va_list * args)
2484 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2487 k.as_u64[0] = v->key[0];
2488 k.as_u64[1] = v->key[1];
2491 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2492 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2493 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2494 format_ip_protocol, k.proto, k.fib_index, v->value);
2500 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2502 snat_main_t *sm = &snat_main;
2503 u32 next_worker_index = 0;
2506 next_worker_index = sm->first_worker_index;
2507 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2508 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
2510 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2511 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2513 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2515 return next_worker_index;
2519 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2521 snat_main_t *sm = &snat_main;
2524 snat_session_key_t m_key;
2525 clib_bihash_kv_8_8_t kv, value;
2526 snat_static_mapping_t *m;
2528 u32 next_worker_index = 0;
2530 /* first try static mappings without port */
2531 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2533 m_key.addr = ip0->dst_address;
2536 m_key.fib_index = rx_fib_index0;
2537 kv.key = m_key.as_u64;
2538 if (!clib_bihash_search_8_8
2539 (&sm->static_mapping_by_external, &kv, &value))
2541 m = pool_elt_at_index (sm->static_mappings, value.value);
2542 return m->workers[0];
2546 proto = ip_proto_to_snat_proto (ip0->protocol);
2547 udp = ip4_next_header (ip0);
2548 port = udp->dst_port;
2550 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2552 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2553 return vlib_get_thread_index ();
2555 if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2557 nat_reass_ip4_t *reass;
2559 reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2560 ip0->fragment_id, ip0->protocol);
2562 if (reass && (reass->thread_index != (u32) ~ 0))
2563 return reass->thread_index;
2565 return vlib_get_thread_index ();
2569 /* unknown protocol */
2570 if (PREDICT_FALSE (proto == ~0))
2572 /* use current thread */
2573 return vlib_get_thread_index ();
2576 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2578 icmp46_header_t *icmp = (icmp46_header_t *) udp;
2579 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
2580 if (!icmp_is_error_message (icmp))
2581 port = echo->identifier;
2584 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2585 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2586 void *l4_header = ip4_next_header (inner_ip);
2589 case SNAT_PROTOCOL_ICMP:
2590 icmp = (icmp46_header_t *) l4_header;
2591 echo = (icmp_echo_header_t *) (icmp + 1);
2592 port = echo->identifier;
2594 case SNAT_PROTOCOL_UDP:
2595 case SNAT_PROTOCOL_TCP:
2596 port = ((tcp_udp_header_t *) l4_header)->src_port;
2599 return vlib_get_thread_index ();
2604 /* try static mappings with port */
2605 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2607 m_key.addr = ip0->dst_address;
2608 m_key.port = clib_net_to_host_u16 (port);
2609 m_key.protocol = proto;
2610 m_key.fib_index = rx_fib_index0;
2611 kv.key = m_key.as_u64;
2612 if (!clib_bihash_search_8_8
2613 (&sm->static_mapping_by_external, &kv, &value))
2615 m = pool_elt_at_index (sm->static_mappings, value.value);
2616 return m->workers[0];
2620 /* worker by outside port */
2621 next_worker_index = sm->first_worker_index;
2622 next_worker_index +=
2623 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2624 return next_worker_index;
2628 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2630 snat_main_t *sm = &snat_main;
2631 clib_bihash_kv_8_8_t kv, value;
2632 u32 proto, next_worker_index = 0;
2635 snat_static_mapping_t *m;
2638 /* first try static mappings without port */
2639 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2641 make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
2642 if (!clib_bihash_search_8_8
2643 (&sm->static_mapping_by_external, &kv, &value))
2645 m = pool_elt_at_index (sm->static_mappings, value.value);
2646 return m->workers[0];
2650 proto = ip_proto_to_snat_proto (ip->protocol);
2652 /* unknown protocol */
2653 if (PREDICT_FALSE (proto == ~0))
2655 /* use current thread */
2656 return vlib_get_thread_index ();
2659 udp = ip4_next_header (ip);
2660 port = udp->dst_port;
2662 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2664 icmp46_header_t *icmp = (icmp46_header_t *) udp;
2665 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
2666 if (!icmp_is_error_message (icmp))
2667 port = echo->identifier;
2670 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2671 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2672 void *l4_header = ip4_next_header (inner_ip);
2675 case SNAT_PROTOCOL_ICMP:
2676 icmp = (icmp46_header_t *) l4_header;
2677 echo = (icmp_echo_header_t *) (icmp + 1);
2678 port = echo->identifier;
2680 case SNAT_PROTOCOL_UDP:
2681 case SNAT_PROTOCOL_TCP:
2682 port = ((tcp_udp_header_t *) l4_header)->src_port;
2685 return vlib_get_thread_index ();
2690 /* try static mappings with port */
2691 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2693 make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
2694 clib_net_to_host_u16 (port));
2695 if (!clib_bihash_search_8_8
2696 (&sm->static_mapping_by_external, &kv, &value))
2698 m = pool_elt_at_index (sm->static_mappings, value.value);
2699 if (!is_lb_static_mapping (m))
2700 return m->workers[0];
2702 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2703 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
2705 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
2706 return m->workers[hash & (_vec_len (m->workers) - 1)];
2708 return m->workers[hash % _vec_len (m->workers)];
2712 /* worker by outside port */
2713 next_worker_index = sm->first_worker_index;
2714 next_worker_index +=
2715 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2717 return next_worker_index;
2720 static clib_error_t *
2721 snat_config (vlib_main_t * vm, unformat_input_t * input)
2723 snat_main_t *sm = &snat_main;
2724 nat66_main_t *nm = &nat66_main;
2725 u32 translation_buckets = 1024;
2726 u32 translation_memory_size = 128 << 20;
2727 u32 user_buckets = 128;
2728 u32 user_memory_size = 64 << 20;
2729 u32 max_translations_per_user = 100;
2730 u32 outside_vrf_id = 0;
2731 u32 outside_ip6_vrf_id = 0;
2732 u32 inside_vrf_id = 0;
2733 u32 static_mapping_buckets = 1024;
2734 u32 static_mapping_memory_size = 64 << 20;
2735 u32 nat64_bib_buckets = 1024;
2736 u32 nat64_bib_memory_size = 128 << 20;
2737 u32 nat64_st_buckets = 2048;
2738 u32 nat64_st_memory_size = 256 << 20;
2739 u8 static_mapping_only = 0;
2740 u8 static_mapping_connection_tracking = 0;
2741 snat_main_per_thread_data_t *tsm;
2742 dslite_main_t *dm = &dslite_main;
2744 sm->deterministic = 0;
2746 sm->endpoint_dependent = 0;
2748 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2751 (input, "translation hash buckets %d", &translation_buckets))
2753 else if (unformat (input, "translation hash memory %d",
2754 &translation_memory_size));
2755 else if (unformat (input, "user hash buckets %d", &user_buckets))
2757 else if (unformat (input, "user hash memory %d", &user_memory_size))
2759 else if (unformat (input, "max translations per user %d",
2760 &max_translations_per_user))
2762 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
2764 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
2766 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
2768 else if (unformat (input, "static mapping only"))
2770 static_mapping_only = 1;
2771 if (unformat (input, "connection tracking"))
2772 static_mapping_connection_tracking = 1;
2774 else if (unformat (input, "deterministic"))
2775 sm->deterministic = 1;
2776 else if (unformat (input, "nat64 bib hash buckets %d",
2777 &nat64_bib_buckets))
2779 else if (unformat (input, "nat64 bib hash memory %d",
2780 &nat64_bib_memory_size))
2783 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2785 else if (unformat (input, "nat64 st hash memory %d",
2786 &nat64_st_memory_size))
2788 else if (unformat (input, "out2in dpo"))
2790 else if (unformat (input, "dslite ce"))
2791 dslite_set_ce (dm, 1);
2792 else if (unformat (input, "endpoint-dependent"))
2793 sm->endpoint_dependent = 1;
2795 return clib_error_return (0, "unknown input '%U'",
2796 format_unformat_error, input);
2799 if (sm->deterministic && sm->endpoint_dependent)
2800 return clib_error_return (0,
2801 "deterministic and endpoint-dependent modes are mutually exclusive");
2803 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
2804 return clib_error_return (0,
2805 "static mapping only mode available only for simple nat");
2807 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
2808 return clib_error_return (0,
2809 "out2in dpo mode available only for simple nat");
2811 /* for show commands, etc. */
2812 sm->translation_buckets = translation_buckets;
2813 sm->translation_memory_size = translation_memory_size;
2814 /* do not exceed load factor 10 */
2815 sm->max_translations = 10 * translation_buckets;
2816 sm->user_buckets = user_buckets;
2817 sm->user_memory_size = user_memory_size;
2818 sm->max_translations_per_user = max_translations_per_user;
2819 sm->outside_vrf_id = outside_vrf_id;
2820 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2822 FIB_SOURCE_PLUGIN_HI);
2823 nm->outside_vrf_id = outside_ip6_vrf_id;
2824 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2826 FIB_SOURCE_PLUGIN_HI);
2827 sm->inside_vrf_id = inside_vrf_id;
2828 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2830 FIB_SOURCE_PLUGIN_HI);
2831 sm->static_mapping_only = static_mapping_only;
2832 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2834 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2835 nat64_st_memory_size);
2837 if (sm->deterministic)
2839 sm->in2out_node_index = snat_det_in2out_node.index;
2840 sm->in2out_output_node_index = ~0;
2841 sm->out2in_node_index = snat_det_out2in_node.index;
2842 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2843 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2847 if (sm->endpoint_dependent)
2849 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2850 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
2851 sm->in2out_node_index = nat44_ed_in2out_node.index;
2852 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
2853 sm->out2in_node_index = nat44_ed_out2in_node.index;
2854 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
2855 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
2856 nat_affinity_init (vm);
2860 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2861 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2862 sm->in2out_node_index = snat_in2out_node.index;
2863 sm->in2out_output_node_index = snat_in2out_output_node.index;
2864 sm->out2in_node_index = snat_out2in_node.index;
2865 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2866 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2868 if (!static_mapping_only ||
2869 (static_mapping_only && static_mapping_connection_tracking))
2872 vec_foreach (tsm, sm->per_thread_data)
2874 if (sm->endpoint_dependent)
2876 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
2877 translation_buckets,
2878 translation_memory_size);
2879 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
2880 format_ed_session_kvp);
2882 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
2883 translation_buckets,
2884 translation_memory_size);
2885 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
2886 format_ed_session_kvp);
2890 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
2891 translation_buckets,
2892 translation_memory_size);
2893 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
2894 format_session_kvp);
2896 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
2897 translation_buckets,
2898 translation_memory_size);
2899 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
2900 format_session_kvp);
2903 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2905 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
2913 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2914 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2916 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2917 "static_mapping_by_local", static_mapping_buckets,
2918 static_mapping_memory_size);
2919 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
2920 format_static_mapping_kvp);
2922 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2923 "static_mapping_by_external",
2924 static_mapping_buckets,
2925 static_mapping_memory_size);
2926 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
2927 format_static_mapping_kvp);
2933 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2936 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2939 ip4_address_t * address,
2941 u32 if_address_index, u32 is_delete)
2943 snat_main_t *sm = &snat_main;
2944 snat_static_map_resolve_t *rp;
2945 snat_static_mapping_t *m;
2946 snat_session_key_t m_key;
2947 clib_bihash_kv_8_8_t kv, value;
2949 ip4_address_t l_addr;
2951 for (i = 0; i < vec_len (sm->to_resolve); i++)
2953 rp = sm->to_resolve + i;
2954 if (rp->addr_only == 0)
2956 if (rp->sw_if_index == sw_if_index)
2963 m_key.addr.as_u32 = address->as_u32;
2964 m_key.port = rp->addr_only ? 0 : rp->e_port;
2965 m_key.protocol = rp->addr_only ? 0 : rp->proto;
2966 m_key.fib_index = sm->outside_fib_index;
2967 kv.key = m_key.as_u64;
2968 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2971 m = pool_elt_at_index (sm->static_mappings, value.value);
2975 /* Don't trip over lease renewal, static config */
2985 /* Indetity mapping? */
2986 if (rp->l_addr.as_u32 == 0)
2987 l_addr.as_u32 = address[0].as_u32;
2989 l_addr.as_u32 = rp->l_addr.as_u32;
2990 /* Add the static mapping */
2991 rv = snat_add_static_mapping (l_addr,
2996 rp->addr_only, ~0 /* sw_if_index */ ,
2997 rp->proto, !is_delete, rp->twice_nat,
2998 rp->out2in_only, rp->tag, rp->identity_nat);
3000 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3004 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3007 ip4_address_t * address,
3009 u32 if_address_index, u32 is_delete)
3011 snat_main_t *sm = &snat_main;
3012 snat_static_map_resolve_t *rp;
3013 ip4_address_t l_addr;
3017 snat_address_t *addresses = sm->addresses;
3019 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
3021 if (sw_if_index == sm->auto_add_sw_if_indices[i])
3025 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
3028 addresses = sm->twice_nat_addresses;
3029 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3038 /* Don't trip over lease renewal, static config */
3039 for (j = 0; j < vec_len (addresses); j++)
3040 if (addresses[j].addr.as_u32 == address->as_u32)
3043 (void) snat_add_address (sm, address, ~0, twice_nat);
3044 /* Scan static map resolution vector */
3045 for (j = 0; j < vec_len (sm->to_resolve); j++)
3047 rp = sm->to_resolve + j;
3050 /* On this interface? */
3051 if (rp->sw_if_index == sw_if_index)
3053 /* Indetity mapping? */
3054 if (rp->l_addr.as_u32 == 0)
3055 l_addr.as_u32 = address[0].as_u32;
3057 l_addr.as_u32 = rp->l_addr.as_u32;
3058 /* Add the static mapping */
3059 rv = snat_add_static_mapping (l_addr,
3065 ~0 /* sw_if_index */ ,
3067 rp->is_add, rp->twice_nat,
3068 rp->out2in_only, rp->tag,
3071 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3078 (void) snat_del_address (sm, address[0], 1, twice_nat);
3085 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
3088 ip4_main_t *ip4_main = sm->ip4_main;
3089 ip4_address_t *first_int_addr;
3090 snat_static_map_resolve_t *rp;
3091 u32 *indices_to_delete = 0;
3093 u32 *auto_add_sw_if_indices =
3095 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3097 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
3100 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
3102 if (auto_add_sw_if_indices[i] == sw_if_index)
3106 /* if have address remove it */
3108 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3111 for (j = 0; j < vec_len (sm->to_resolve); j++)
3113 rp = sm->to_resolve + j;
3114 if (rp->sw_if_index == sw_if_index)
3115 vec_add1 (indices_to_delete, j);
3117 if (vec_len (indices_to_delete))
3119 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3120 vec_del1 (sm->to_resolve, j);
3121 vec_free (indices_to_delete);
3125 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3127 vec_del1 (sm->auto_add_sw_if_indices, i);
3130 return VNET_API_ERROR_VALUE_EXIST;
3137 return VNET_API_ERROR_NO_SUCH_ENTRY;
3139 /* add to the auto-address list */
3141 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3143 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
3145 /* If the address is already bound - or static - add it now */
3147 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
3153 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3154 snat_protocol_t proto, u32 vrf_id, int is_in)
3156 snat_main_per_thread_data_t *tsm;
3157 clib_bihash_kv_8_8_t kv, value;
3159 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3160 snat_session_key_t key;
3162 clib_bihash_8_8_t *t;
3164 if (sm->endpoint_dependent)
3165 return VNET_API_ERROR_UNSUPPORTED;
3167 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3168 if (sm->num_workers > 1)
3170 vec_elt_at_index (sm->per_thread_data,
3171 sm->worker_in2out_cb (&ip, fib_index));
3173 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3175 key.addr.as_u32 = addr->as_u32;
3176 key.port = clib_host_to_net_u16 (port);
3177 key.protocol = proto;
3178 key.fib_index = fib_index;
3179 kv.key = key.as_u64;
3180 t = is_in ? &tsm->in2out : &tsm->out2in;
3181 if (!clib_bihash_search_8_8 (t, &kv, &value))
3183 if (pool_is_free_index (tsm->sessions, value.value))
3184 return VNET_API_ERROR_UNSPECIFIED;
3186 s = pool_elt_at_index (tsm->sessions, value.value);
3187 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3188 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3192 return VNET_API_ERROR_NO_SUCH_ENTRY;
3196 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3197 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3198 u32 vrf_id, int is_in)
3201 clib_bihash_16_8_t *t;
3202 nat_ed_ses_key_t key;
3203 clib_bihash_kv_16_8_t kv, value;
3204 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3206 snat_main_per_thread_data_t *tsm;
3208 if (!sm->endpoint_dependent)
3209 return VNET_API_ERROR_FEATURE_DISABLED;
3211 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3212 if (sm->num_workers > 1)
3214 vec_elt_at_index (sm->per_thread_data,
3215 sm->worker_in2out_cb (&ip, fib_index));
3217 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3219 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
3220 key.l_addr.as_u32 = addr->as_u32;
3221 key.r_addr.as_u32 = eh_addr->as_u32;
3222 key.l_port = clib_host_to_net_u16 (port);
3223 key.r_port = clib_host_to_net_u16 (eh_port);
3225 key.fib_index = fib_index;
3226 kv.key[0] = key.as_u64[0];
3227 kv.key[1] = key.as_u64[1];
3228 if (clib_bihash_search_16_8 (t, &kv, &value))
3229 return VNET_API_ERROR_NO_SUCH_ENTRY;
3231 if (pool_is_free_index (tsm->sessions, value.value))
3232 return VNET_API_ERROR_UNSPECIFIED;
3233 s = pool_elt_at_index (tsm->sessions, value.value);
3234 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3235 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3240 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3242 snat_main_t *sm = &snat_main;
3244 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
3245 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3247 sm->psid_offset = psid_offset;
3248 sm->psid_length = psid_length;
3252 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
3254 snat_main_t *sm = &snat_main;
3256 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
3257 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
3258 sm->start_port = start_port;
3259 sm->end_port = end_port;
3263 nat_set_alloc_addr_and_port_default (void)
3265 snat_main_t *sm = &snat_main;
3267 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
3268 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3272 * fd.io coding-style-patch-verification: ON
3275 * eval: (c-set-style "gnu")