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 <vpp/app/version.h>
20 #include <vnet/vnet.h>
21 #include <vnet/ip/ip.h>
22 #include <vnet/ip/ip4.h>
23 #include <vnet/ip/ip_table.h>
24 #include <vnet/ip/reass/ip4_sv_reass.h>
25 #include <vnet/fib/fib_table.h>
26 #include <vnet/fib/ip4_fib.h>
27 #include <vnet/plugin/plugin.h>
28 #include <vppinfra/bihash_16_8.h>
30 #include <nat/lib/log.h>
31 #include <nat/lib/nat_syslog.h>
32 #include <nat/lib/nat_inlines.h>
33 #include <nat/lib/ipfix_logging.h>
35 #include <nat/nat44-ed/nat44_ed.h>
36 #include <nat/nat44-ed/nat44_ed_affinity.h>
37 #include <nat/nat44-ed/nat44_ed_inlines.h>
39 #include <vpp/stats/stat_segment.h>
41 snat_main_t snat_main;
43 static_always_inline void nat_validate_interface_counters (snat_main_t *sm,
46 #define skip_if_disabled() \
49 snat_main_t *sm = &snat_main; \
50 if (PREDICT_FALSE (!sm->enabled)) \
55 #define fail_if_enabled() \
58 snat_main_t *sm = &snat_main; \
59 if (PREDICT_FALSE (sm->enabled)) \
61 nat_log_err ("plugin enabled"); \
67 #define fail_if_disabled() \
70 snat_main_t *sm = &snat_main; \
71 if (PREDICT_FALSE (!sm->enabled)) \
73 nat_log_err ("plugin disabled"); \
79 /* Hook up input features */
80 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
81 .arc_name = "ip4-unicast",
82 .node_name = "nat-pre-in2out",
83 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
84 "ip4-sv-reassembly-feature"),
86 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
87 .arc_name = "ip4-unicast",
88 .node_name = "nat-pre-out2in",
89 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
90 "ip4-dhcp-client-detect",
91 "ip4-sv-reassembly-feature"),
93 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
94 .arc_name = "ip4-unicast",
95 .node_name = "nat44-in2out-worker-handoff",
96 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
98 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
99 .arc_name = "ip4-unicast",
100 .node_name = "nat44-out2in-worker-handoff",
101 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
102 "ip4-dhcp-client-detect"),
104 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
105 .arc_name = "ip4-unicast",
106 .node_name = "nat44-in2out",
107 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
109 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
110 .arc_name = "ip4-unicast",
111 .node_name = "nat44-out2in",
112 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
113 "ip4-dhcp-client-detect"),
115 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
116 .arc_name = "ip4-unicast",
117 .node_name = "nat44-ed-in2out",
118 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
120 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
121 .arc_name = "ip4-unicast",
122 .node_name = "nat44-ed-out2in",
123 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
124 "ip4-dhcp-client-detect"),
126 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
127 .arc_name = "ip4-unicast",
128 .node_name = "nat44-ed-classify",
129 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
131 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
132 .arc_name = "ip4-unicast",
133 .node_name = "nat44-handoff-classify",
134 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
136 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
137 .arc_name = "ip4-unicast",
138 .node_name = "nat44-in2out-fast",
139 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
141 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
142 .arc_name = "ip4-unicast",
143 .node_name = "nat44-out2in-fast",
144 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
145 "ip4-dhcp-client-detect"),
148 /* Hook up output features */
149 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
150 .arc_name = "ip4-output",
151 .node_name = "nat44-in2out-output",
152 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
153 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
155 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
156 .arc_name = "ip4-output",
157 .node_name = "nat44-in2out-output-worker-handoff",
158 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
159 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
161 VNET_FEATURE_INIT (nat_pre_in2out_output, static) = {
162 .arc_name = "ip4-output",
163 .node_name = "nat-pre-in2out-output",
164 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
165 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
167 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
168 .arc_name = "ip4-output",
169 .node_name = "nat44-ed-in2out-output",
170 .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
171 .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
174 VLIB_PLUGIN_REGISTER () = {
175 .version = VPP_BUILD_VER,
176 .description = "Network Address Translation (NAT)",
179 static void nat44_ed_db_init (u32 translations, u32 translation_buckets);
181 static void nat44_ed_db_free ();
183 u32 nat_calc_bihash_buckets (u32 n_elts);
186 format_session_kvp (u8 * s, va_list * args)
188 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
190 s = format (s, "%U thread-index %llu session-index %llu", format_snat_key,
191 v->key, nat_value_get_thread_index (v),
192 nat_value_get_session_index (v));
198 format_static_mapping_kvp (u8 * s, va_list * args)
200 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
202 s = format (s, "%U static-mapping-index %llu",
203 format_snat_key, v->key, v->value);
209 format_ed_session_kvp (u8 * s, va_list * args)
211 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
215 ip4_address_t l_addr, r_addr;
218 split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
220 "local %U:%d remote %U:%d proto %U fib %d thread-index %u "
222 format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
223 format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
224 format_ip_protocol, proto, fib_index,
225 ed_value_get_thread_index (v), ed_value_get_session_index (v));
231 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
234 per_vrf_sessions_unregister_session (s, thread_index);
236 if (nat_ed_ses_i2o_flow_hash_add_del (sm, thread_index, s, 0))
237 nat_elog_warn (sm, "flow hash del failed");
239 if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 0))
240 nat_elog_warn (sm, "flow hash del failed");
242 if (is_fwd_bypass_session (s))
247 if (is_affinity_sessions (s))
248 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
249 s->nat_proto, s->out2in.port);
252 nat_syslog_nat44_sdel (
253 0, s->in2out.fib_index, &s->in2out.addr, s->in2out.port,
254 &s->ext_host_nat_addr, s->ext_host_nat_port, &s->out2in.addr,
255 s->out2in.port, &s->ext_host_addr, s->ext_host_port, s->nat_proto,
256 is_twice_nat_session (s));
258 if (snat_is_unk_proto_session (s))
264 nat_ipfix_logging_nat44_ses_delete (thread_index,
265 s->in2out.addr.as_u32,
266 s->out2in.addr.as_u32,
270 s->in2out.fib_index);
273 /* Twice NAT address and port for external host */
274 if (is_twice_nat_session (s))
276 snat_free_outside_address_and_port (sm->twice_nat_addresses,
278 &s->ext_host_nat_addr,
279 s->ext_host_nat_port, s->nat_proto);
282 if (snat_is_session_static (s))
285 snat_free_outside_address_and_port (sm->addresses, thread_index,
286 &s->out2in.addr, s->out2in.port,
291 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
294 snat_main_t *sm = &snat_main;
295 fib_prefix_t prefix = {
297 .fp_proto = FIB_PROTOCOL_IP4,
299 .ip4.as_u32 = addr->as_u32,
302 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
305 fib_table_entry_update_one_path (fib_index,
308 (FIB_ENTRY_FLAG_CONNECTED |
309 FIB_ENTRY_FLAG_LOCAL |
310 FIB_ENTRY_FLAG_EXCLUSIVE),
314 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
316 fib_table_entry_delete (fib_index, &prefix, sm->fib_src_low);
320 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
325 vlib_thread_main_t *tm = vlib_get_thread_main ();
327 /* Check if address already exists */
328 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
330 if (ap->addr.as_u32 == addr->as_u32)
332 nat_log_err ("address exist");
333 return VNET_API_ERROR_VALUE_EXIST;
338 vec_add2 (sm->twice_nat_addresses, ap, 1);
340 vec_add2 (sm->addresses, ap, 1);
345 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
350 #define _(N, i, n, s) \
351 clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
352 ap->busy_##n##_ports = 0; \
353 ap->busy_##n##_ports_per_thread = 0;\
354 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
361 /* Add external address to FIB */
362 pool_foreach (i, sm->interfaces)
364 if (nat_interface_is_inside (i))
367 snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
370 pool_foreach (i, sm->output_feature_interfaces)
372 if (nat_interface_is_inside (i))
375 snat_add_del_addr_to_fib (addr, 32, i->sw_if_index, 1);
383 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
385 snat_static_mapping_t *m;
386 pool_foreach (m, sm->static_mappings)
388 if (is_sm_addr_only (m->flags) || is_sm_out2in_only (m->flags) ||
389 is_sm_identity_nat (m->flags))
391 if (m->external_addr.as_u32 == addr.as_u32)
398 get_thread_idx_by_port (u16 e_port)
400 snat_main_t *sm = &snat_main;
401 u32 thread_idx = sm->num_workers;
402 if (sm->num_workers > 1)
405 sm->first_worker_index +
406 sm->workers[(e_port - 1024) / sm->port_per_thread];
412 nat_ed_static_mapping_del_sessions (snat_main_t * sm,
413 snat_main_per_thread_data_t * tsm,
414 ip4_address_t l_addr,
417 u32 fib_index, int addr_only,
418 ip4_address_t e_addr, u16 e_port)
421 u32 *indexes_to_free = NULL;
422 pool_foreach (s, tsm->sessions) {
423 if (s->in2out.fib_index != fib_index ||
424 s->in2out.addr.as_u32 != l_addr.as_u32)
430 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
431 s->out2in.port != e_port ||
432 s->in2out.port != l_port ||
433 s->nat_proto != protocol)
437 if (is_lb_session (s))
439 if (!snat_is_session_static (s))
441 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
442 vec_add1 (indexes_to_free, s - tsm->sessions);
447 vec_foreach (ses_index, indexes_to_free)
449 s = pool_elt_at_index (tsm->sessions, *ses_index);
450 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
452 vec_free (indexes_to_free);
456 nat44_ed_reserve_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
458 u32 ti = get_thread_idx_by_port (port);
459 snat_main_t *sm = &snat_main;
460 snat_address_t *a = 0;
463 for (i = 0; i < vec_len (sm->addresses); i++)
465 a = sm->addresses + i;
467 if (a->addr.as_u32 != addr.as_u32)
472 #define _(N, j, n, s) \
473 case NAT_PROTOCOL_##N: \
474 if (a->busy_##n##_port_refcounts[port]) \
476 ++a->busy_##n##_port_refcounts[port]; \
479 a->busy_##n##_ports++; \
480 a->busy_##n##_ports_per_thread[ti]++; \
485 default : nat_elog_info (sm, "unknown protocol");
497 nat44_ed_free_port (ip4_address_t addr, u16 port, nat_protocol_t proto)
499 u32 ti = get_thread_idx_by_port (port);
500 snat_main_t *sm = &snat_main;
501 snat_address_t *a = 0;
504 for (i = 0; i < vec_len (sm->addresses); i++)
506 a = sm->addresses + i;
508 if (a->addr.as_u32 != addr.as_u32)
513 #define _(N, j, n, s) \
514 case NAT_PROTOCOL_##N: \
515 --a->busy_##n##_port_refcounts[port]; \
518 a->busy_##n##_ports--; \
519 a->busy_##n##_ports_per_thread[ti]--; \
524 default : nat_elog_info (sm, "unknown protocol");
536 nat44_ed_add_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
537 nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
538 u32 flags, ip4_address_t pool_addr, u8 *tag)
540 snat_static_map_resolve_t *rp;
541 snat_main_t *sm = &snat_main;
543 vec_add2 (sm->to_resolve, rp, 1);
544 rp->l_addr.as_u32 = l_addr.as_u32;
547 rp->sw_if_index = sw_if_index;
551 rp->pool_addr = pool_addr;
552 rp->tag = vec_dup (tag);
556 nat44_ed_get_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
557 nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
560 snat_static_map_resolve_t *rp;
561 snat_main_t *sm = &snat_main;
564 for (i = 0; i < vec_len (sm->to_resolve); i++)
566 rp = sm->to_resolve + i;
568 if (rp->sw_if_index == sw_if_index && rp->vrf_id == vrf_id)
570 if (is_sm_identity_nat (rp->flags) && is_sm_identity_nat (flags))
572 if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
574 if (rp->e_port != e_port || rp->proto != proto)
580 else if (rp->l_addr.as_u32 == l_addr.as_u32)
582 if (!(is_sm_addr_only (rp->flags) && is_sm_addr_only (flags)))
584 if (rp->l_port != l_port || rp->e_port != e_port ||
606 nat44_ed_del_resolve_record (ip4_address_t l_addr, u16 l_port, u16 e_port,
607 nat_protocol_t proto, u32 vrf_id, u32 sw_if_index,
610 snat_main_t *sm = &snat_main;
612 if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
613 sw_if_index, flags, &i))
615 vec_del1 (sm->to_resolve, i);
621 static_always_inline int
622 nat44_ed_validate_sm_input (u32 flags)
624 // identity nat can be initiated only from inside interface
625 if (is_sm_identity_nat (flags) && is_sm_out2in_only (flags))
627 return VNET_API_ERROR_UNSUPPORTED;
630 if (is_sm_twice_nat (flags) || is_sm_self_twice_nat (flags))
632 if (is_sm_addr_only (flags) || is_sm_identity_nat (flags))
634 return VNET_API_ERROR_UNSUPPORTED;
641 nat44_ed_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
642 u16 l_port, u16 e_port, nat_protocol_t proto,
643 u32 vrf_id, u32 sw_if_index, u32 flags,
644 ip4_address_t pool_addr, u8 *tag)
646 snat_main_t *sm = &snat_main;
647 clib_bihash_kv_8_8_t kv, value;
648 snat_interface_t *interface;
649 nat44_lb_addr_port_t *local;
650 snat_static_mapping_t *m;
654 rv = nat44_ed_validate_sm_input (flags);
660 if (is_sm_addr_only (flags))
662 e_port = l_port = proto = 0;
665 if (is_sm_switch_address (flags))
667 // this mapping is interface bound
668 ip4_address_t *first_int_addr;
670 // check if this record isn't registered for resolve
671 if (!nat44_ed_get_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
672 sw_if_index, flags, 0))
674 return VNET_API_ERROR_VALUE_EXIST;
676 // register record for resolve
677 nat44_ed_add_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
678 sw_if_index, flags, pool_addr, tag);
681 ip4_interface_first_address (sm->ip4_main, sw_if_index, 0);
684 // dhcp resolution required
688 e_addr.as_u32 = first_int_addr->as_u32;
691 if (is_sm_identity_nat (flags))
694 l_addr.as_u32 = e_addr.as_u32;
698 init_nat_k (&kv, e_addr, e_port, 0, proto);
700 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
702 m = pool_elt_at_index (sm->static_mappings, value.value);
703 if (!is_sm_identity_nat (m->flags))
705 return VNET_API_ERROR_VALUE_EXIST;
709 // adding local identity nat record for different vrf table
710 pool_foreach (local, m->locals)
712 if (local->vrf_id == vrf_id)
714 return VNET_API_ERROR_VALUE_EXIST;
718 pool_get (m->locals, local);
720 local->vrf_id = vrf_id;
721 local->fib_index = fib_table_find_or_create_and_lock (
722 FIB_PROTOCOL_IP4, vrf_id, sm->fib_src_low);
724 init_nat_kv (&kv, m->local_addr, m->local_port, local->fib_index,
725 m->proto, 0, m - sm->static_mappings);
726 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
733 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
738 // fallback to default vrf
739 vrf_id = sm->inside_vrf_id;
740 fib_index = sm->inside_fib_index;
741 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
744 // test if local mapping record doesn't exist
745 // identity nat supports multiple records in local mapping
746 if (!(is_sm_out2in_only (flags) || is_sm_identity_nat (flags)))
748 init_nat_k (&kv, l_addr, l_port, fib_index, proto);
749 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_local, &kv, &value))
751 return VNET_API_ERROR_VALUE_EXIST;
755 if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) ||
756 sm->static_mapping_only))
758 if (nat44_ed_reserve_port (e_addr, e_port, proto))
760 // remove resolve record
761 if (is_sm_switch_address (flags) && !is_sm_identity_nat (flags))
763 nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto,
764 vrf_id, sw_if_index, flags);
766 return VNET_API_ERROR_NO_SUCH_ENTRY;
770 pool_get (sm->static_mappings, m);
771 clib_memset (m, 0, sizeof (*m));
774 m->local_addr = l_addr;
775 m->external_addr = e_addr;
777 m->tag = vec_dup (tag);
779 if (is_sm_exact_address (flags) && is_sm_twice_nat (flags))
781 m->pool_addr = pool_addr;
784 if (!is_sm_addr_only (flags))
786 m->local_port = l_port;
787 m->external_port = e_port;
791 if (is_sm_identity_nat (flags))
793 pool_get (m->locals, local);
795 local->vrf_id = vrf_id;
796 local->fib_index = fib_index;
801 m->fib_index = fib_index;
804 if (!is_sm_out2in_only (flags))
806 init_nat_kv (&kv, m->local_addr, m->local_port, fib_index, m->proto, 0,
807 m - sm->static_mappings);
808 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
811 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
812 m - sm->static_mappings);
813 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
815 if (sm->num_workers > 1)
817 // store worker index for this record
819 .src_address = m->local_addr,
823 nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0);
824 vec_add1 (m->workers, worker_index);
827 if (is_sm_identity_nat (flags) || !is_sm_addr_only (flags))
830 pool_foreach (interface, sm->interfaces)
832 if (nat_interface_is_inside (interface))
835 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 1);
839 pool_foreach (interface, sm->output_feature_interfaces)
841 if (nat_interface_is_inside (interface))
844 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 1);
852 nat44_ed_del_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
853 u16 l_port, u16 e_port, nat_protocol_t proto,
854 u32 vrf_id, u32 sw_if_index, u32 flags)
856 snat_main_per_thread_data_t *tsm;
857 snat_main_t *sm = &snat_main;
859 clib_bihash_kv_8_8_t kv, value;
860 snat_interface_t *interface;
861 nat44_lb_addr_port_t *local;
862 snat_static_mapping_t *m;
866 rv = nat44_ed_validate_sm_input (flags);
872 if (is_sm_addr_only (flags))
874 e_port = l_port = proto = 0;
877 if (is_sm_switch_address (flags))
879 // this mapping is interface bound
880 ip4_address_t *first_int_addr;
882 // delete record registered for resolve
883 if (nat44_ed_del_resolve_record (l_addr, l_port, e_port, proto, vrf_id,
886 return VNET_API_ERROR_NO_SUCH_ENTRY;
890 ip4_interface_first_address (sm->ip4_main, sw_if_index, 0);
893 // dhcp resolution required
897 e_addr.as_u32 = first_int_addr->as_u32;
900 if (is_sm_identity_nat (flags))
903 l_addr.as_u32 = e_addr.as_u32;
907 init_nat_k (&kv, e_addr, e_port, 0, proto);
909 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
911 if (is_sm_switch_address (flags))
915 return VNET_API_ERROR_NO_SUCH_ENTRY;
918 m = pool_elt_at_index (sm->static_mappings, value.value);
920 if (is_sm_identity_nat (flags))
924 if (!is_sm_switch_address (flags))
926 vrf_id = sm->inside_vrf_id;
929 pool_foreach (local, m->locals)
931 if (local->vrf_id == vrf_id)
933 local = pool_elt_at_index (m->locals, local - m->locals);
934 fib_index = local->fib_index;
935 pool_put (m->locals, local);
942 return VNET_API_ERROR_NO_SUCH_ENTRY;
947 fib_index = m->fib_index;
950 if (!(is_sm_out2in_only (flags) || is_sm_addr_only (flags) ||
951 sm->static_mapping_only))
953 if (nat44_ed_free_port (e_addr, e_port, proto))
955 return VNET_API_ERROR_INVALID_VALUE;
959 if (!is_sm_out2in_only (flags))
961 init_nat_k (&kv, l_addr, l_port, fib_index, proto);
962 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
965 if (!sm->static_mapping_only || sm->static_mapping_connection_tracking)
967 // delete sessions for static mapping
968 if (sm->num_workers > 1)
969 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
971 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
973 nat_ed_static_mapping_del_sessions (
974 sm, tsm, m->local_addr, m->local_port, m->proto, fib_index,
975 is_sm_addr_only (flags), e_addr, e_port);
978 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
980 if (pool_elts (m->locals))
984 init_nat_k (&kv, e_addr, e_port, 0, proto);
985 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
988 vec_free (m->workers);
989 pool_put (sm->static_mappings, m);
991 if (is_sm_identity_nat (flags) || !is_sm_addr_only (flags))
994 pool_foreach (interface, sm->interfaces)
996 if (nat_interface_is_inside (interface))
999 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 0);
1003 pool_foreach (interface, sm->output_feature_interfaces)
1005 if (nat_interface_is_inside (interface))
1008 snat_add_del_addr_to_fib (&e_addr, 32, interface->sw_if_index, 0);
1016 nat44_ed_add_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1017 nat_protocol_t proto,
1018 nat44_lb_addr_port_t *locals, u32 flags,
1019 u8 *tag, u32 affinity)
1021 snat_main_t *sm = &snat_main;
1022 snat_static_mapping_t *m;
1023 clib_bihash_kv_8_8_t kv, value;
1024 snat_address_t *a = 0;
1026 nat44_lb_addr_port_t *local;
1031 init_nat_k (&kv, e_addr, e_port, 0, proto);
1032 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1035 m = pool_elt_at_index (sm->static_mappings, value.value);
1038 return VNET_API_ERROR_VALUE_EXIST;
1040 if (vec_len (locals) < 2)
1041 return VNET_API_ERROR_INVALID_VALUE;
1043 /* Find external address in allocated addresses and reserve port for
1044 address and port pair mapping when dynamic translations enabled */
1045 if (!(sm->static_mapping_only || is_sm_out2in_only (flags)))
1047 for (i = 0; i < vec_len (sm->addresses); i++)
1049 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1051 a = sm->addresses + i;
1052 /* External port must be unused */
1055 #define _(N, j, n, s) \
1056 case NAT_PROTOCOL_##N: \
1057 if (a->busy_##n##_port_refcounts[e_port]) \
1058 return VNET_API_ERROR_INVALID_VALUE; \
1059 ++a->busy_##n##_port_refcounts[e_port]; \
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_nat_protocol
1068 default : nat_elog_info (sm, "unknown protocol");
1069 return VNET_API_ERROR_INVALID_VALUE_2;
1074 /* External address must be allocated */
1076 return VNET_API_ERROR_NO_SUCH_ENTRY;
1079 pool_get (sm->static_mappings, m);
1080 clib_memset (m, 0, sizeof (*m));
1081 m->tag = vec_dup (tag);
1082 m->external_addr = e_addr;
1083 m->external_port = e_port;
1084 m->affinity = affinity;
1088 m->flags |= NAT_SM_FLAG_LB;
1091 m->affinity_per_service_list_head_index =
1092 nat_affinity_get_per_service_list_head_index ();
1094 m->affinity_per_service_list_head_index = ~0;
1096 init_nat_kv (&kv, m->external_addr, m->external_port, 0, m->proto, 0,
1097 m - sm->static_mappings);
1098 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1100 nat_elog_err (sm, "static_mapping_by_external key add failed");
1101 return VNET_API_ERROR_UNSPECIFIED;
1104 for (i = 0; i < vec_len (locals); i++)
1106 locals[i].fib_index = fib_table_find_or_create_and_lock (
1107 FIB_PROTOCOL_IP4, locals[i].vrf_id, sm->fib_src_low);
1108 if (!is_sm_out2in_only (flags))
1110 init_nat_kv (&kv, locals[i].addr, locals[i].port,
1111 locals[i].fib_index, m->proto, 0,
1112 m - sm->static_mappings);
1113 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1115 locals[i].prefix = (i == 0) ?
1116 locals[i].probability :
1117 (locals[i - 1].prefix + locals[i].probability);
1118 pool_get (m->locals, local);
1120 if (sm->num_workers > 1)
1123 .src_address = locals[i].addr,
1125 bitmap = clib_bitmap_set (
1126 bitmap, nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0),
1131 /* Assign workers */
1132 if (sm->num_workers > 1)
1134 clib_bitmap_foreach (i, bitmap)
1136 vec_add1 (m->workers, i);
1144 nat44_ed_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1145 nat_protocol_t proto, u32 flags)
1147 snat_main_t *sm = &snat_main;
1148 snat_static_mapping_t *m;
1149 clib_bihash_kv_8_8_t kv, value;
1150 snat_address_t *a = 0;
1152 nat44_lb_addr_port_t *local;
1153 snat_main_per_thread_data_t *tsm;
1157 init_nat_k (&kv, e_addr, e_port, 0, proto);
1158 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1161 m = pool_elt_at_index (sm->static_mappings, value.value);
1164 return VNET_API_ERROR_NO_SUCH_ENTRY;
1166 if (!is_sm_lb (m->flags))
1167 return VNET_API_ERROR_INVALID_VALUE;
1169 /* Free external address port */
1170 if (!(sm->static_mapping_only || is_sm_out2in_only (flags)))
1172 for (i = 0; i < vec_len (sm->addresses); i++)
1174 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1176 a = sm->addresses + i;
1179 #define _(N, j, n, s) \
1180 case NAT_PROTOCOL_##N: \
1181 --a->busy_##n##_port_refcounts[e_port]; \
1182 if (e_port > 1024) \
1184 a->busy_##n##_ports--; \
1185 a->busy_##n##_ports_per_thread[get_thread_idx_by_port (e_port)]--; \
1188 foreach_nat_protocol
1190 default : nat_elog_info (sm, "unknown protocol");
1191 return VNET_API_ERROR_INVALID_VALUE_2;
1198 init_nat_k (&kv, m->external_addr, m->external_port, 0, m->proto);
1199 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1201 nat_elog_err (sm, "static_mapping_by_external key del failed");
1202 return VNET_API_ERROR_UNSPECIFIED;
1205 pool_foreach (local, m->locals)
1207 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1208 if (!is_sm_out2in_only (flags))
1210 init_nat_k (&kv, local->addr, local->port, local->fib_index,
1212 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1214 nat_elog_err (sm, "static_mapping_by_local key del failed");
1215 return VNET_API_ERROR_UNSPECIFIED;
1219 if (sm->num_workers > 1)
1222 .src_address = local->addr,
1224 tsm = vec_elt_at_index (
1225 sm->per_thread_data,
1226 nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0));
1229 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1231 /* Delete sessions */
1232 pool_foreach (s, tsm->sessions)
1234 if (!(is_lb_session (s)))
1237 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1238 s->in2out.port != local->port)
1241 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1242 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1248 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1251 pool_free (m->locals);
1253 vec_free (m->workers);
1254 pool_put (sm->static_mappings, m);
1260 nat44_ed_add_del_lb_static_mapping_local (ip4_address_t e_addr, u16 e_port,
1261 ip4_address_t l_addr, u16 l_port,
1262 nat_protocol_t proto, u32 vrf_id,
1263 u8 probability, u8 is_add)
1265 snat_main_t *sm = &snat_main;
1266 snat_static_mapping_t *m = 0;
1267 clib_bihash_kv_8_8_t kv, value;
1268 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1269 snat_main_per_thread_data_t *tsm;
1275 init_nat_k (&kv, e_addr, e_port, 0, proto);
1276 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1277 m = pool_elt_at_index (sm->static_mappings, value.value);
1280 return VNET_API_ERROR_NO_SUCH_ENTRY;
1282 if (!is_sm_lb (m->flags))
1283 return VNET_API_ERROR_INVALID_VALUE;
1285 pool_foreach (local, m->locals)
1287 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1288 (local->vrf_id == vrf_id))
1290 match_local = local;
1298 return VNET_API_ERROR_VALUE_EXIST;
1300 pool_get (m->locals, local);
1301 clib_memset (local, 0, sizeof (*local));
1302 local->addr.as_u32 = l_addr.as_u32;
1303 local->port = l_port;
1304 local->probability = probability;
1305 local->vrf_id = vrf_id;
1307 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1310 if (!is_sm_out2in_only (m->flags))
1312 init_nat_kv (&kv, l_addr, l_port, local->fib_index, proto, 0,
1313 m - sm->static_mappings);
1314 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1315 nat_elog_err (sm, "static_mapping_by_local key add failed");
1321 return VNET_API_ERROR_NO_SUCH_ENTRY;
1323 if (pool_elts (m->locals) < 3)
1324 return VNET_API_ERROR_UNSPECIFIED;
1326 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1329 if (!is_sm_out2in_only (m->flags))
1331 init_nat_k (&kv, l_addr, l_port, match_local->fib_index, proto);
1332 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1333 nat_elog_err (sm, "static_mapping_by_local key del failed");
1336 if (sm->num_workers > 1)
1339 .src_address = local->addr,
1341 tsm = vec_elt_at_index (
1342 sm->per_thread_data,
1343 nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index, 0));
1346 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1348 /* Delete sessions */
1349 pool_foreach (s, tsm->sessions) {
1350 if (!(is_lb_session (s)))
1353 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1354 s->in2out.port != match_local->port)
1357 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1358 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
1361 pool_put (m->locals, match_local);
1364 vec_free (m->workers);
1366 pool_foreach (local, m->locals)
1368 vec_add1 (locals, local - m->locals);
1369 if (sm->num_workers > 1)
1372 ip.src_address.as_u32 = local->addr.as_u32,
1373 bitmap = clib_bitmap_set (
1375 nat44_ed_get_in2out_worker_index (0, &ip, local->fib_index, 0), 1);
1379 ASSERT (vec_len (locals) > 1);
1381 local = pool_elt_at_index (m->locals, locals[0]);
1382 local->prefix = local->probability;
1383 for (i = 1; i < vec_len (locals); i++)
1385 local = pool_elt_at_index (m->locals, locals[i]);
1386 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1387 local->prefix = local->probability + prev_local->prefix;
1390 /* Assign workers */
1391 if (sm->num_workers > 1)
1393 clib_bitmap_foreach (i, bitmap) { vec_add1(m->workers, i); }
1400 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1403 snat_address_t *a = 0;
1404 snat_session_t *ses;
1405 u32 *ses_to_be_removed = 0, *ses_index;
1406 snat_main_per_thread_data_t *tsm;
1407 snat_static_mapping_t *m;
1408 snat_interface_t *interface;
1410 snat_address_t *addresses =
1411 twice_nat ? sm->twice_nat_addresses : sm->addresses;
1413 /* Find SNAT address */
1414 for (i = 0; i < vec_len (addresses); i++)
1416 if (addresses[i].addr.as_u32 == addr.as_u32)
1424 nat_log_err ("no such address");
1425 return VNET_API_ERROR_NO_SUCH_ENTRY;
1430 pool_foreach (m, sm->static_mappings)
1432 if (m->external_addr.as_u32 == addr.as_u32)
1434 nat44_ed_del_static_mapping (m->local_addr, m->external_addr,
1435 m->local_port, m->external_port,
1436 m->proto, m->vrf_id, ~0, m->flags);
1442 /* Check if address is used in some static mapping */
1443 if (is_snat_address_used_in_static_mapping (sm, addr))
1445 nat_log_err ("address used in static mapping");
1446 return VNET_API_ERROR_UNSPECIFIED;
1450 if (a->fib_index != ~0)
1451 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, sm->fib_src_low);
1453 /* Delete sessions using address */
1454 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1456 vec_foreach (tsm, sm->per_thread_data)
1458 pool_foreach (ses, tsm->sessions) {
1459 if (ses->out2in.addr.as_u32 == addr.as_u32)
1461 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1462 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1466 vec_foreach (ses_index, ses_to_be_removed)
1468 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1469 nat_ed_session_delete (sm, ses, tsm - sm->per_thread_data, 1);
1472 vec_free (ses_to_be_removed);
1476 #define _(N, i, n, s) \
1477 vec_free (a->busy_##n##_ports_per_thread);
1478 foreach_nat_protocol
1483 vec_del1 (sm->twice_nat_addresses, i);
1486 else vec_del1 (sm->addresses, i);
1488 /* Delete external address from FIB */
1489 pool_foreach (interface, sm->interfaces)
1491 if (nat_interface_is_inside (interface))
1494 snat_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
1497 pool_foreach (interface, sm->output_feature_interfaces)
1499 if (nat_interface_is_inside (interface))
1502 snat_add_del_addr_to_fib (&addr, 32, interface->sw_if_index, 0);
1510 expire_per_vrf_sessions (u32 fib_index)
1512 per_vrf_sessions_t *per_vrf_sessions;
1513 snat_main_per_thread_data_t *tsm;
1514 snat_main_t *sm = &snat_main;
1516 vec_foreach (tsm, sm->per_thread_data)
1518 vec_foreach (per_vrf_sessions, tsm->per_vrf_sessions_vec)
1520 if ((per_vrf_sessions->rx_fib_index == fib_index) ||
1521 (per_vrf_sessions->tx_fib_index == fib_index))
1523 per_vrf_sessions->expired = 1;
1530 update_per_vrf_sessions_vec (u32 fib_index, int is_del)
1532 snat_main_t *sm = &snat_main;
1535 // we don't care if it is outside/inside fib
1536 // we just care about their ref_count
1537 // if it reaches 0 sessions should expire
1538 // because the fib isn't valid for NAT anymore
1540 vec_foreach (fib, sm->fibs)
1542 if (fib->fib_index == fib_index)
1547 if (!fib->ref_count)
1549 vec_del1 (sm->fibs, fib - sm->fibs);
1550 expire_per_vrf_sessions (fib_index);
1560 vec_add2 (sm->fibs, fib, 1);
1562 fib->fib_index = fib_index;
1566 static_always_inline nat_outside_fib_t *
1567 nat44_ed_get_outside_fib (nat_outside_fib_t *outside_fibs, u32 fib_index)
1569 nat_outside_fib_t *f;
1570 vec_foreach (f, outside_fibs)
1572 if (f->fib_index == fib_index)
1580 static_always_inline snat_interface_t *
1581 nat44_ed_get_interface (snat_interface_t *interfaces, u32 sw_if_index)
1583 snat_interface_t *i;
1584 pool_foreach (i, interfaces)
1586 if (i->sw_if_index == sw_if_index)
1595 nat44_ed_add_interface (u32 sw_if_index, u8 is_inside)
1597 const char *del_feature_name, *feature_name;
1598 snat_main_t *sm = &snat_main;
1600 nat_outside_fib_t *outside_fib;
1601 snat_static_mapping_t *m;
1602 snat_interface_t *i;
1609 nat_log_err ("nat44 is disabled");
1610 return VNET_API_ERROR_UNSUPPORTED;
1613 if (nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index))
1615 nat_log_err ("error interface already configured");
1616 return VNET_API_ERROR_VALUE_EXIST;
1619 i = nat44_ed_get_interface (sm->interfaces, sw_if_index);
1622 if ((nat_interface_is_inside (i) && is_inside) ||
1623 (nat_interface_is_outside (i) && !is_inside))
1627 if (sm->num_workers > 1)
1629 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1630 "nat44-out2in-worker-handoff";
1631 feature_name = "nat44-handoff-classify";
1635 del_feature_name = !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1637 feature_name = "nat44-ed-classify";
1640 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1643 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1644 sw_if_index, 0, 0, 0);
1645 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1650 if (sm->num_workers > 1)
1652 feature_name = is_inside ? "nat44-in2out-worker-handoff" :
1653 "nat44-out2in-worker-handoff";
1657 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1660 nat_validate_interface_counters (sm, sw_if_index);
1661 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1664 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1667 pool_get (sm->interfaces, i);
1668 i->sw_if_index = sw_if_index;
1673 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1675 update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
1679 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1681 outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1684 outside_fib->refcount++;
1688 vec_add2 (sm->outside_fibs, outside_fib, 1);
1689 outside_fib->fib_index = fib_index;
1690 outside_fib->refcount = 1;
1693 vec_foreach (ap, sm->addresses)
1695 snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 1);
1697 pool_foreach (m, sm->static_mappings)
1699 if (!(is_sm_addr_only (m->flags)) ||
1700 (m->local_addr.as_u32 == m->external_addr.as_u32))
1704 snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 1);
1709 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1716 nat44_ed_del_interface (u32 sw_if_index, u8 is_inside)
1718 const char *del_feature_name, *feature_name;
1719 snat_main_t *sm = &snat_main;
1721 nat_outside_fib_t *outside_fib;
1722 snat_static_mapping_t *m;
1723 snat_interface_t *i;
1730 nat_log_err ("nat44 is disabled");
1731 return VNET_API_ERROR_UNSUPPORTED;
1734 i = nat44_ed_get_interface (sm->interfaces, sw_if_index);
1737 nat_log_err ("error interface couldn't be found");
1738 return VNET_API_ERROR_NO_SUCH_ENTRY;
1741 if (nat_interface_is_inside (i) && nat_interface_is_outside (i))
1743 if (sm->num_workers > 1)
1745 del_feature_name = "nat44-handoff-classify";
1746 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1747 "nat44-out2in-worker-handoff";
1751 del_feature_name = "nat44-ed-classify";
1752 feature_name = !is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1755 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1760 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1761 sw_if_index, 0, 0, 0);
1762 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1,
1767 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1771 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1776 if (sm->num_workers > 1)
1778 feature_name = is_inside ? "nat44-in2out-worker-handoff" :
1779 "nat44-out2in-worker-handoff";
1783 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1786 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1791 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 0,
1795 pool_put (sm->interfaces, i);
1799 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1801 update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
1805 outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1808 outside_fib->refcount--;
1809 if (!outside_fib->refcount)
1811 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1815 vec_foreach (ap, sm->addresses)
1817 snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 0);
1820 pool_foreach (m, sm->static_mappings)
1822 if (!(is_sm_addr_only (m->flags)) ||
1823 (m->local_addr.as_u32 == m->external_addr.as_u32))
1827 snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 0);
1835 nat44_ed_add_output_interface (u32 sw_if_index)
1837 snat_main_t *sm = &snat_main;
1839 nat_outside_fib_t *outside_fib;
1840 snat_static_mapping_t *m;
1841 snat_interface_t *i;
1848 nat_log_err ("nat44 is disabled");
1849 return VNET_API_ERROR_UNSUPPORTED;
1852 if (nat44_ed_get_interface (sm->interfaces, sw_if_index))
1854 nat_log_err ("error interface already configured");
1855 return VNET_API_ERROR_VALUE_EXIST;
1858 if (nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index))
1860 nat_log_err ("error interface already configured");
1861 return VNET_API_ERROR_VALUE_EXIST;
1864 if (sm->num_workers > 1)
1866 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1872 rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
1878 vnet_feature_enable_disable (
1879 "ip4-unicast", "nat44-out2in-worker-handoff", sw_if_index, 1, 0, 0);
1880 vnet_feature_enable_disable ("ip4-output",
1881 "nat44-in2out-output-worker-handoff",
1882 sw_if_index, 1, 0, 0);
1886 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1892 rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 1);
1898 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
1899 sw_if_index, 1, 0, 0);
1900 vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output",
1901 sw_if_index, 1, 0, 0);
1904 nat_validate_interface_counters (sm, sw_if_index);
1906 pool_get (sm->output_feature_interfaces, i);
1907 i->sw_if_index = sw_if_index;
1909 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1910 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1913 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
1914 update_per_vrf_sessions_vec (fib_index, 0 /*is_del*/);
1916 outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
1919 outside_fib->refcount++;
1923 vec_add2 (sm->outside_fibs, outside_fib, 1);
1924 outside_fib->fib_index = fib_index;
1925 outside_fib->refcount = 1;
1928 vec_foreach (ap, sm->addresses)
1930 snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 1);
1933 pool_foreach (m, sm->static_mappings)
1935 if (!((is_sm_addr_only (m->flags))) ||
1936 (m->local_addr.as_u32 == m->external_addr.as_u32))
1940 snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 1);
1947 nat44_ed_del_output_interface (u32 sw_if_index)
1949 snat_main_t *sm = &snat_main;
1951 nat_outside_fib_t *outside_fib;
1952 snat_static_mapping_t *m;
1953 snat_interface_t *i;
1960 nat_log_err ("nat44 is disabled");
1961 return VNET_API_ERROR_UNSUPPORTED;
1964 i = nat44_ed_get_interface (sm->output_feature_interfaces, sw_if_index);
1967 nat_log_err ("error interface couldn't be found");
1968 return VNET_API_ERROR_NO_SUCH_ENTRY;
1971 if (sm->num_workers > 1)
1973 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1979 rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
1985 vnet_feature_enable_disable (
1986 "ip4-unicast", "nat44-out2in-worker-handoff", sw_if_index, 0, 0, 0);
1987 vnet_feature_enable_disable ("ip4-output",
1988 "nat44-in2out-output-worker-handoff",
1989 sw_if_index, 0, 0, 0);
1993 rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1999 rv = ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, 0);
2005 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2006 sw_if_index, 0, 0, 0);
2007 vnet_feature_enable_disable ("ip4-output", "nat-pre-in2out-output",
2008 sw_if_index, 0, 0, 0);
2012 pool_put (sm->output_feature_interfaces, i);
2015 fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, sw_if_index);
2016 update_per_vrf_sessions_vec (fib_index, 1 /*is_del*/);
2018 outside_fib = nat44_ed_get_outside_fib (sm->outside_fibs, fib_index);
2021 outside_fib->refcount--;
2022 if (!outside_fib->refcount)
2024 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2028 vec_foreach (ap, sm->addresses)
2030 snat_add_del_addr_to_fib (&ap->addr, 32, sw_if_index, 0);
2033 pool_foreach (m, sm->static_mappings)
2035 if (!((is_sm_addr_only (m->flags))) ||
2036 (m->local_addr.as_u32 == m->external_addr.as_u32))
2040 snat_add_del_addr_to_fib (&m->external_addr, 32, sw_if_index, 0);
2047 snat_set_workers (uword * bitmap)
2049 snat_main_t *sm = &snat_main;
2052 if (sm->num_workers < 2)
2053 return VNET_API_ERROR_FEATURE_DISABLED;
2055 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2056 return VNET_API_ERROR_INVALID_WORKER;
2058 vec_free (sm->workers);
2059 clib_bitmap_foreach (i, bitmap)
2061 vec_add1(sm->workers, i);
2062 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2063 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2067 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2073 nat44_ed_set_frame_queue_nelts (u32 frame_queue_nelts)
2076 snat_main_t *sm = &snat_main;
2077 sm->frame_queue_nelts = frame_queue_nelts;
2082 snat_update_outside_fib (ip4_main_t * im, uword opaque,
2083 u32 sw_if_index, u32 new_fib_index,
2086 snat_main_t *sm = &snat_main;
2087 nat_outside_fib_t *outside_fib;
2088 snat_interface_t *i;
2092 if (!sm->enabled || (new_fib_index == old_fib_index)
2093 || (!vec_len (sm->outside_fibs)))
2098 pool_foreach (i, sm->interfaces)
2100 if (i->sw_if_index == sw_if_index)
2102 if (!(nat_interface_is_outside (i)))
2108 pool_foreach (i, sm->output_feature_interfaces)
2110 if (i->sw_if_index == sw_if_index)
2112 if (!(nat_interface_is_outside (i)))
2121 vec_foreach (outside_fib, sm->outside_fibs)
2123 if (outside_fib->fib_index == old_fib_index)
2125 outside_fib->refcount--;
2126 if (!outside_fib->refcount)
2127 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2132 vec_foreach (outside_fib, sm->outside_fibs)
2134 if (outside_fib->fib_index == new_fib_index)
2136 outside_fib->refcount++;
2144 vec_add2 (sm->outside_fibs, outside_fib, 1);
2145 outside_fib->refcount = 1;
2146 outside_fib->fib_index = new_fib_index;
2151 snat_update_outside_fib (ip4_main_t * im, uword opaque,
2152 u32 sw_if_index, u32 new_fib_index,
2156 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2159 ip4_address_t * address,
2161 u32 if_address_index, u32 is_delete);
2164 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2167 ip4_address_t * address,
2169 u32 if_address_index, u32 is_delete);
2172 test_key_calc_split ()
2174 ip4_address_t l_addr;
2175 l_addr.as_u8[0] = 1;
2176 l_addr.as_u8[1] = 1;
2177 l_addr.as_u8[2] = 1;
2178 l_addr.as_u8[3] = 1;
2179 ip4_address_t r_addr;
2180 r_addr.as_u8[0] = 2;
2181 r_addr.as_u8[1] = 2;
2182 r_addr.as_u8[2] = 2;
2183 r_addr.as_u8[3] = 2;
2187 u32 fib_index = 9000001;
2188 u32 thread_index = 3000000001;
2189 u32 session_index = 3000000221;
2190 clib_bihash_kv_16_8_t kv;
2191 init_ed_kv (&kv, l_addr, l_port, r_addr, r_port, fib_index, proto,
2192 thread_index, session_index);
2193 ip4_address_t l_addr2;
2194 ip4_address_t r_addr2;
2195 clib_memset (&l_addr2, 0, sizeof (l_addr2));
2196 clib_memset (&r_addr2, 0, sizeof (r_addr2));
2201 split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
2203 ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2204 ASSERT (r_addr.as_u32 == r_addr2.as_u32);
2205 ASSERT (l_port == l_port2);
2206 ASSERT (r_port == r_port2);
2207 ASSERT (proto == proto2);
2208 ASSERT (fib_index == fib_index2);
2209 ASSERT (thread_index == ed_value_get_thread_index (&kv));
2210 ASSERT (session_index == ed_value_get_session_index (&kv));
2214 nat_protocol_t proto3 = ~0;
2215 u64 key = calc_nat_key (l_addr, l_port, fib_index, proto);
2216 split_nat_key (key, &l_addr2, &l_port2, &fib_index2, &proto3);
2217 ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2218 ASSERT (l_port == l_port2);
2219 ASSERT (proto == proto3);
2220 ASSERT (fib_index == fib_index2);
2223 static clib_error_t *
2224 nat_ip_table_add_del (vnet_main_t * vnm, u32 table_id, u32 is_add)
2229 fib_index = ip4_fib_index_from_table_id (table_id);
2230 if (fib_index != ~0)
2232 expire_per_vrf_sessions (fib_index);
2238 VNET_IP_TABLE_ADD_DEL_FUNCTION (nat_ip_table_add_del);
2241 nat44_set_node_indexes (snat_main_t * sm, vlib_main_t * vm)
2245 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2246 sm->out2in_node_index = node->index;
2248 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2249 sm->in2out_node_index = node->index;
2251 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-output");
2252 sm->in2out_output_node_index = node->index;
2255 #define nat_validate_simple_counter(c, i) \
2258 vlib_validate_simple_counter (&c, i); \
2259 vlib_zero_simple_counter (&c, i); \
2263 #define nat_init_simple_counter(c, n, sn) \
2267 c.stat_segment_name = sn; \
2268 nat_validate_simple_counter (c, 0); \
2272 static_always_inline void
2273 nat_validate_interface_counters (snat_main_t *sm, u32 sw_if_index)
2276 nat_validate_simple_counter (sm->counters.fastpath.in2out.x, sw_if_index); \
2277 nat_validate_simple_counter (sm->counters.fastpath.out2in.x, sw_if_index); \
2278 nat_validate_simple_counter (sm->counters.slowpath.in2out.x, sw_if_index); \
2279 nat_validate_simple_counter (sm->counters.slowpath.out2in.x, sw_if_index);
2280 foreach_nat_counter;
2282 nat_validate_simple_counter (sm->counters.hairpinning, sw_if_index);
2285 static clib_error_t *
2286 nat_init (vlib_main_t * vm)
2288 snat_main_t *sm = &snat_main;
2289 vlib_thread_main_t *tm = vlib_get_thread_main ();
2290 vlib_thread_registration_t *tr;
2291 ip4_add_del_interface_address_callback_t cbi = { 0 };
2292 ip4_table_bind_callback_t cbt = { 0 };
2293 u32 i, num_threads = 0;
2294 uword *p, *bitmap = 0;
2296 clib_memset (sm, 0, sizeof (*sm));
2299 sm->vnet_main = vnet_get_main ();
2301 sm->ip4_main = &ip4_main;
2302 sm->api_main = vlibapi_get_main ();
2303 sm->ip4_lookup_main = &ip4_main.lookup_main;
2305 // frame queue indices used for handoff
2306 sm->fq_out2in_index = ~0;
2307 sm->fq_in2out_index = ~0;
2308 sm->fq_in2out_output_index = ~0;
2310 sm->log_level = NAT_LOG_ERROR;
2312 nat44_set_node_indexes (sm, vm);
2314 sm->log_class = vlib_log_register_class ("nat", 0);
2315 nat_ipfix_logging_init (vm);
2317 nat_init_simple_counter (sm->total_sessions, "total-sessions",
2318 "/nat44-ed/total-sessions");
2319 sm->max_cfg_sessions_gauge = stat_segment_new_entry (
2320 (u8 *) "/nat44-ed/max-cfg-sessions", STAT_DIR_TYPE_SCALAR_INDEX);
2323 nat_init_simple_counter (sm->counters.fastpath.in2out.x, #x, \
2324 "/nat44-ed/in2out/fastpath/" #x); \
2325 nat_init_simple_counter (sm->counters.fastpath.out2in.x, #x, \
2326 "/nat44-ed/out2in/fastpath/" #x); \
2327 nat_init_simple_counter (sm->counters.slowpath.in2out.x, #x, \
2328 "/nat44-ed/in2out/slowpath/" #x); \
2329 nat_init_simple_counter (sm->counters.slowpath.out2in.x, #x, \
2330 "/nat44-ed/out2in/slowpath/" #x);
2331 foreach_nat_counter;
2333 nat_init_simple_counter (sm->counters.hairpinning, "hairpinning",
2334 "/nat44-ed/hairpinning");
2336 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2339 tr = (vlib_thread_registration_t *) p[0];
2342 sm->num_workers = tr->count;
2343 sm->first_worker_index = tr->first_index;
2346 num_threads = tm->n_vlib_mains - 1;
2347 sm->port_per_thread = 0xffff - 1024;
2348 vec_validate (sm->per_thread_data, num_threads);
2350 /* Use all available workers by default */
2351 if (sm->num_workers > 1)
2353 for (i = 0; i < sm->num_workers; i++)
2354 bitmap = clib_bitmap_set (bitmap, i, 1);
2355 snat_set_workers (bitmap);
2356 clib_bitmap_free (bitmap);
2360 sm->per_thread_data[0].snat_thread_index = 0;
2363 /* callbacks to call when interface address changes. */
2364 cbi.function = snat_ip4_add_del_interface_address_cb;
2365 vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
2366 cbi.function = nat_ip4_add_del_addr_only_sm_cb;
2367 vec_add1 (sm->ip4_main->add_del_interface_address_callbacks, cbi);
2369 /* callbacks to call when interface to table biding changes */
2370 cbt.function = snat_update_outside_fib;
2371 vec_add1 (sm->ip4_main->table_bind_callbacks, cbt);
2374 fib_source_allocate ("nat-low", FIB_SOURCE_PRIORITY_LOW,
2375 FIB_SOURCE_BH_SIMPLE);
2377 fib_source_allocate ("nat-hi", FIB_SOURCE_PRIORITY_HI,
2378 FIB_SOURCE_BH_SIMPLE);
2380 nat_affinity_init (vm);
2381 test_key_calc_split ();
2383 return nat44_api_hookup (vm);
2386 VLIB_INIT_FUNCTION (nat_init);
2389 nat44_plugin_enable (nat44_config_t c)
2391 snat_main_t *sm = &snat_main;
2395 if (c.static_mapping_only && !c.connection_tracking)
2397 nat_log_err ("unsupported combination of configuration");
2401 sm->static_mapping_only = c.static_mapping_only;
2402 sm->static_mapping_connection_tracking = c.connection_tracking;
2404 sm->forwarding_enabled = 0;
2405 sm->mss_clamping = 0;
2406 sm->pat = (!c.static_mapping_only ||
2407 (c.static_mapping_only && c.connection_tracking));
2410 c.sessions = 63 * 1024;
2412 sm->max_translations_per_thread = c.sessions;
2413 stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
2414 sm->max_translations_per_thread);
2415 sm->translation_buckets = nat_calc_bihash_buckets (c.sessions);
2417 vec_add1 (sm->max_translations_per_fib, sm->max_translations_per_thread);
2419 sm->inside_vrf_id = c.inside_vrf;
2420 sm->inside_fib_index =
2421 fib_table_find_or_create_and_lock
2422 (FIB_PROTOCOL_IP4, c.inside_vrf, sm->fib_src_hi);
2424 sm->outside_vrf_id = c.outside_vrf;
2425 sm->outside_fib_index = fib_table_find_or_create_and_lock (
2426 FIB_PROTOCOL_IP4, c.outside_vrf, sm->fib_src_hi);
2428 nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets);
2430 nat_affinity_enable ();
2432 nat_reset_timeouts (&sm->timeouts);
2434 vlib_zero_simple_counter (&sm->total_sessions, 0);
2436 if (!sm->frame_queue_nelts)
2438 sm->frame_queue_nelts = NAT_FQ_NELTS_DEFAULT;
2441 if (sm->num_workers > 1)
2443 if (sm->fq_in2out_index == ~0)
2445 sm->fq_in2out_index = vlib_frame_queue_main_init (
2446 sm->in2out_node_index, sm->frame_queue_nelts);
2448 if (sm->fq_out2in_index == ~0)
2450 sm->fq_out2in_index = vlib_frame_queue_main_init (
2451 sm->out2in_node_index, sm->frame_queue_nelts);
2453 if (sm->fq_in2out_output_index == ~0)
2455 sm->fq_in2out_output_index = vlib_frame_queue_main_init (
2456 sm->in2out_output_node_index, sm->frame_queue_nelts);
2467 nat44_addresses_free (snat_address_t ** addresses)
2470 vec_foreach (ap, *addresses)
2472 #define _(N, i, n, s) \
2473 vec_free (ap->busy_##n##_ports_per_thread);
2474 foreach_nat_protocol
2477 vec_free (*addresses);
2482 nat44_plugin_disable ()
2484 snat_main_t *sm = &snat_main;
2485 snat_interface_t *i, *pool;
2488 fail_if_disabled ();
2490 pool = pool_dup (sm->interfaces);
2491 pool_foreach (i, pool)
2493 if (nat_interface_is_inside (i))
2495 error = nat44_ed_del_interface (i->sw_if_index, 1);
2497 if (nat_interface_is_outside (i))
2499 error = nat44_ed_del_interface (i->sw_if_index, 0);
2503 nat_log_err ("error occurred while removing interface %u",
2507 pool_free (sm->interfaces);
2511 pool = pool_dup (sm->output_feature_interfaces);
2512 pool_foreach (i, pool)
2514 error = nat44_ed_del_output_interface (i->sw_if_index);
2517 nat_log_err ("error occurred while removing interface %u",
2521 pool_free (sm->output_feature_interfaces);
2523 sm->output_feature_interfaces = 0;
2525 vec_free (sm->max_translations_per_fib);
2527 nat44_ed_db_free ();
2529 nat44_addresses_free (&sm->addresses);
2530 nat44_addresses_free (&sm->twice_nat_addresses);
2532 vec_free (sm->to_resolve);
2533 vec_free (sm->auto_add_sw_if_indices);
2534 vec_free (sm->auto_add_sw_if_indices_twice_nat);
2537 sm->auto_add_sw_if_indices = 0;
2538 sm->auto_add_sw_if_indices_twice_nat = 0;
2540 sm->forwarding_enabled = 0;
2543 clib_memset (&sm->rconfig, 0, sizeof (sm->rconfig));
2549 nat44_ed_forwarding_enable_disable (u8 is_enable)
2551 snat_main_per_thread_data_t *tsm;
2552 snat_main_t *sm = &snat_main;
2555 u32 *ses_to_be_removed = 0, *ses_index;
2557 sm->forwarding_enabled = is_enable != 0;
2562 vec_foreach (tsm, sm->per_thread_data)
2564 pool_foreach (s, tsm->sessions)
2566 if (is_fwd_bypass_session (s))
2568 vec_add1 (ses_to_be_removed, s - tsm->sessions);
2571 vec_foreach (ses_index, ses_to_be_removed)
2573 s = pool_elt_at_index (tsm->sessions, ses_index[0]);
2574 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
2575 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
2578 vec_free (ses_to_be_removed);
2583 snat_free_outside_address_and_port (snat_address_t *addresses,
2584 u32 thread_index, ip4_address_t *addr,
2585 u16 port, nat_protocol_t protocol)
2587 snat_main_t *sm = &snat_main;
2590 u16 port_host_byte_order = clib_net_to_host_u16 (port);
2592 for (address_index = 0; address_index < vec_len (addresses);
2595 if (addresses[address_index].addr.as_u32 == addr->as_u32)
2599 ASSERT (address_index < vec_len (addresses));
2601 a = addresses + address_index;
2605 #define _(N, i, n, s) \
2606 case NAT_PROTOCOL_##N: \
2607 ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2608 --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2609 a->busy_##n##_ports--; \
2610 a->busy_##n##_ports_per_thread[thread_index]--; \
2612 foreach_nat_protocol
2614 default : nat_elog_info (sm, "unknown protocol");
2620 nat_set_outside_address_and_port (snat_address_t *addresses, u32 thread_index,
2621 ip4_address_t addr, u16 port,
2622 nat_protocol_t protocol)
2624 snat_main_t *sm = &snat_main;
2625 snat_address_t *a = 0;
2627 u16 port_host_byte_order = clib_net_to_host_u16 (port);
2629 for (address_index = 0; address_index < vec_len (addresses);
2632 if (addresses[address_index].addr.as_u32 != addr.as_u32)
2635 a = addresses + address_index;
2638 #define _(N, j, n, s) \
2639 case NAT_PROTOCOL_##N: \
2640 if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
2641 return VNET_API_ERROR_INSTANCE_IN_USE; \
2642 ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
2643 a->busy_##n##_ports_per_thread[thread_index]++; \
2644 a->busy_##n##_ports++; \
2646 foreach_nat_protocol
2648 default : nat_elog_info (sm, "unknown protocol");
2653 return VNET_API_ERROR_NO_SUCH_ENTRY;
2657 snat_static_mapping_match (vlib_main_t *vm, snat_main_t *sm,
2658 ip4_address_t match_addr, u16 match_port,
2659 u32 match_fib_index, nat_protocol_t match_protocol,
2660 ip4_address_t *mapping_addr, u16 *mapping_port,
2661 u32 *mapping_fib_index, u8 by_external,
2662 u8 *is_addr_only, twice_nat_type_t *twice_nat,
2663 lb_nat_type_t *lb, ip4_address_t *ext_host_addr,
2664 u8 *is_identity_nat, snat_static_mapping_t **out)
2666 clib_bihash_kv_8_8_t kv, value;
2667 clib_bihash_8_8_t *mapping_hash;
2668 snat_static_mapping_t *m;
2669 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2670 nat44_lb_addr_port_t *local;
2675 mapping_hash = &sm->static_mapping_by_local;
2676 init_nat_k (&kv, match_addr, match_port, match_fib_index,
2678 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2680 /* Try address only mapping */
2681 init_nat_k (&kv, match_addr, 0, match_fib_index, 0);
2682 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2688 mapping_hash = &sm->static_mapping_by_external;
2689 init_nat_k (&kv, match_addr, match_port, 0, match_protocol);
2690 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2692 /* Try address only mapping */
2693 init_nat_k (&kv, match_addr, 0, 0, 0);
2694 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2699 m = pool_elt_at_index (sm->static_mappings, value.value);
2703 if (is_sm_lb (m->flags))
2705 if (PREDICT_FALSE (lb != 0))
2706 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2707 if (m->affinity && !nat_affinity_find_and_lock (
2708 vm, ext_host_addr[0], match_addr,
2709 match_protocol, match_port, &backend_index))
2711 local = pool_elt_at_index (m->locals, backend_index);
2712 *mapping_addr = local->addr;
2713 *mapping_port = local->port;
2714 *mapping_fib_index = local->fib_index;
2717 // pick locals matching this worker
2718 if (PREDICT_FALSE (sm->num_workers > 1))
2720 u32 thread_index = vlib_get_thread_index ();
2721 pool_foreach_index (i, m->locals)
2723 local = pool_elt_at_index (m->locals, i);
2726 .src_address = local->addr,
2729 if (nat44_ed_get_in2out_worker_index (0, &ip, m->fib_index,
2735 ASSERT (vec_len (tmp) != 0);
2739 pool_foreach_index (i, m->locals)
2744 hi = vec_len (tmp) - 1;
2745 local = pool_elt_at_index (m->locals, tmp[hi]);
2746 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2749 mid = ((hi - lo) >> 1) + lo;
2750 local = pool_elt_at_index (m->locals, tmp[mid]);
2751 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2753 local = pool_elt_at_index (m->locals, tmp[lo]);
2754 if (!(local->prefix >= rand))
2756 *mapping_addr = local->addr;
2757 *mapping_port = local->port;
2758 *mapping_fib_index = local->fib_index;
2761 if (nat_affinity_create_and_lock (ext_host_addr[0], match_addr,
2762 match_protocol, match_port,
2763 tmp[lo], m->affinity,
2764 m->affinity_per_service_list_head_index))
2765 nat_elog_info (sm, "create affinity record failed");
2771 if (PREDICT_FALSE (lb != 0))
2773 *mapping_fib_index = m->fib_index;
2774 *mapping_addr = m->local_addr;
2775 /* Address only mapping doesn't change port */
2777 is_sm_addr_only (m->flags) ? match_port : m->local_port;
2782 *mapping_addr = m->external_addr;
2783 /* Address only mapping doesn't change port */
2785 is_sm_addr_only (m->flags) ? match_port : m->external_port;
2786 *mapping_fib_index = sm->outside_fib_index;
2790 if (PREDICT_FALSE (is_addr_only != 0))
2791 *is_addr_only = is_sm_addr_only (m->flags);
2793 if (PREDICT_FALSE (twice_nat != 0))
2795 *twice_nat = TWICE_NAT_DISABLED;
2797 if (is_sm_twice_nat (m->flags))
2799 *twice_nat = TWICE_NAT;
2801 else if (is_sm_self_twice_nat (m->flags))
2803 *twice_nat = TWICE_NAT_SELF;
2807 if (PREDICT_FALSE (is_identity_nat != 0))
2808 *is_identity_nat = is_sm_identity_nat (m->flags);
2817 nat44_ed_get_in2out_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
2818 u32 rx_fib_index, u8 is_output)
2820 snat_main_t *sm = &snat_main;
2821 u32 next_worker_index = sm->first_worker_index;
2824 clib_bihash_kv_16_8_t kv16, value16;
2826 u32 fib_index = rx_fib_index;
2829 if (PREDICT_FALSE (is_output))
2831 fib_index = sm->outside_fib_index;
2832 nat_outside_fib_t *outside_fib;
2833 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
2834 fib_prefix_t pfx = {
2835 .fp_proto = FIB_PROTOCOL_IP4,
2838 .ip4.as_u32 = ip->dst_address.as_u32,
2842 switch (vec_len (sm->outside_fibs))
2845 fib_index = sm->outside_fib_index;
2848 fib_index = sm->outside_fibs[0].fib_index;
2851 vec_foreach (outside_fib, sm->outside_fibs)
2853 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
2854 if (FIB_NODE_INDEX_INVALID != fei)
2856 if (fib_entry_get_resolving_interface (fei) != ~0)
2858 fib_index = outside_fib->fib_index;
2867 init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2868 ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2869 fib_index, ip->protocol);
2871 if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))
2873 next_worker_index = ed_value_get_thread_index (&value16);
2874 vnet_buffer2 (b)->nat.cached_session_index =
2875 ed_value_get_session_index (&value16);
2880 init_ed_k (&kv16, ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2881 ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2882 rx_fib_index, ip->protocol);
2883 if (!clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16))
2885 next_worker_index = ed_value_get_thread_index (&value16);
2886 vnet_buffer2 (b)->nat.cached_dst_nat_session_index =
2887 ed_value_get_session_index (&value16);
2892 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2893 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
2895 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2896 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2898 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2901 if (PREDICT_TRUE (!is_output))
2903 nat_elog_debug_handoff (sm, "HANDOFF IN2OUT", next_worker_index,
2905 clib_net_to_host_u32 (ip->src_address.as_u32),
2906 clib_net_to_host_u32 (ip->dst_address.as_u32));
2910 nat_elog_debug_handoff (sm, "HANDOFF IN2OUT-OUTPUT-FEATURE",
2911 next_worker_index, rx_fib_index,
2912 clib_net_to_host_u32 (ip->src_address.as_u32),
2913 clib_net_to_host_u32 (ip->dst_address.as_u32));
2916 return next_worker_index;
2920 nat44_ed_get_out2in_worker_index (vlib_buffer_t *b, ip4_header_t *ip,
2921 u32 rx_fib_index, u8 is_output)
2923 snat_main_t *sm = &snat_main;
2924 clib_bihash_kv_8_8_t kv, value;
2925 clib_bihash_kv_16_8_t kv16, value16;
2927 u32 proto, next_worker_index = 0;
2929 snat_static_mapping_t *m;
2932 proto = ip_proto_to_nat_proto (ip->protocol);
2934 if (PREDICT_FALSE (proto == NAT_PROTOCOL_ICMP))
2936 ip4_address_t lookup_saddr, lookup_daddr;
2937 u16 lookup_sport, lookup_dport;
2939 if (!nat_get_icmp_session_lookup_values (
2940 b, ip, &lookup_saddr, &lookup_sport, &lookup_daddr, &lookup_dport,
2943 init_ed_k (&kv16, lookup_saddr, lookup_sport, lookup_daddr,
2944 lookup_dport, rx_fib_index, lookup_protocol);
2946 !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)))
2948 next_worker_index = ed_value_get_thread_index (&value16);
2949 nat_elog_debug_handoff (
2950 sm, "HANDOFF OUT2IN (session)", next_worker_index,
2951 rx_fib_index, clib_net_to_host_u32 (ip->src_address.as_u32),
2952 clib_net_to_host_u32 (ip->dst_address.as_u32));
2953 return next_worker_index;
2958 init_ed_k (&kv16, ip->src_address, vnet_buffer (b)->ip.reass.l4_src_port,
2959 ip->dst_address, vnet_buffer (b)->ip.reass.l4_dst_port,
2960 rx_fib_index, ip->protocol);
2963 !clib_bihash_search_16_8 (&sm->flow_hash, &kv16, &value16)))
2965 vnet_buffer2 (b)->nat.cached_session_index =
2966 ed_value_get_session_index (&value16);
2967 next_worker_index = ed_value_get_thread_index (&value16);
2968 nat_elog_debug_handoff (sm, "HANDOFF OUT2IN (session)",
2969 next_worker_index, rx_fib_index,
2970 clib_net_to_host_u32 (ip->src_address.as_u32),
2971 clib_net_to_host_u32 (ip->dst_address.as_u32));
2972 return next_worker_index;
2975 /* first try static mappings without port */
2976 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2978 init_nat_k (&kv, ip->dst_address, 0, 0, 0);
2979 if (!clib_bihash_search_8_8
2980 (&sm->static_mapping_by_external, &kv, &value))
2982 m = pool_elt_at_index (sm->static_mappings, value.value);
2983 next_worker_index = m->workers[0];
2988 /* unknown protocol */
2989 if (PREDICT_FALSE (proto == NAT_PROTOCOL_OTHER))
2991 /* use current thread */
2992 next_worker_index = vlib_get_thread_index ();
2996 port = vnet_buffer (b)->ip.reass.l4_dst_port;
2998 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3000 udp_header_t *udp = ip4_next_header (ip);
3001 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3002 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3003 if (!icmp_type_is_error_message
3004 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3005 port = vnet_buffer (b)->ip.reass.l4_src_port;
3008 /* if error message, then it's not fragmented and we can access it */
3009 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3010 proto = ip_proto_to_nat_proto (inner_ip->protocol);
3011 void *l4_header = ip4_next_header (inner_ip);
3014 case NAT_PROTOCOL_ICMP:
3015 icmp = (icmp46_header_t *) l4_header;
3016 echo = (icmp_echo_header_t *) (icmp + 1);
3017 port = echo->identifier;
3019 case NAT_PROTOCOL_UDP:
3020 case NAT_PROTOCOL_TCP:
3021 port = ((tcp_udp_header_t *) l4_header)->src_port;
3024 next_worker_index = vlib_get_thread_index ();
3030 /* try static mappings with port */
3031 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3033 init_nat_k (&kv, ip->dst_address, port, 0, proto);
3034 if (!clib_bihash_search_8_8
3035 (&sm->static_mapping_by_external, &kv, &value))
3037 m = pool_elt_at_index (sm->static_mappings, value.value);
3038 if (!is_sm_lb (m->flags))
3040 next_worker_index = m->workers[0];
3044 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3045 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3047 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3049 m->workers[hash & (_vec_len (m->workers) - 1)];
3051 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3056 /* worker by outside port */
3057 next_worker_index = sm->first_worker_index;
3058 next_worker_index +=
3059 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3062 nat_elog_debug_handoff (sm, "HANDOFF OUT2IN", next_worker_index,
3064 clib_net_to_host_u32 (ip->src_address.as_u32),
3065 clib_net_to_host_u32 (ip->dst_address.as_u32));
3066 return next_worker_index;
3070 nat44_get_max_session_limit ()
3072 snat_main_t *sm = &snat_main;
3073 u32 max_limit = 0, len = 0;
3075 for (; len < vec_len (sm->max_translations_per_fib); len++)
3077 if (max_limit < sm->max_translations_per_fib[len])
3078 max_limit = sm->max_translations_per_fib[len];
3084 nat44_set_session_limit (u32 session_limit, u32 vrf_id)
3086 snat_main_t *sm = &snat_main;
3087 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3088 u32 len = vec_len (sm->max_translations_per_fib);
3090 if (len <= fib_index)
3092 vec_validate (sm->max_translations_per_fib, fib_index + 1);
3094 for (; len < vec_len (sm->max_translations_per_fib); len++)
3095 sm->max_translations_per_fib[len] = sm->max_translations_per_thread;
3098 sm->max_translations_per_fib[fib_index] = session_limit;
3103 nat44_update_session_limit (u32 session_limit, u32 vrf_id)
3105 snat_main_t *sm = &snat_main;
3107 if (nat44_set_session_limit (session_limit, vrf_id))
3109 sm->max_translations_per_thread = nat44_get_max_session_limit ();
3111 stat_segment_set_state_counter (sm->max_cfg_sessions_gauge,
3112 sm->max_translations_per_thread);
3114 sm->translation_buckets =
3115 nat_calc_bihash_buckets (sm->max_translations_per_thread);
3117 nat44_ed_sessions_clear ();
3122 nat44_ed_worker_db_init (snat_main_per_thread_data_t *tsm, u32 translations,
3123 u32 translation_buckets)
3127 pool_alloc (tsm->sessions, translations);
3128 pool_alloc (tsm->lru_pool, translations);
3130 pool_get (tsm->lru_pool, head);
3131 tsm->tcp_trans_lru_head_index = head - tsm->lru_pool;
3132 clib_dlist_init (tsm->lru_pool, tsm->tcp_trans_lru_head_index);
3134 pool_get (tsm->lru_pool, head);
3135 tsm->tcp_estab_lru_head_index = head - tsm->lru_pool;
3136 clib_dlist_init (tsm->lru_pool, tsm->tcp_estab_lru_head_index);
3138 pool_get (tsm->lru_pool, head);
3139 tsm->udp_lru_head_index = head - tsm->lru_pool;
3140 clib_dlist_init (tsm->lru_pool, tsm->udp_lru_head_index);
3142 pool_get (tsm->lru_pool, head);
3143 tsm->icmp_lru_head_index = head - tsm->lru_pool;
3144 clib_dlist_init (tsm->lru_pool, tsm->icmp_lru_head_index);
3146 pool_get (tsm->lru_pool, head);
3147 tsm->unk_proto_lru_head_index = head - tsm->lru_pool;
3148 clib_dlist_init (tsm->lru_pool, tsm->unk_proto_lru_head_index);
3152 reinit_ed_flow_hash ()
3154 snat_main_t *sm = &snat_main;
3155 // we expect 2 flows per session, so multiply translation_buckets by 2
3156 clib_bihash_init_16_8 (
3157 &sm->flow_hash, "ed-flow-hash",
3158 clib_max (1, sm->num_workers) * 2 * sm->translation_buckets, 0);
3159 clib_bihash_set_kvp_format_fn_16_8 (&sm->flow_hash, format_ed_session_kvp);
3163 nat44_ed_db_init (u32 translations, u32 translation_buckets)
3165 snat_main_t *sm = &snat_main;
3166 snat_main_per_thread_data_t *tsm;
3167 u32 static_mapping_buckets = 1024;
3168 u32 static_mapping_memory_size = 64 << 20;
3170 reinit_ed_flow_hash ();
3172 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3173 "static_mapping_by_local", static_mapping_buckets,
3174 static_mapping_memory_size);
3175 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
3176 format_static_mapping_kvp);
3178 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3179 "static_mapping_by_external", static_mapping_buckets,
3180 static_mapping_memory_size);
3181 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
3182 format_static_mapping_kvp);
3186 vec_foreach (tsm, sm->per_thread_data)
3188 nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
3189 sm->translation_buckets);
3195 nat44_ed_worker_db_free (snat_main_per_thread_data_t *tsm)
3197 pool_free (tsm->lru_pool);
3198 pool_free (tsm->sessions);
3199 vec_free (tsm->per_vrf_sessions_vec);
3205 snat_main_t *sm = &snat_main;
3206 snat_main_per_thread_data_t *tsm;
3208 pool_free (sm->static_mappings);
3209 clib_bihash_free_16_8 (&sm->flow_hash);
3210 clib_bihash_free_8_8 (&sm->static_mapping_by_local);
3211 clib_bihash_free_8_8 (&sm->static_mapping_by_external);
3215 vec_foreach (tsm, sm->per_thread_data)
3217 nat44_ed_worker_db_free (tsm);
3223 nat44_ed_sessions_clear ()
3225 snat_main_t *sm = &snat_main;
3226 snat_main_per_thread_data_t *tsm;
3228 reinit_ed_flow_hash ();
3232 vec_foreach (tsm, sm->per_thread_data)
3235 nat44_ed_worker_db_free (tsm);
3236 nat44_ed_worker_db_init (tsm, sm->max_translations_per_thread,
3237 sm->translation_buckets);
3240 vlib_zero_simple_counter (&sm->total_sessions, 0);
3244 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
3247 ip4_address_t * address,
3249 u32 if_address_index, u32 is_delete)
3251 snat_main_t *sm = &snat_main;
3252 snat_static_map_resolve_t *rp;
3253 snat_static_mapping_t *m;
3254 clib_bihash_kv_8_8_t kv, value;
3255 ip4_address_t l_addr;
3261 for (i = 0; i < vec_len (sm->to_resolve); i++)
3263 rp = sm->to_resolve + i;
3264 if (rp->addr_only == 0)
3266 if (rp->sw_if_index == sw_if_index)
3273 init_nat_k (&kv, *address, rp->addr_only ? 0 : rp->e_port,
3274 sm->outside_fib_index, rp->addr_only ? 0 : rp->proto);
3275 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3278 m = pool_elt_at_index (sm->static_mappings, value.value);
3282 /* Don't trip over lease renewal, static config */
3292 /* Indetity mapping? */
3293 if (rp->l_addr.as_u32 == 0)
3294 l_addr.as_u32 = address[0].as_u32;
3296 l_addr.as_u32 = rp->l_addr.as_u32;
3300 rv = nat44_ed_del_static_mapping (l_addr, address[0], rp->l_port,
3301 rp->e_port, rp->proto, rp->vrf_id, ~0,
3306 rv = nat44_ed_add_static_mapping (l_addr, address[0], rp->l_port,
3307 rp->e_port, rp->proto, rp->vrf_id, ~0,
3308 rp->flags, rp->pool_addr, rp->tag);
3312 nat_elog_notice_X1 (sm, "add_static_mapping returned %d", "i4", rv);
3317 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3320 ip4_address_t * address,
3322 u32 if_address_index, u32 is_delete)
3324 snat_main_t *sm = &snat_main;
3325 snat_static_map_resolve_t *rp;
3326 ip4_address_t l_addr;
3330 snat_address_t *addresses = sm->addresses;
3335 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
3337 if (sw_if_index == sm->auto_add_sw_if_indices[i])
3341 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
3344 addresses = sm->twice_nat_addresses;
3345 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3354 /* Don't trip over lease renewal, static config */
3355 for (j = 0; j < vec_len (addresses); j++)
3356 if (addresses[j].addr.as_u32 == address->as_u32)
3359 (void) snat_add_address (sm, address, ~0, twice_nat);
3360 /* Scan static map resolution vector */
3361 for (j = 0; j < vec_len (sm->to_resolve); j++)
3363 rp = sm->to_resolve + j;
3366 /* On this interface? */
3367 if (rp->sw_if_index == sw_if_index)
3370 // TODO: remove if not needed (handled by function)
3371 /* Indetity mapping? */
3372 if (rp->l_addr.as_u32 == 0)
3373 l_addr.as_u32 = address[0].as_u32;
3375 l_addr.as_u32 = rp->l_addr.as_u32;
3377 /* Add the static mapping */
3378 rv = nat44_ed_add_static_mapping (
3379 l_addr, address[0], rp->l_port, rp->e_port, rp->proto,
3380 rp->vrf_id, ~0, rp->flags, rp->pool_addr, rp->tag);
3383 nat_elog_notice_X1 (sm, "add_static_mapping returned %d",
3392 (void) snat_del_address (sm, address[0], 1, twice_nat);
3398 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
3401 ip4_main_t *ip4_main = sm->ip4_main;
3402 ip4_address_t *first_int_addr;
3403 snat_static_map_resolve_t *rp;
3404 u32 *indices_to_delete = 0;
3406 u32 *auto_add_sw_if_indices =
3408 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3410 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
3413 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
3415 if (auto_add_sw_if_indices[i] == sw_if_index)
3419 /* if have address remove it */
3421 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3424 for (j = 0; j < vec_len (sm->to_resolve); j++)
3426 rp = sm->to_resolve + j;
3427 if (rp->sw_if_index == sw_if_index)
3428 vec_add1 (indices_to_delete, j);
3430 if (vec_len (indices_to_delete))
3432 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3433 vec_del1 (sm->to_resolve, j);
3434 vec_free (indices_to_delete);
3438 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3440 vec_del1 (sm->auto_add_sw_if_indices, i);
3443 return VNET_API_ERROR_VALUE_EXIST;
3450 return VNET_API_ERROR_NO_SUCH_ENTRY;
3452 /* add to the auto-address list */
3454 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3456 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
3458 /* If the address is already bound - or static - add it now */
3460 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
3466 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3467 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3468 u32 vrf_id, int is_in)
3471 clib_bihash_kv_16_8_t kv, value;
3472 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3474 snat_main_per_thread_data_t *tsm;
3476 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3477 if (sm->num_workers > 1)
3478 tsm = vec_elt_at_index (
3479 sm->per_thread_data,
3480 nat44_ed_get_in2out_worker_index (0, &ip, fib_index, 0));
3482 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3484 init_ed_k (&kv, *addr, port, *eh_addr, eh_port, fib_index, proto);
3485 if (clib_bihash_search_16_8 (&sm->flow_hash, &kv, &value))
3487 return VNET_API_ERROR_NO_SUCH_ENTRY;
3490 if (pool_is_free_index (tsm->sessions, ed_value_get_session_index (&value)))
3491 return VNET_API_ERROR_UNSPECIFIED;
3492 s = pool_elt_at_index (tsm->sessions, ed_value_get_session_index (&value));
3493 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
3494 nat_ed_session_delete (sm, s, tsm - sm->per_thread_data, 1);
3498 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
3499 vlib_node_runtime_t * node,
3500 vlib_frame_t * frame)
3505 VLIB_REGISTER_NODE (nat_default_node) = {
3506 .name = "nat-default",
3507 .vector_size = sizeof (u32),
3509 .type = VLIB_NODE_TYPE_INTERNAL,
3511 .n_next_nodes = NAT_N_NEXT,
3513 [NAT_NEXT_DROP] = "error-drop",
3514 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
3515 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
3516 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
3517 [NAT_NEXT_IN2OUT_ED_OUTPUT_FAST_PATH] = "nat44-ed-in2out-output",
3518 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
3519 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
3520 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
3521 [NAT_NEXT_IN2OUT_CLASSIFY] = "nat44-in2out-worker-handoff",
3522 [NAT_NEXT_OUT2IN_CLASSIFY] = "nat44-out2in-worker-handoff",
3527 nat_6t_l3_l4_csum_calc (nat_6t_flow_t *f)
3529 f->l3_csum_delta = 0;
3530 f->l4_csum_delta = 0;
3531 if (f->ops & NAT_FLOW_OP_SADDR_REWRITE &&
3532 f->rewrite.saddr.as_u32 != f->match.saddr.as_u32)
3535 ip_csum_add_even (f->l3_csum_delta, f->rewrite.saddr.as_u32);
3537 ip_csum_sub_even (f->l3_csum_delta, f->match.saddr.as_u32);
3541 f->rewrite.saddr.as_u32 = f->match.saddr.as_u32;
3543 if (f->ops & NAT_FLOW_OP_DADDR_REWRITE &&
3544 f->rewrite.daddr.as_u32 != f->match.daddr.as_u32)
3547 ip_csum_add_even (f->l3_csum_delta, f->rewrite.daddr.as_u32);
3549 ip_csum_sub_even (f->l3_csum_delta, f->match.daddr.as_u32);
3553 f->rewrite.daddr.as_u32 = f->match.daddr.as_u32;
3555 if (f->ops & NAT_FLOW_OP_SPORT_REWRITE && f->rewrite.sport != f->match.sport)
3557 f->l4_csum_delta = ip_csum_add_even (f->l4_csum_delta, f->rewrite.sport);
3558 f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.sport);
3562 f->rewrite.sport = f->match.sport;
3564 if (f->ops & NAT_FLOW_OP_DPORT_REWRITE && f->rewrite.dport != f->match.dport)
3566 f->l4_csum_delta = ip_csum_add_even (f->l4_csum_delta, f->rewrite.dport);
3567 f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.dport);
3571 f->rewrite.dport = f->match.dport;
3573 if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE &&
3574 f->rewrite.icmp_id != f->match.sport)
3577 ip_csum_add_even (f->l4_csum_delta, f->rewrite.icmp_id);
3578 f->l4_csum_delta = ip_csum_sub_even (f->l4_csum_delta, f->match.sport);
3582 f->rewrite.icmp_id = f->match.sport;
3584 if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
3589 f->rewrite.fib_index = f->match.fib_index;
3593 static_always_inline int
3594 nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3595 ip4_header_t *ip, nat_6t_flow_t *f);
3597 static_always_inline void
3598 nat_6t_flow_ip4_translate (snat_main_t *sm, vlib_buffer_t *b, ip4_header_t *ip,
3599 nat_6t_flow_t *f, nat_protocol_t proto,
3600 int is_icmp_inner_ip4, int skip_saddr_rewrite)
3602 udp_header_t *udp = ip4_next_header (ip);
3603 tcp_header_t *tcp = (tcp_header_t *) udp;
3605 if ((NAT_PROTOCOL_TCP == proto || NAT_PROTOCOL_UDP == proto) &&
3606 !vnet_buffer (b)->ip.reass.is_non_first_fragment)
3608 if (!is_icmp_inner_ip4)
3610 ip->src_address = f->rewrite.saddr;
3611 ip->dst_address = f->rewrite.daddr;
3612 udp->src_port = f->rewrite.sport;
3613 udp->dst_port = f->rewrite.dport;
3616 { // icmp inner ip4 - reversed saddr/daddr
3617 ip->src_address = f->rewrite.daddr;
3618 ip->dst_address = f->rewrite.saddr;
3619 udp->src_port = f->rewrite.dport;
3620 udp->dst_port = f->rewrite.sport;
3623 if (NAT_PROTOCOL_TCP == proto)
3625 ip_csum_t tcp_sum = tcp->checksum;
3626 tcp_sum = ip_csum_sub_even (tcp_sum, f->l3_csum_delta);
3627 tcp_sum = ip_csum_sub_even (tcp_sum, f->l4_csum_delta);
3628 mss_clamping (sm->mss_clamping, tcp, &tcp_sum);
3629 tcp->checksum = ip_csum_fold (tcp_sum);
3631 else if (proto == NAT_PROTOCOL_UDP && udp->checksum)
3633 ip_csum_t udp_sum = udp->checksum;
3634 udp_sum = ip_csum_sub_even (udp_sum, f->l3_csum_delta);
3635 udp_sum = ip_csum_sub_even (udp_sum, f->l4_csum_delta);
3636 udp->checksum = ip_csum_fold (udp_sum);
3641 if (!is_icmp_inner_ip4)
3643 if (!skip_saddr_rewrite)
3645 ip->src_address = f->rewrite.saddr;
3647 ip->dst_address = f->rewrite.daddr;
3650 { // icmp inner ip4 - reversed saddr/daddr
3651 ip->src_address = f->rewrite.daddr;
3652 ip->dst_address = f->rewrite.saddr;
3656 if (skip_saddr_rewrite)
3658 ip->checksum = ip4_header_checksum (ip);
3662 ip_csum_t ip_sum = ip->checksum;
3663 ip_sum = ip_csum_sub_even (ip_sum, f->l3_csum_delta);
3664 ip->checksum = ip_csum_fold (ip_sum);
3666 if (0xffff == ip->checksum)
3668 ASSERT (ip4_header_checksum_is_valid (ip));
3671 static_always_inline int
3672 it_fits (vlib_main_t *vm, vlib_buffer_t *b, void *object, size_t size)
3674 int result = ((u8 *) object + size <=
3675 (u8 *) vlib_buffer_get_current (b) + b->current_length) &&
3676 vlib_object_within_buffer_data (vm, b, object, size);
3680 static_always_inline int
3681 nat_6t_flow_icmp_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3682 ip4_header_t *ip, nat_6t_flow_t *f)
3684 if (IP_PROTOCOL_ICMP != ip->protocol)
3685 return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED;
3687 icmp46_header_t *icmp = ip4_next_header (ip);
3688 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3690 if ((!vnet_buffer (b)->ip.reass.is_non_first_fragment))
3692 if (!it_fits (vm, b, icmp, sizeof (*icmp)))
3694 return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3697 ssize_t icmp_offset = (u8 *) icmp - (u8 *) vlib_buffer_get_current (b);
3699 ip_incremental_checksum (0, icmp, b->current_length - icmp_offset);
3700 sum = (u16) ~ip_csum_fold (sum);
3703 return NAT_ED_TRNSL_ERR_INVALID_CSUM;
3706 if (!icmp_type_is_error_message (icmp->type))
3708 if ((f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE) &&
3709 (f->rewrite.icmp_id != echo->identifier))
3711 ip_csum_t sum = icmp->checksum;
3712 sum = ip_csum_update (sum, echo->identifier, f->rewrite.icmp_id,
3714 identifier /* changed member */);
3715 echo->identifier = f->rewrite.icmp_id;
3716 icmp->checksum = ip_csum_fold (sum);
3721 // errors are not fragmented
3722 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3724 if (!ip4_header_checksum_is_valid (inner_ip))
3726 return NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT;
3729 nat_protocol_t inner_proto =
3730 ip_proto_to_nat_proto (inner_ip->protocol);
3732 ip_csum_t old_icmp_sum = icmp->checksum;
3733 ip_csum_t old_inner_ip_sum = inner_ip->checksum;
3734 ip_csum_t old_udp_sum;
3735 ip_csum_t old_tcp_sum;
3736 ip_csum_t new_icmp_sum;
3740 switch (inner_proto)
3742 case NAT_PROTOCOL_UDP:
3743 udp = (udp_header_t *) (inner_ip + 1);
3744 if (!it_fits (vm, b, udp, sizeof (*udp)))
3746 return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3748 old_udp_sum = udp->checksum;
3749 nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto,
3750 1 /* is_icmp_inner_ip4 */,
3751 0 /* skip_saddr_rewrite */);
3752 new_icmp_sum = ip_csum_sub_even (old_icmp_sum, f->l3_csum_delta);
3753 new_icmp_sum = ip_csum_sub_even (new_icmp_sum, f->l4_csum_delta);
3755 ip_csum_update (new_icmp_sum, old_inner_ip_sum,
3756 inner_ip->checksum, ip4_header_t, checksum);
3758 ip_csum_update (new_icmp_sum, old_udp_sum, udp->checksum,
3759 udp_header_t, checksum);
3760 new_icmp_sum = ip_csum_fold (new_icmp_sum);
3761 icmp->checksum = new_icmp_sum;
3763 case NAT_PROTOCOL_TCP:
3764 tcp = (tcp_header_t *) (inner_ip + 1);
3765 if (!it_fits (vm, b, tcp, sizeof (*tcp)))
3767 return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3769 old_tcp_sum = tcp->checksum;
3770 nat_6t_flow_ip4_translate (sm, b, inner_ip, f, inner_proto,
3771 1 /* is_icmp_inner_ip4 */,
3772 0 /* skip_saddr_rewrite */);
3773 new_icmp_sum = ip_csum_sub_even (old_icmp_sum, f->l3_csum_delta);
3774 new_icmp_sum = ip_csum_sub_even (new_icmp_sum, f->l4_csum_delta);
3776 ip_csum_update (new_icmp_sum, old_inner_ip_sum,
3777 inner_ip->checksum, ip4_header_t, checksum);
3779 ip_csum_update (new_icmp_sum, old_tcp_sum, tcp->checksum,
3780 tcp_header_t, checksum);
3781 new_icmp_sum = ip_csum_fold (new_icmp_sum);
3782 icmp->checksum = new_icmp_sum;
3784 case NAT_PROTOCOL_ICMP:
3785 if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE)
3787 icmp46_header_t *inner_icmp = ip4_next_header (inner_ip);
3788 if (!it_fits (vm, b, inner_icmp, sizeof (*inner_icmp)))
3790 return NAT_ED_TRNSL_ERR_PACKET_TRUNCATED;
3792 icmp_echo_header_t *inner_echo =
3793 (icmp_echo_header_t *) (inner_icmp + 1);
3794 if (f->rewrite.icmp_id != inner_echo->identifier)
3796 ip_csum_t sum = icmp->checksum;
3797 sum = ip_csum_update (
3798 sum, inner_echo->identifier, f->rewrite.icmp_id,
3799 icmp_echo_header_t, identifier /* changed member */);
3800 icmp->checksum = ip_csum_fold (sum);
3801 ip_csum_t inner_sum = inner_icmp->checksum;
3802 inner_sum = ip_csum_update (
3803 sum, inner_echo->identifier, f->rewrite.icmp_id,
3804 icmp_echo_header_t, identifier /* changed member */);
3805 inner_icmp->checksum = ip_csum_fold (inner_sum);
3806 inner_echo->identifier = f->rewrite.icmp_id;
3811 clib_warning ("unexpected NAT protocol value `%d'", inner_proto);
3812 return NAT_ED_TRNSL_ERR_TRANSLATION_FAILED;
3817 return NAT_ED_TRNSL_ERR_SUCCESS;
3820 static_always_inline nat_translation_error_e
3821 nat_6t_flow_buf_translate (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b,
3822 ip4_header_t *ip, nat_6t_flow_t *f,
3823 nat_protocol_t proto, int is_output_feature,
3826 if (!is_output_feature && f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
3828 vnet_buffer (b)->sw_if_index[VLIB_TX] = f->rewrite.fib_index;
3831 if (NAT_PROTOCOL_ICMP == proto)
3833 if (ip->src_address.as_u32 != f->rewrite.saddr.as_u32)
3835 // packet is returned from a router, not from destination
3836 // skip source address rewrite if in o2i path
3837 nat_6t_flow_ip4_translate (sm, b, ip, f, proto,
3838 0 /* is_icmp_inner_ip4 */,
3839 !is_i2o /* skip_saddr_rewrite */);
3843 nat_6t_flow_ip4_translate (sm, b, ip, f, proto,
3844 0 /* is_icmp_inner_ip4 */,
3845 0 /* skip_saddr_rewrite */);
3847 return nat_6t_flow_icmp_translate (vm, sm, b, ip, f);
3850 nat_6t_flow_ip4_translate (sm, b, ip, f, proto, 0 /* is_icmp_inner_ip4 */,
3851 0 /* skip_saddr_rewrite */);
3853 return NAT_ED_TRNSL_ERR_SUCCESS;
3856 nat_translation_error_e
3857 nat_6t_flow_buf_translate_i2o (vlib_main_t *vm, snat_main_t *sm,
3858 vlib_buffer_t *b, ip4_header_t *ip,
3859 nat_6t_flow_t *f, nat_protocol_t proto,
3860 int is_output_feature)
3862 return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature,
3866 nat_translation_error_e
3867 nat_6t_flow_buf_translate_o2i (vlib_main_t *vm, snat_main_t *sm,
3868 vlib_buffer_t *b, ip4_header_t *ip,
3869 nat_6t_flow_t *f, nat_protocol_t proto,
3870 int is_output_feature)
3872 return nat_6t_flow_buf_translate (vm, sm, b, ip, f, proto, is_output_feature,
3877 format_nat_6t (u8 *s, va_list *args)
3879 nat_6t_t *t = va_arg (*args, nat_6t_t *);
3881 s = format (s, "saddr %U sport %u daddr %U dport %u proto %U fib_idx %u",
3882 format_ip4_address, t->saddr.as_u8,
3883 clib_net_to_host_u16 (t->sport), format_ip4_address,
3884 t->daddr.as_u8, clib_net_to_host_u16 (t->dport),
3885 format_ip_protocol, t->proto, t->fib_index);
3890 format_nat_ed_translation_error (u8 *s, va_list *args)
3892 nat_translation_error_e e = va_arg (*args, nat_translation_error_e);
3896 case NAT_ED_TRNSL_ERR_SUCCESS:
3897 s = format (s, "success");
3899 case NAT_ED_TRNSL_ERR_TRANSLATION_FAILED:
3900 s = format (s, "translation-failed");
3902 case NAT_ED_TRNSL_ERR_FLOW_MISMATCH:
3903 s = format (s, "flow-mismatch");
3905 case NAT_ED_TRNSL_ERR_PACKET_TRUNCATED:
3906 s = format (s, "packet-truncated");
3908 case NAT_ED_TRNSL_ERR_INNER_IP_CORRUPT:
3909 s = format (s, "inner-ip-corrupted");
3911 case NAT_ED_TRNSL_ERR_INVALID_CSUM:
3912 s = format (s, "invalid-checksum");
3919 format_nat_6t_flow (u8 *s, va_list *args)
3921 nat_6t_flow_t *f = va_arg (*args, nat_6t_flow_t *);
3923 s = format (s, "match: %U ", format_nat_6t, &f->match);
3925 if (f->ops & NAT_FLOW_OP_SADDR_REWRITE)
3927 s = format (s, "rewrite: saddr %U ", format_ip4_address,
3928 f->rewrite.saddr.as_u8);
3931 if (f->ops & NAT_FLOW_OP_SPORT_REWRITE)
3935 s = format (s, "rewrite: ");
3938 s = format (s, "sport %u ", clib_net_to_host_u16 (f->rewrite.sport));
3940 if (f->ops & NAT_FLOW_OP_DADDR_REWRITE)
3944 s = format (s, "rewrite: ");
3947 s = format (s, "daddr %U ", format_ip4_address, f->rewrite.daddr.as_u8);
3949 if (f->ops & NAT_FLOW_OP_DPORT_REWRITE)
3953 s = format (s, "rewrite: ");
3956 s = format (s, "dport %u ", clib_net_to_host_u16 (f->rewrite.dport));
3958 if (f->ops & NAT_FLOW_OP_ICMP_ID_REWRITE)
3962 s = format (s, "rewrite: ");
3965 s = format (s, "icmp-id %u ", clib_net_to_host_u16 (f->rewrite.icmp_id));
3967 if (f->ops & NAT_FLOW_OP_TXFIB_REWRITE)
3971 s = format (s, "rewrite: ");
3974 s = format (s, "txfib %u ", f->rewrite.fib_index);
3980 * fd.io coding-style-patch-verification: ON
3983 * eval: (c-set-style "gnu")