blob: c1a18394aff5ee69bedfe989f0a7c3e1d7596abf [file] [log] [blame]
Dave Barach20c02cb2016-06-26 10:42:08 -04001/*
2 * snat.c - simple nat plugin
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18#include <vnet/vnet.h>
Dave Barachcab65ec2017-01-11 13:01:14 -050019#include <vnet/ip/ip.h>
20#include <vnet/ip/ip4.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040021#include <vnet/plugin/plugin.h>
Matus Fabian2ba92e32017-08-21 07:05:03 -070022#include <nat/nat.h>
Juraj Slobodacba69362017-12-19 02:09:32 +010023#include <nat/nat_dpo.h>
Matus Fabian2ba92e32017-08-21 07:05:03 -070024#include <nat/nat_ipfix_logging.h>
25#include <nat/nat_det.h>
26#include <nat/nat64.h>
Matus Fabianf2a23cc2018-01-22 03:41:53 -080027#include <nat/nat66.h>
Matus Fabian8ebe6252017-11-06 05:04:53 -080028#include <nat/dslite.h>
Matus Fabian229c1aa2018-05-28 04:09:52 -070029#include <nat/nat_inlines.h>
Matus Fabianea5b5be2018-09-03 05:02:23 -070030#include <nat/nat_affinity.h>
Matus Fabianad1f3e12018-11-28 21:26:34 -080031#include <nat/nat_syslog.h>
Matus Fabian34931eb2019-02-26 09:05:23 -080032#include <nat/nat_ha.h>
Matus Fabiane1ae29a2017-01-27 00:47:58 -080033#include <vnet/fib/fib_table.h>
34#include <vnet/fib/ip4_fib.h>
Klement Sekeraf126e742019-10-10 09:46:06 +000035#include <vnet/ip/reass/ip4_sv_reass.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040036
Damjan Marion3b46cba2017-01-23 21:13:45 +010037#include <vpp/app/version.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040038
39snat_main_t snat_main;
40
Neale Ranns3bab8f92019-12-04 06:11:00 +000041fib_source_t nat_fib_src_hi;
42fib_source_t nat_fib_src_low;
43
Matus Fabianab395ec2018-09-20 23:18:41 -070044/* *INDENT-OFF* */
Dave Barach20c02cb2016-06-26 10:42:08 -040045/* Hook up input features */
Filip Varga9a6dc8a2019-09-09 16:55:19 +020046VNET_FEATURE_INIT (nat_pre_in2out, static) = {
47 .arc_name = "ip4-unicast",
48 .node_name = "nat-pre-in2out",
Klement Sekeraf126e742019-10-10 09:46:06 +000049 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
50 "ip4-sv-reassembly-feature"),
Filip Varga9a6dc8a2019-09-09 16:55:19 +020051};
52VNET_FEATURE_INIT (nat_pre_out2in, static) = {
53 .arc_name = "ip4-unicast",
54 .node_name = "nat-pre-out2in",
55 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
Klement Sekeraf126e742019-10-10 09:46:06 +000056 "ip4-dhcp-client-detect",
57 "ip4-sv-reassembly-feature"),
Filip Varga9a6dc8a2019-09-09 16:55:19 +020058};
59VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
60 .arc_name = "ip4-unicast",
61 .node_name = "nat44-in2out-worker-handoff",
62 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
63};
64VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
65 .arc_name = "ip4-unicast",
66 .node_name = "nat44-out2in-worker-handoff",
67 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
68 "ip4-dhcp-client-detect"),
69};
Damjan Marion8b3191e2016-11-09 19:54:20 +010070VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
71 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070072 .node_name = "nat44-in2out",
Klement Sekeraf126e742019-10-10 09:46:06 +000073 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Dave Barach20c02cb2016-06-26 10:42:08 -040074};
Damjan Marion8b3191e2016-11-09 19:54:20 +010075VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
76 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070077 .node_name = "nat44-out2in",
Klement Sekeraf126e742019-10-10 09:46:06 +000078 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
Dave Barach525c9d02018-05-26 10:48:55 -040079 "ip4-dhcp-client-detect"),
Dave Barach20c02cb2016-06-26 10:42:08 -040080};
Matus Fabian36ea2d62017-10-24 04:13:49 -070081VNET_FEATURE_INIT (ip4_nat_classify, static) = {
82 .arc_name = "ip4-unicast",
83 .node_name = "nat44-classify",
Klement Sekeraf126e742019-10-10 09:46:06 +000084 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabian36ea2d62017-10-24 04:13:49 -070085};
Matus Fabian066f0342017-02-10 03:48:01 -080086VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
87 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070088 .node_name = "nat44-det-in2out",
Klement Sekeraf126e742019-10-10 09:46:06 +000089 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabian066f0342017-02-10 03:48:01 -080090};
91VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
92 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070093 .node_name = "nat44-det-out2in",
Klement Sekeraf126e742019-10-10 09:46:06 +000094 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
Matus Fabiana6110b62018-06-13 05:39:07 -070095 "ip4-dhcp-client-detect"),
Matus Fabian066f0342017-02-10 03:48:01 -080096};
Matus Fabian36ea2d62017-10-24 04:13:49 -070097VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
98 .arc_name = "ip4-unicast",
99 .node_name = "nat44-det-classify",
Klement Sekeraf126e742019-10-10 09:46:06 +0000100 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabian36ea2d62017-10-24 04:13:49 -0700101};
Matus Fabiana6110b62018-06-13 05:39:07 -0700102VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
103 .arc_name = "ip4-unicast",
104 .node_name = "nat44-ed-in2out",
Klement Sekeraf126e742019-10-10 09:46:06 +0000105 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabiana6110b62018-06-13 05:39:07 -0700106};
107VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
108 .arc_name = "ip4-unicast",
109 .node_name = "nat44-ed-out2in",
Klement Sekeraf126e742019-10-10 09:46:06 +0000110 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
Matus Fabiana6110b62018-06-13 05:39:07 -0700111 "ip4-dhcp-client-detect"),
112};
113VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
114 .arc_name = "ip4-unicast",
115 .node_name = "nat44-ed-classify",
Klement Sekeraf126e742019-10-10 09:46:06 +0000116 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabiana6110b62018-06-13 05:39:07 -0700117};
Matus Fabian36ea2d62017-10-24 04:13:49 -0700118VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
119 .arc_name = "ip4-unicast",
120 .node_name = "nat44-handoff-classify",
Klement Sekeraf126e742019-10-10 09:46:06 +0000121 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabian36ea2d62017-10-24 04:13:49 -0700122};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100123VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
124 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700125 .node_name = "nat44-in2out-fast",
Klement Sekeraf126e742019-10-10 09:46:06 +0000126 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabiandb649882016-08-26 05:45:27 -0700127};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100128VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
129 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700130 .node_name = "nat44-out2in-fast",
Klement Sekeraf126e742019-10-10 09:46:06 +0000131 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
Matus Fabiana6110b62018-06-13 05:39:07 -0700132 "ip4-dhcp-client-detect"),
Matus Fabiandb649882016-08-26 05:45:27 -0700133};
Matus Fabian161c59c2017-07-21 03:46:03 -0700134VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
135 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700136 .node_name = "nat44-hairpin-dst",
Klement Sekeraf126e742019-10-10 09:46:06 +0000137 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700138};
Matus Fabiana6110b62018-06-13 05:39:07 -0700139VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
140 .arc_name = "ip4-unicast",
141 .node_name = "nat44-ed-hairpin-dst",
Klement Sekeraf126e742019-10-10 09:46:06 +0000142 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
Matus Fabiana6110b62018-06-13 05:39:07 -0700143};
Matus Fabiandb649882016-08-26 05:45:27 -0700144
Matus Fabian93d84c92017-07-19 08:06:01 -0700145/* Hook up output features */
146VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
147 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700148 .node_name = "nat44-in2out-output",
Klement Sekeraf126e742019-10-10 09:46:06 +0000149 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700150};
Matus Fabian93d84c92017-07-19 08:06:01 -0700151VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
152 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700153 .node_name = "nat44-in2out-output-worker-handoff",
Klement Sekeraf126e742019-10-10 09:46:06 +0000154 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700155};
Matus Fabian161c59c2017-07-21 03:46:03 -0700156VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
157 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700158 .node_name = "nat44-hairpin-src",
Klement Sekeraf126e742019-10-10 09:46:06 +0000159 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700160};
Matus Fabiana6110b62018-06-13 05:39:07 -0700161VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
162 .arc_name = "ip4-output",
163 .node_name = "nat44-ed-in2out-output",
Klement Sekeraf126e742019-10-10 09:46:06 +0000164 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
Matus Fabiana6110b62018-06-13 05:39:07 -0700165};
166VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
167 .arc_name = "ip4-output",
168 .node_name = "nat44-ed-hairpin-src",
Klement Sekeraf126e742019-10-10 09:46:06 +0000169 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
Matus Fabiana6110b62018-06-13 05:39:07 -0700170};
Matus Fabian93d84c92017-07-19 08:06:01 -0700171
Matus Fabian87da4762017-10-04 08:03:56 -0700172/* Hook up ip4-local features */
173VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
174{
175 .arc_name = "ip4-local",
176 .node_name = "nat44-hairpinning",
177 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
178};
Matus Fabiana6110b62018-06-13 05:39:07 -0700179VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
180{
181 .arc_name = "ip4-local",
182 .node_name = "nat44-ed-hairpinning",
183 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
184};
Matus Fabian87da4762017-10-04 08:03:56 -0700185
Matus Fabian93d84c92017-07-19 08:06:01 -0700186
Damjan Marion3b46cba2017-01-23 21:13:45 +0100187VLIB_PLUGIN_REGISTER () = {
188 .version = VPP_BUILD_VER,
Dave Wallace1d1985d2019-04-23 15:29:50 -0400189 .description = "Network Address Translation (NAT)",
Damjan Marion3b46cba2017-01-23 21:13:45 +0100190};
191/* *INDENT-ON* */
Dave Barach20c02cb2016-06-26 10:42:08 -0400192
Matus Fabianb932d262017-12-18 05:38:24 -0800193void
Matus Fabian34931eb2019-02-26 09:05:23 -0800194nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
195 u8 is_ha)
Matus Fabianb932d262017-12-18 05:38:24 -0800196{
197 snat_session_key_t key;
198 clib_bihash_kv_8_8_t kv;
199 nat_ed_ses_key_t ed_key;
200 clib_bihash_kv_16_8_t ed_kv;
Matus Fabianb932d262017-12-18 05:38:24 -0800201 snat_main_per_thread_data_t *tsm =
202 vec_elt_at_index (sm->per_thread_data, thread_index);
203
Matus Fabian36ed73a2018-04-18 01:39:17 -0700204 if (is_fwd_bypass_session (s))
205 {
Matthew Smithaaed1702019-04-22 17:30:13 -0500206 if (snat_is_unk_proto_session (s))
207 {
208 ed_key.proto = s->in2out.port;
209 ed_key.r_port = 0;
210 ed_key.l_port = 0;
211 }
212 else
213 {
214 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
215 ed_key.l_port = s->in2out.port;
216 ed_key.r_port = s->ext_host_port;
217 }
Matus Fabian36ed73a2018-04-18 01:39:17 -0700218 ed_key.l_addr = s->in2out.addr;
219 ed_key.r_addr = s->ext_host_addr;
Matus Fabian36ed73a2018-04-18 01:39:17 -0700220 ed_key.fib_index = 0;
221 ed_kv.key[0] = ed_key.as_u64[0];
222 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700223 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +0200224 nat_elog_warn ("in2out_ed key del failed");
Matus Fabian36ed73a2018-04-18 01:39:17 -0700225 return;
226 }
227
Matus Fabiana6110b62018-06-13 05:39:07 -0700228 /* session lookup tables */
Matus Fabianb932d262017-12-18 05:38:24 -0800229 if (is_ed_session (s))
230 {
Matus Fabianea5b5be2018-09-03 05:02:23 -0700231 if (is_affinity_sessions (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700232 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
233 s->in2out.protocol, s->out2in.port);
Matus Fabianb932d262017-12-18 05:38:24 -0800234 ed_key.l_addr = s->out2in.addr;
235 ed_key.r_addr = s->ext_host_addr;
236 ed_key.fib_index = s->out2in.fib_index;
237 if (snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700238 {
239 ed_key.proto = s->in2out.port;
240 ed_key.r_port = 0;
241 ed_key.l_port = 0;
242 }
Matus Fabianb932d262017-12-18 05:38:24 -0800243 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700244 {
245 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
246 ed_key.l_port = s->out2in.port;
247 ed_key.r_port = s->ext_host_port;
248 }
Matus Fabianb932d262017-12-18 05:38:24 -0800249 ed_kv.key[0] = ed_key.as_u64[0];
250 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700251 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +0200252 nat_elog_warn ("out2in_ed key del failed");
Matus Fabianb932d262017-12-18 05:38:24 -0800253 ed_key.l_addr = s->in2out.addr;
254 ed_key.fib_index = s->in2out.fib_index;
255 if (!snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700256 ed_key.l_port = s->in2out.port;
Matus Fabianb932d262017-12-18 05:38:24 -0800257 if (is_twice_nat_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700258 {
259 ed_key.r_addr = s->ext_host_nat_addr;
260 ed_key.r_port = s->ext_host_nat_port;
261 }
Matus Fabianb932d262017-12-18 05:38:24 -0800262 ed_kv.key[0] = ed_key.as_u64[0];
263 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700264 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +0200265 nat_elog_warn ("in2out_ed key del failed");
Matus Fabianad1f3e12018-11-28 21:26:34 -0800266
Matus Fabian34931eb2019-02-26 09:05:23 -0800267 if (!is_ha)
268 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
269 &s->in2out.addr, s->in2out.port,
270 &s->ext_host_nat_addr, s->ext_host_nat_port,
271 &s->out2in.addr, s->out2in.port,
272 &s->ext_host_addr, s->ext_host_port,
273 s->in2out.protocol, is_twice_nat_session (s));
Matus Fabianb932d262017-12-18 05:38:24 -0800274 }
Matus Fabiana6110b62018-06-13 05:39:07 -0700275 else
276 {
277 kv.key = s->in2out.as_u64;
278 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +0200279 nat_elog_warn ("in2out key del failed");
Matus Fabiana6110b62018-06-13 05:39:07 -0700280 kv.key = s->out2in.as_u64;
281 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +0200282 nat_elog_warn ("out2in key del failed");
Matus Fabianad1f3e12018-11-28 21:26:34 -0800283
Matus Fabian34931eb2019-02-26 09:05:23 -0800284 if (!is_ha)
285 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
286 &s->in2out.addr, s->in2out.port,
287 &s->out2in.addr, s->out2in.port,
288 s->in2out.protocol);
Matus Fabiana6110b62018-06-13 05:39:07 -0700289 }
Matus Fabianb932d262017-12-18 05:38:24 -0800290
291 if (snat_is_unk_proto_session (s))
292 return;
293
Matus Fabian34931eb2019-02-26 09:05:23 -0800294 if (!is_ha)
295 {
296 /* log NAT event */
297 snat_ipfix_logging_nat44_ses_delete (thread_index,
298 s->in2out.addr.as_u32,
299 s->out2in.addr.as_u32,
300 s->in2out.protocol,
301 s->in2out.port,
302 s->out2in.port,
303 s->in2out.fib_index);
304
305 nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
306 s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
307 thread_index);
308 }
Matus Fabianb932d262017-12-18 05:38:24 -0800309
310 /* Twice NAT address and port for external host */
Matus Fabian70a26ac2018-05-14 06:20:28 -0700311 if (is_twice_nat_session (s))
Matus Fabianb932d262017-12-18 05:38:24 -0800312 {
shubing guo762a4932018-08-13 17:16:46 +0800313 key.protocol = s->in2out.protocol;
314 key.port = s->ext_host_nat_port;
315 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
316 snat_free_outside_address_and_port (sm->twice_nat_addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -0700317 thread_index, &key);
Matus Fabianb932d262017-12-18 05:38:24 -0800318 }
319
Matus Fabianb932d262017-12-18 05:38:24 -0800320 if (snat_is_session_static (s))
321 return;
322
Matus Fabianab395ec2018-09-20 23:18:41 -0700323 snat_free_outside_address_and_port (sm->addresses, thread_index,
324 &s->out2in);
Matus Fabianb932d262017-12-18 05:38:24 -0800325}
326
327snat_user_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700328nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
329 u32 thread_index)
Matus Fabianb932d262017-12-18 05:38:24 -0800330{
331 snat_user_t *u = 0;
332 snat_user_key_t user_key;
333 clib_bihash_kv_8_8_t kv, value;
334 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabianab395ec2018-09-20 23:18:41 -0700335 dlist_elt_t *per_user_list_head_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800336
337 user_key.addr.as_u32 = addr->as_u32;
338 user_key.fib_index = fib_index;
339 kv.key = user_key.as_u64;
340
341 /* Ever heard of the "user" = src ip4 address before? */
342 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
343 {
344 /* no, make a new one */
345 pool_get (tsm->users, u);
Dave Barachb7b92992018-10-17 10:38:51 -0400346 clib_memset (u, 0, sizeof (*u));
Matus Fabianb932d262017-12-18 05:38:24 -0800347 u->addr.as_u32 = addr->as_u32;
348 u->fib_index = fib_index;
349
350 pool_get (tsm->list_pool, per_user_list_head_elt);
351
352 u->sessions_per_user_list_head_index = per_user_list_head_elt -
Matus Fabianab395ec2018-09-20 23:18:41 -0700353 tsm->list_pool;
Matus Fabianb932d262017-12-18 05:38:24 -0800354
355 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
356
357 kv.value = u - tsm->users;
358
359 /* add user */
360 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +0200361 nat_elog_warn ("user_hash keay add failed");
Matus Fabianfd0d5082018-12-18 01:08:51 -0800362
363 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
364 pool_elts (tsm->users));
Matus Fabianb932d262017-12-18 05:38:24 -0800365 }
366 else
367 {
368 u = pool_elt_at_index (tsm->users, value.value);
369 }
370
371 return u;
372}
373
374snat_session_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700375nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
Matus Fabian34931eb2019-02-26 09:05:23 -0800376 u32 thread_index, f64 now)
Matus Fabianb932d262017-12-18 05:38:24 -0800377{
378 snat_session_t *s;
379 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
380 u32 oldest_per_user_translation_list_index, session_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700381 dlist_elt_t *oldest_per_user_translation_list_elt;
382 dlist_elt_t *per_user_translation_list_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800383
384 /* Over quota? Recycle the least recently used translation */
385 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
386 {
387 oldest_per_user_translation_list_index =
Matus Fabianab395ec2018-09-20 23:18:41 -0700388 clib_dlist_remove_head (tsm->list_pool,
389 u->sessions_per_user_list_head_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800390
391 ASSERT (oldest_per_user_translation_list_index != ~0);
392
393 /* Add it back to the end of the LRU list */
394 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700395 u->sessions_per_user_list_head_index,
396 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800397 /* Get the list element */
398 oldest_per_user_translation_list_elt =
Matus Fabianab395ec2018-09-20 23:18:41 -0700399 pool_elt_at_index (tsm->list_pool,
400 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800401
402 /* Get the session index from the list element */
403 session_index = oldest_per_user_translation_list_elt->value;
404
405 /* Get the session */
406 s = pool_elt_at_index (tsm->sessions, session_index);
Matus Fabian34931eb2019-02-26 09:05:23 -0800407 nat_free_session_data (sm, s, thread_index, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -0700408 if (snat_is_session_static (s))
409 u->nstaticsessions--;
Matus Fabian132dc492018-05-09 04:51:03 -0700410 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700411 u->nsessions--;
Matus Fabianb932d262017-12-18 05:38:24 -0800412 s->flags = 0;
413 s->total_bytes = 0;
414 s->total_pkts = 0;
Matus Fabianebdf1902018-05-04 03:57:42 -0700415 s->state = 0;
416 s->ext_host_addr.as_u32 = 0;
417 s->ext_host_port = 0;
418 s->ext_host_nat_addr.as_u32 = 0;
419 s->ext_host_nat_port = 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800420 }
421 else
422 {
423 pool_get (tsm->sessions, s);
Dave Barachb7b92992018-10-17 10:38:51 -0400424 clib_memset (s, 0, sizeof (*s));
Matus Fabianb932d262017-12-18 05:38:24 -0800425
426 /* Create list elts */
427 pool_get (tsm->list_pool, per_user_translation_list_elt);
428 clib_dlist_init (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700429 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianb932d262017-12-18 05:38:24 -0800430
431 per_user_translation_list_elt->value = s - tsm->sessions;
432 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
433 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
434
435 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700436 s->per_user_list_head_index,
437 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianad1f3e12018-11-28 21:26:34 -0800438
439 s->user_index = u - tsm->users;
Matus Fabianfd0d5082018-12-18 01:08:51 -0800440 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
441 pool_elts (tsm->sessions));
Matus Fabianb932d262017-12-18 05:38:24 -0800442 }
443
Matus Fabian34931eb2019-02-26 09:05:23 -0800444 s->ha_last_refreshed = now;
445
Matus Fabianb932d262017-12-18 05:38:24 -0800446 return s;
447}
448
Matus Fabian878c6462018-08-23 00:33:35 -0700449snat_session_t *
Matus Fabian8fdc0152018-09-24 04:41:28 -0700450nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
451 f64 now)
Matus Fabian878c6462018-08-23 00:33:35 -0700452{
453 snat_session_t *s;
454 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabian8fdc0152018-09-24 04:41:28 -0700455 dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
456 u32 oldest_index;
457 u64 sess_timeout_time;
Matus Fabian878c6462018-08-23 00:33:35 -0700458
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800459 if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
460 goto alloc_new;
461
462 oldest_index =
463 clib_dlist_remove_head (tsm->list_pool,
464 u->sessions_per_user_list_head_index);
465 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
466 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
Filip Vargae6eaa242019-11-27 17:40:29 +0100467
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800468 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
469 if (now >= sess_timeout_time)
Matus Fabian878c6462018-08-23 00:33:35 -0700470 {
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800471 clib_dlist_addtail (tsm->list_pool,
472 u->sessions_per_user_list_head_index, oldest_index);
Matus Fabian34931eb2019-02-26 09:05:23 -0800473 nat_free_session_data (sm, s, thread_index, 0);
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800474 if (snat_is_session_static (s))
475 u->nstaticsessions--;
Matus Fabian8fdc0152018-09-24 04:41:28 -0700476 else
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800477 u->nsessions--;
478 s->flags = 0;
479 s->total_bytes = 0;
480 s->total_pkts = 0;
481 s->state = 0;
482 s->ext_host_addr.as_u32 = 0;
483 s->ext_host_port = 0;
484 s->ext_host_nat_addr.as_u32 = 0;
485 s->ext_host_nat_port = 0;
486 }
487 else
488 {
489 clib_dlist_addhead (tsm->list_pool,
490 u->sessions_per_user_list_head_index, oldest_index);
491 if ((u->nsessions + u->nstaticsessions) >=
492 sm->max_translations_per_user)
Matus Fabian8fdc0152018-09-24 04:41:28 -0700493 {
Filip Vargae6e09a42019-07-31 12:45:48 +0200494 nat_elog_addr (SNAT_LOG_WARNING, "[warn] max translations per user",
495 clib_net_to_host_u32 (u->addr.as_u32));
Matus Fabian8fdc0152018-09-24 04:41:28 -0700496 snat_ipfix_logging_max_entries_per_user
Filip Varga8254ab82019-01-21 00:05:03 -0800497 (thread_index, sm->max_translations_per_user, u->addr.as_u32);
Matus Fabian8fdc0152018-09-24 04:41:28 -0700498 return 0;
499 }
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800500 else
501 {
502 alloc_new:
503 pool_get (tsm->sessions, s);
504 clib_memset (s, 0, sizeof (*s));
505
506 /* Create list elts */
507 pool_get (tsm->list_pool, per_user_translation_list_elt);
508 clib_dlist_init (tsm->list_pool,
509 per_user_translation_list_elt - tsm->list_pool);
510
511 per_user_translation_list_elt->value = s - tsm->sessions;
512 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
513 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
514
515 clib_dlist_addtail (tsm->list_pool,
516 s->per_user_list_head_index,
517 per_user_translation_list_elt - tsm->list_pool);
518 }
Matus Fabianfd0d5082018-12-18 01:08:51 -0800519
520 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
521 pool_elts (tsm->sessions));
Matus Fabian878c6462018-08-23 00:33:35 -0700522 }
523
Matus Fabian34931eb2019-02-26 09:05:23 -0800524 s->ha_last_refreshed = now;
525
Matus Fabian878c6462018-08-23 00:33:35 -0700526 return s;
527}
528
Matus Fabian066f0342017-02-10 03:48:01 -0800529void
530snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
Matus Fabianab395ec2018-09-20 23:18:41 -0700531 int is_add)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800532{
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800533 fib_prefix_t prefix = {
Matus Fabian066f0342017-02-10 03:48:01 -0800534 .fp_len = p_len,
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800535 .fp_proto = FIB_PROTOCOL_IP4,
536 .fp_addr = {
Matus Fabianab395ec2018-09-20 23:18:41 -0700537 .ip4.as_u32 = addr->as_u32,
538 },
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800539 };
Matus Fabianab395ec2018-09-20 23:18:41 -0700540 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800541
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800542 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700543 fib_table_entry_update_one_path (fib_index,
544 &prefix,
Neale Ranns3bab8f92019-12-04 06:11:00 +0000545 nat_fib_src_low,
Matus Fabianab395ec2018-09-20 23:18:41 -0700546 (FIB_ENTRY_FLAG_CONNECTED |
547 FIB_ENTRY_FLAG_LOCAL |
548 FIB_ENTRY_FLAG_EXCLUSIVE),
549 DPO_PROTO_IP4,
550 NULL,
551 sw_if_index,
552 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800553 else
Neale Ranns3bab8f92019-12-04 06:11:00 +0000554 fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800555}
556
Matus Fabianab395ec2018-09-20 23:18:41 -0700557int
558snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
559 u8 twice_nat)
Dave Barach20c02cb2016-06-26 10:42:08 -0400560{
Matus Fabianab395ec2018-09-20 23:18:41 -0700561 snat_address_t *ap;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800562 snat_interface_t *i;
Matus Fabian624b8d92017-09-12 04:15:30 -0700563 vlib_thread_main_t *tm = vlib_get_thread_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -0400564
Matus Fabiana6110b62018-06-13 05:39:07 -0700565 if (twice_nat && !sm->endpoint_dependent)
566 return VNET_API_ERROR_FEATURE_DISABLED;
567
Matus Fabian860dacc2016-10-25 04:19:26 -0700568 /* Check if address already exists */
Matus Fabianab395ec2018-09-20 23:18:41 -0700569 /* *INDENT-OFF* */
Matus Fabianb932d262017-12-18 05:38:24 -0800570 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
Matus Fabian860dacc2016-10-25 04:19:26 -0700571 {
572 if (ap->addr.as_u32 == addr->as_u32)
Matus Fabiana6110b62018-06-13 05:39:07 -0700573 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian860dacc2016-10-25 04:19:26 -0700574 }
Matus Fabianab395ec2018-09-20 23:18:41 -0700575 /* *INDENT-ON* */
Matus Fabian860dacc2016-10-25 04:19:26 -0700576
Matus Fabianb932d262017-12-18 05:38:24 -0800577 if (twice_nat)
578 vec_add2 (sm->twice_nat_addresses, ap, 1);
579 else
580 vec_add2 (sm->addresses, ap, 1);
581
Dave Barach20c02cb2016-06-26 10:42:08 -0400582 ap->addr = *addr;
Matus Fabianf8d84902017-07-23 23:41:03 -0700583 if (vrf_id != ~0)
584 ap->fib_index =
Neale Ranns15002542017-09-10 04:39:11 -0700585 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +0000586 nat_fib_src_low);
Matus Fabianf8d84902017-07-23 23:41:03 -0700587 else
588 ap->fib_index = ~0;
Matus Fabian09d96f42017-02-02 01:43:00 -0800589#define _(N, i, n, s) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700590 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
591 ap->busy_##n##_ports = 0; \
dongjuandf865202018-09-11 11:20:30 +0000592 ap->busy_##n##_ports_per_thread = 0;\
Matus Fabian624b8d92017-09-12 04:15:30 -0700593 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
Matus Fabian09d96f42017-02-02 01:43:00 -0800594 foreach_snat_protocol
595#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700596 if (twice_nat)
Matus Fabiana6110b62018-06-13 05:39:07 -0700597 return 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800598
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800599 /* Add external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -0700600 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800601 pool_foreach (i, sm->interfaces,
602 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100603 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800604 continue;
605
Matus Fabian066f0342017-02-10 03:48:01 -0800606 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
Matus Fabiandccbee32017-01-31 22:20:30 -0800607 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800608 }));
Matus Fabian93d84c92017-07-19 08:06:01 -0700609 pool_foreach (i, sm->output_feature_interfaces,
610 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100611 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -0700612 continue;
613
614 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
615 break;
616 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700617 /* *INDENT-ON* */
Matus Fabiana6110b62018-06-13 05:39:07 -0700618
619 return 0;
Dave Barach20c02cb2016-06-26 10:42:08 -0400620}
621
Matus Fabianab395ec2018-09-20 23:18:41 -0700622static int
623is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
Matus Fabian724b8152016-10-04 03:23:43 -0700624{
625 snat_static_mapping_t *m;
Matus Fabianab395ec2018-09-20 23:18:41 -0700626 /* *INDENT-OFF* */
Matus Fabian724b8152016-10-04 03:23:43 -0700627 pool_foreach (m, sm->static_mappings,
628 ({
Matus Fabianc3df1e92018-11-06 23:17:31 -0800629 if (is_addr_only_static_mapping (m) ||
630 is_out2in_only_static_mapping (m) ||
631 is_identity_static_mapping (m))
632 continue;
Matus Fabian724b8152016-10-04 03:23:43 -0700633 if (m->external_addr.as_u32 == addr.as_u32)
634 return 1;
635 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700636 /* *INDENT-ON* */
Matus Fabian724b8152016-10-04 03:23:43 -0700637
638 return 0;
639}
640
Matus Fabianab395ec2018-09-20 23:18:41 -0700641void
642increment_v4_address (ip4_address_t * a)
Dave Barach20c02cb2016-06-26 10:42:08 -0400643{
644 u32 v;
Matus Fabian2ba92e32017-08-21 07:05:03 -0700645
Matus Fabianab395ec2018-09-20 23:18:41 -0700646 v = clib_net_to_host_u32 (a->as_u32) + 1;
647 a->as_u32 = clib_host_to_net_u32 (v);
Dave Barach20c02cb2016-06-26 10:42:08 -0400648}
649
Matus Fabian2ba92e32017-08-21 07:05:03 -0700650static void
651snat_add_static_mapping_when_resolved (snat_main_t * sm,
Matus Fabianab395ec2018-09-20 23:18:41 -0700652 ip4_address_t l_addr,
653 u16 l_port,
654 u32 sw_if_index,
655 u16 e_port,
656 u32 vrf_id,
657 snat_protocol_t proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700658 int addr_only, int is_add, u8 * tag,
659 int twice_nat, int out2in_only,
660 int identity_nat)
Dave Barach8b275372017-01-16 10:54:02 -0500661{
662 snat_static_map_resolve_t *rp;
663
664 vec_add2 (sm->to_resolve, rp, 1);
665 rp->l_addr.as_u32 = l_addr.as_u32;
666 rp->l_port = l_port;
667 rp->sw_if_index = sw_if_index;
668 rp->e_port = e_port;
669 rp->vrf_id = vrf_id;
Matus Fabian09d96f42017-02-02 01:43:00 -0800670 rp->proto = proto;
Dave Barach8b275372017-01-16 10:54:02 -0500671 rp->addr_only = addr_only;
672 rp->is_add = is_add;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700673 rp->twice_nat = twice_nat;
674 rp->out2in_only = out2in_only;
675 rp->identity_nat = identity_nat;
Matus Fabian5f224992018-01-25 21:59:16 -0800676 rp->tag = vec_dup (tag);
Dave Barach8b275372017-01-16 10:54:02 -0500677}
Matus Fabianab395ec2018-09-20 23:18:41 -0700678
679static u32
680get_thread_idx_by_port (u16 e_port)
dongjuan58f50f12018-09-04 17:40:53 +0800681{
Matus Fabianab395ec2018-09-20 23:18:41 -0700682 snat_main_t *sm = &snat_main;
683 u32 thread_idx = sm->num_workers;
684 if (sm->num_workers > 1)
dongjuan58f50f12018-09-04 17:40:53 +0800685 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700686 thread_idx =
687 sm->first_worker_index +
688 sm->workers[(e_port - 1024) / sm->port_per_thread];
689 }
690 return thread_idx;
dongjuan58f50f12018-09-04 17:40:53 +0800691}
Dave Barach8b275372017-01-16 10:54:02 -0500692
Matus Fabianab395ec2018-09-20 23:18:41 -0700693int
694snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
695 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
696 u32 sw_if_index, snat_protocol_t proto, int is_add,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700697 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
698 u8 identity_nat)
Matus Fabiandb649882016-08-26 05:45:27 -0700699{
Matus Fabianab395ec2018-09-20 23:18:41 -0700700 snat_main_t *sm = &snat_main;
Matus Fabiandb649882016-08-26 05:45:27 -0700701 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -0800702 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -0700703 clib_bihash_kv_8_8_t kv, value;
704 snat_address_t *a = 0;
705 u32 fib_index = ~0;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800706 snat_interface_t *interface;
Matus Fabiandb649882016-08-26 05:45:27 -0700707 int i;
Matus Fabianb932d262017-12-18 05:38:24 -0800708 snat_main_per_thread_data_t *tsm;
Matus Fabianb793d092018-01-31 05:50:21 -0800709 snat_user_key_t u_key;
710 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -0700711 dlist_elt_t *head, *elt;
Matus Fabianb793d092018-01-31 05:50:21 -0800712 u32 elt_index, head_index;
713 u32 ses_index;
714 u64 user_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700715 snat_session_t *s;
Matus Fabianf13a8782018-04-06 02:54:40 -0700716 snat_static_map_resolve_t *rp, *rp_match = 0;
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700717 nat44_lb_addr_port_t *local;
Matus Fabianb6865082018-12-06 03:11:09 -0800718 u32 find = ~0;
Matus Fabiandb649882016-08-26 05:45:27 -0700719
Matus Fabiana6110b62018-06-13 05:39:07 -0700720 if (!sm->endpoint_dependent)
721 {
722 if (twice_nat || out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700723 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabiana6110b62018-06-13 05:39:07 -0700724 }
725
Dave Barach8b275372017-01-16 10:54:02 -0500726 /* If the external address is a specific interface address */
727 if (sw_if_index != ~0)
728 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700729 ip4_address_t *first_int_addr;
Matus Fabianea2600a2018-03-28 04:06:26 -0700730
731 for (i = 0; i < vec_len (sm->to_resolve); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -0700732 {
733 rp = sm->to_resolve + i;
734 if (rp->sw_if_index != sw_if_index ||
735 rp->l_addr.as_u32 != l_addr.as_u32 ||
736 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
737 continue;
Matus Fabianea2600a2018-03-28 04:06:26 -0700738
Matus Fabianab395ec2018-09-20 23:18:41 -0700739 if (!addr_only)
740 {
Alexander Chernavin6825bc12019-04-17 04:38:04 -0400741 if ((rp->l_port != l_port && rp->e_port != e_port)
Matus Fabianab395ec2018-09-20 23:18:41 -0700742 || rp->proto != proto)
743 continue;
744 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700745
Matus Fabianab395ec2018-09-20 23:18:41 -0700746 rp_match = rp;
747 break;
748 }
Dave Barach8b275372017-01-16 10:54:02 -0500749
750 /* Might be already set... */
Matus Fabian2ba92e32017-08-21 07:05:03 -0700751 first_int_addr = ip4_interface_first_address
Matus Fabianab395ec2018-09-20 23:18:41 -0700752 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
Dave Barach8b275372017-01-16 10:54:02 -0500753
Matus Fabianea2600a2018-03-28 04:06:26 -0700754 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700755 {
756 if (rp_match)
757 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabianea2600a2018-03-28 04:06:26 -0700758
Matus Fabianab395ec2018-09-20 23:18:41 -0700759 snat_add_static_mapping_when_resolved
760 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700761 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
Matus Fabian4772e7a2018-04-04 00:38:02 -0700762
Matus Fabianab395ec2018-09-20 23:18:41 -0700763 /* DHCP resolution required? */
764 if (first_int_addr == 0)
765 {
766 return 0;
767 }
768 else
769 {
770 e_addr.as_u32 = first_int_addr->as_u32;
771 /* Identity mapping? */
772 if (l_addr.as_u32 == 0)
773 l_addr.as_u32 = e_addr.as_u32;
774 }
775 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700776 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700777 {
778 if (!rp_match)
779 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabianea2600a2018-03-28 04:06:26 -0700780
Matus Fabianab395ec2018-09-20 23:18:41 -0700781 vec_del1 (sm->to_resolve, i);
Matus Fabianea2600a2018-03-28 04:06:26 -0700782
Matus Fabianab395ec2018-09-20 23:18:41 -0700783 if (first_int_addr)
784 {
785 e_addr.as_u32 = first_int_addr->as_u32;
786 /* Identity mapping? */
787 if (l_addr.as_u32 == 0)
788 l_addr.as_u32 = e_addr.as_u32;
789 }
790 else
791 return 0;
792 }
Dave Barach8b275372017-01-16 10:54:02 -0500793 }
794
Matus Fabiandb649882016-08-26 05:45:27 -0700795 m_key.addr = e_addr;
796 m_key.port = addr_only ? 0 : e_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800797 m_key.protocol = addr_only ? 0 : proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700798 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700799 kv.key = m_key.as_u64;
800 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
801 m = 0;
802 else
803 m = pool_elt_at_index (sm->static_mappings, value.value);
804
805 if (is_add)
806 {
807 if (m)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700808 {
809 if (is_identity_static_mapping (m))
810 {
811 /* *INDENT-OFF* */
Matus Fabianb6865082018-12-06 03:11:09 -0800812 pool_foreach (local, m->locals,
813 ({
814 if (local->vrf_id == vrf_id)
815 return VNET_API_ERROR_VALUE_EXIST;
816 }));
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700817 /* *INDENT-ON* */
Matus Fabianb6865082018-12-06 03:11:09 -0800818 pool_get (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700819 local->vrf_id = vrf_id;
820 local->fib_index =
821 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +0000822 nat_fib_src_low);
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700823 m_key.addr = m->local_addr;
824 m_key.port = m->local_port;
825 m_key.protocol = m->proto;
826 m_key.fib_index = local->fib_index;
827 kv.key = m_key.as_u64;
828 kv.value = m - sm->static_mappings;
829 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
830 return 0;
831 }
832 else
833 return VNET_API_ERROR_VALUE_EXIST;
834 }
Matus Fabiandb649882016-08-26 05:45:27 -0700835
Matus Fabianb932d262017-12-18 05:38:24 -0800836 if (twice_nat && addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700837 return VNET_API_ERROR_UNSUPPORTED;
Matus Fabianb932d262017-12-18 05:38:24 -0800838
Matus Fabiandb649882016-08-26 05:45:27 -0700839 /* Convert VRF id to FIB index */
840 if (vrf_id != ~0)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700841 fib_index =
842 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +0000843 nat_fib_src_low);
Matus Fabiandb649882016-08-26 05:45:27 -0700844 /* If not specified use inside VRF id from SNAT plugin startup config */
845 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700846 {
847 fib_index = sm->inside_fib_index;
848 vrf_id = sm->inside_vrf_id;
Neale Ranns3bab8f92019-12-04 06:11:00 +0000849 fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
Matus Fabianab395ec2018-09-20 23:18:41 -0700850 }
Matus Fabiandb649882016-08-26 05:45:27 -0700851
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700852 if (!(out2in_only || identity_nat))
Matus Fabianab395ec2018-09-20 23:18:41 -0700853 {
854 m_key.addr = l_addr;
855 m_key.port = addr_only ? 0 : l_port;
856 m_key.protocol = addr_only ? 0 : proto;
857 m_key.fib_index = fib_index;
858 kv.key = m_key.as_u64;
859 if (!clib_bihash_search_8_8
860 (&sm->static_mapping_by_local, &kv, &value))
861 return VNET_API_ERROR_VALUE_EXIST;
862 }
Matus Fabian36a62702018-04-04 03:27:43 -0700863
Matus Fabiandb649882016-08-26 05:45:27 -0700864 /* Find external address in allocated addresses and reserve port for
865 address and port pair mapping when dynamic translations enabled */
Matus Fabiane82488f2018-01-18 03:38:45 -0800866 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700867 {
868 for (i = 0; i < vec_len (sm->addresses); i++)
869 {
870 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
871 {
872 a = sm->addresses + i;
873 /* External port must be unused */
874 switch (proto)
875 {
Matus Fabian09d96f42017-02-02 01:43:00 -0800876#define _(N, j, n, s) \
877 case SNAT_PROTOCOL_##N: \
878 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
879 return VNET_API_ERROR_INVALID_VALUE; \
880 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
881 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700882 { \
883 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +0800884 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -0700885 } \
Matus Fabian09d96f42017-02-02 01:43:00 -0800886 break;
Matus Fabianab395ec2018-09-20 23:18:41 -0700887 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -0800888#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700889 default:
Filip Vargae6e09a42019-07-31 12:45:48 +0200890 nat_elog_info ("unknown protocol");
Matus Fabianab395ec2018-09-20 23:18:41 -0700891 return VNET_API_ERROR_INVALID_VALUE_2;
892 }
893 break;
894 }
895 }
896 /* External address must be allocated */
897 if (!a && (l_addr.as_u32 != e_addr.as_u32))
898 {
899 if (sw_if_index != ~0)
900 {
901 for (i = 0; i < vec_len (sm->to_resolve); i++)
902 {
903 rp = sm->to_resolve + i;
904 if (rp->addr_only)
905 continue;
906 if (rp->sw_if_index != sw_if_index &&
907 rp->l_addr.as_u32 != l_addr.as_u32 &&
908 rp->vrf_id != vrf_id && rp->l_port != l_port &&
909 rp->e_port != e_port && rp->proto != proto)
910 continue;
Matus Fabianf13a8782018-04-06 02:54:40 -0700911
Matus Fabianab395ec2018-09-20 23:18:41 -0700912 vec_del1 (sm->to_resolve, i);
913 break;
914 }
915 }
916 return VNET_API_ERROR_NO_SUCH_ENTRY;
917 }
918 }
Matus Fabiandb649882016-08-26 05:45:27 -0700919
920 pool_get (sm->static_mappings, m);
Dave Barachb7b92992018-10-17 10:38:51 -0400921 clib_memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -0800922 m->tag = vec_dup (tag);
Matus Fabiandb649882016-08-26 05:45:27 -0700923 m->local_addr = l_addr;
924 m->external_addr = e_addr;
Matus Fabianb932d262017-12-18 05:38:24 -0800925 m->twice_nat = twice_nat;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700926 if (out2in_only)
927 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
928 if (addr_only)
929 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
930 if (identity_nat)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700931 {
932 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
Matus Fabianb6865082018-12-06 03:11:09 -0800933 pool_get (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700934 local->vrf_id = vrf_id;
935 local->fib_index = fib_index;
936 }
937 else
938 {
939 m->vrf_id = vrf_id;
940 m->fib_index = fib_index;
941 }
Matus Fabiandb649882016-08-26 05:45:27 -0700942 if (!addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700943 {
944 m->local_port = l_port;
945 m->external_port = e_port;
946 m->proto = proto;
947 }
Matus Fabiandb649882016-08-26 05:45:27 -0700948
Matus Fabiana6110b62018-06-13 05:39:07 -0700949 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -0700950 {
951 ip4_header_t ip = {
952 .src_address = m->local_addr,
953 };
Filip Varga22bb4172019-08-12 14:24:39 +0200954 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
Matus Fabianab395ec2018-09-20 23:18:41 -0700955 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
956 }
Matus Fabianb932d262017-12-18 05:38:24 -0800957 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700958 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -0800959
Matus Fabiandb649882016-08-26 05:45:27 -0700960 m_key.addr = m->local_addr;
961 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800962 m_key.protocol = m->proto;
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700963 m_key.fib_index = fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -0700964 kv.key = m_key.as_u64;
965 kv.value = m - sm->static_mappings;
Matus Fabiane82488f2018-01-18 03:38:45 -0800966 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700967 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
Matus Fabiandb649882016-08-26 05:45:27 -0700968
969 m_key.addr = m->external_addr;
970 m_key.port = m->external_port;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700971 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700972 kv.key = m_key.as_u64;
973 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -0700974 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
Matus Fabianb932d262017-12-18 05:38:24 -0800975
Matus Fabianb793d092018-01-31 05:50:21 -0800976 /* Delete dynamic sessions matching local address (+ local port) */
977 if (!(sm->static_mapping_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700978 {
979 u_key.addr = m->local_addr;
980 u_key.fib_index = m->fib_index;
981 kv.key = u_key.as_u64;
982 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
983 {
984 user_index = value.value;
985 u = pool_elt_at_index (tsm->users, user_index);
986 if (u->nsessions)
987 {
988 head_index = u->sessions_per_user_list_head_index;
989 head = pool_elt_at_index (tsm->list_pool, head_index);
990 elt_index = head->next;
991 elt = pool_elt_at_index (tsm->list_pool, elt_index);
992 ses_index = elt->value;
993 while (ses_index != ~0)
994 {
995 s = pool_elt_at_index (tsm->sessions, ses_index);
996 elt = pool_elt_at_index (tsm->list_pool, elt->next);
997 ses_index = elt->value;
Matus Fabianb793d092018-01-31 05:50:21 -0800998
Matus Fabianab395ec2018-09-20 23:18:41 -0700999 if (snat_is_session_static (s))
1000 continue;
Matus Fabianb793d092018-01-31 05:50:21 -08001001
Matus Fabianab395ec2018-09-20 23:18:41 -07001002 if (!addr_only
1003 && (clib_net_to_host_u16 (s->in2out.port) !=
1004 m->local_port))
1005 continue;
Matus Fabianb793d092018-01-31 05:50:21 -08001006
Matus Fabianab395ec2018-09-20 23:18:41 -07001007 nat_free_session_data (sm, s,
Matus Fabian34931eb2019-02-26 09:05:23 -08001008 tsm - sm->per_thread_data, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -07001009 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb793d092018-01-31 05:50:21 -08001010
Matus Fabianab395ec2018-09-20 23:18:41 -07001011 if (!addr_only && !sm->endpoint_dependent)
1012 break;
1013 }
1014 }
1015 }
1016 }
Matus Fabiandb649882016-08-26 05:45:27 -07001017 }
1018 else
1019 {
1020 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001021 {
1022 if (sw_if_index != ~0)
1023 return 0;
1024 else
1025 return VNET_API_ERROR_NO_SUCH_ENTRY;
1026 }
Matus Fabiandb649882016-08-26 05:45:27 -07001027
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001028 if (identity_nat)
1029 {
Matus Fabianc3df1e92018-11-06 23:17:31 -08001030 if (vrf_id == ~0)
1031 vrf_id = sm->inside_vrf_id;
1032
Matus Fabianb6865082018-12-06 03:11:09 -08001033 /* *INDENT-OFF* */
1034 pool_foreach (local, m->locals,
1035 ({
1036 if (local->vrf_id == vrf_id)
1037 find = local - m->locals;
1038 }));
1039 /* *INDENT-ON* */
1040 if (find == ~0)
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001041 return VNET_API_ERROR_NO_SUCH_ENTRY;
1042
Matus Fabianb6865082018-12-06 03:11:09 -08001043 local = pool_elt_at_index (m->locals, find);
1044 fib_index = local->fib_index;
1045 pool_put (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001046 }
1047 else
1048 fib_index = m->fib_index;
1049
Matus Fabiandb649882016-08-26 05:45:27 -07001050 /* Free external address port */
Matus Fabiane82488f2018-01-18 03:38:45 -08001051 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001052 {
1053 for (i = 0; i < vec_len (sm->addresses); i++)
1054 {
1055 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1056 {
1057 a = sm->addresses + i;
1058 switch (proto)
1059 {
Matus Fabian09d96f42017-02-02 01:43:00 -08001060#define _(N, j, n, s) \
1061 case SNAT_PROTOCOL_##N: \
1062 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1063 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001064 { \
1065 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +08001066 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001067 } \
Matus Fabian09d96f42017-02-02 01:43:00 -08001068 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001069 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -08001070#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001071 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02001072 nat_elog_info ("unknown protocol");
Matus Fabianab395ec2018-09-20 23:18:41 -07001073 return VNET_API_ERROR_INVALID_VALUE_2;
1074 }
1075 break;
1076 }
1077 }
1078 }
Matus Fabiandb649882016-08-26 05:45:27 -07001079
Matus Fabianb932d262017-12-18 05:38:24 -08001080 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001081 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
Matus Fabianb932d262017-12-18 05:38:24 -08001082 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001083 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -08001084
Matus Fabiandb649882016-08-26 05:45:27 -07001085 m_key.addr = m->local_addr;
1086 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -08001087 m_key.protocol = m->proto;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001088 m_key.fib_index = fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -07001089 kv.key = m_key.as_u64;
Matus Fabiane82488f2018-01-18 03:38:45 -08001090 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -07001091 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
Matus Fabiandb649882016-08-26 05:45:27 -07001092
Matus Fabiandb649882016-08-26 05:45:27 -07001093 /* Delete session(s) for static mapping if exist */
1094 if (!(sm->static_mapping_only) ||
Matus Fabianab395ec2018-09-20 23:18:41 -07001095 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1096 {
1097 u_key.addr = m->local_addr;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001098 u_key.fib_index = fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07001099 kv.key = u_key.as_u64;
1100 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1101 {
1102 user_index = value.value;
1103 u = pool_elt_at_index (tsm->users, user_index);
1104 if (u->nstaticsessions)
1105 {
1106 head_index = u->sessions_per_user_list_head_index;
1107 head = pool_elt_at_index (tsm->list_pool, head_index);
1108 elt_index = head->next;
1109 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1110 ses_index = elt->value;
1111 while (ses_index != ~0)
1112 {
1113 s = pool_elt_at_index (tsm->sessions, ses_index);
1114 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1115 ses_index = elt->value;
Matus Fabiandb649882016-08-26 05:45:27 -07001116
Matus Fabianab395ec2018-09-20 23:18:41 -07001117 if (!addr_only)
1118 {
1119 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1120 (clib_net_to_host_u16 (s->out2in.port) !=
1121 e_port))
1122 continue;
1123 }
Matus Fabian13c08182018-04-11 00:36:57 -07001124
Matus Fabianab395ec2018-09-20 23:18:41 -07001125 if (is_lb_session (s))
1126 continue;
Matus Fabian475f0552016-10-19 06:17:52 -07001127
Matus Fabianab395ec2018-09-20 23:18:41 -07001128 if (!snat_is_session_static (s))
1129 continue;
Matus Fabian70a26ac2018-05-14 06:20:28 -07001130
Matus Fabianab395ec2018-09-20 23:18:41 -07001131 nat_free_session_data (sm, s,
Matus Fabian34931eb2019-02-26 09:05:23 -08001132 tsm - sm->per_thread_data, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -07001133 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabiandb649882016-08-26 05:45:27 -07001134
Matus Fabianab395ec2018-09-20 23:18:41 -07001135 if (!addr_only && !sm->endpoint_dependent)
1136 break;
1137 }
1138 }
1139 }
1140 }
Matus Fabiandb649882016-08-26 05:45:27 -07001141
Neale Ranns3bab8f92019-12-04 06:11:00 +00001142 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
Matus Fabianb6865082018-12-06 03:11:09 -08001143 if (pool_elts (m->locals))
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001144 return 0;
1145
1146 m_key.addr = m->external_addr;
1147 m_key.port = m->external_port;
1148 m_key.fib_index = 0;
1149 kv.key = m_key.as_u64;
1150 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1151
Matus Fabian5f224992018-01-25 21:59:16 -08001152 vec_free (m->tag);
Matus Fabiana6110b62018-06-13 05:39:07 -07001153 vec_free (m->workers);
Matus Fabiandb649882016-08-26 05:45:27 -07001154 /* Delete static mapping from pool */
1155 pool_put (sm->static_mappings, m);
1156 }
1157
Matus Fabianab7a8052017-11-28 04:29:41 -08001158 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001159 return 0;
1160
1161 /* Add/delete external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001162 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001163 pool_foreach (interface, sm->interfaces,
1164 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001165 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001166 continue;
1167
Matus Fabian066f0342017-02-10 03:48:01 -08001168 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
Matus Fabiandccbee32017-01-31 22:20:30 -08001169 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001170 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001171 pool_foreach (interface, sm->output_feature_interfaces,
1172 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001173 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001174 continue;
1175
1176 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1177 break;
1178 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001179 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001180
Matus Fabiandb649882016-08-26 05:45:27 -07001181 return 0;
1182}
1183
Matus Fabianab395ec2018-09-20 23:18:41 -07001184int
1185nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1186 snat_protocol_t proto,
1187 nat44_lb_addr_port_t * locals, u8 is_add,
1188 twice_nat_type_t twice_nat, u8 out2in_only,
1189 u8 * tag, u32 affinity)
Matus Fabian704018c2017-09-04 02:17:18 -07001190{
Matus Fabianab395ec2018-09-20 23:18:41 -07001191 snat_main_t *sm = &snat_main;
Matus Fabian704018c2017-09-04 02:17:18 -07001192 snat_static_mapping_t *m;
1193 snat_session_key_t m_key;
1194 clib_bihash_kv_8_8_t kv, value;
Matus Fabian704018c2017-09-04 02:17:18 -07001195 snat_address_t *a = 0;
1196 int i;
1197 nat44_lb_addr_port_t *local;
Matus Fabiana6110b62018-06-13 05:39:07 -07001198 u32 elt_index, head_index, ses_index;
Matus Fabian092b3cd2017-09-19 05:42:38 -07001199 snat_main_per_thread_data_t *tsm;
Matus Fabianb932d262017-12-18 05:38:24 -08001200 snat_user_key_t u_key;
1201 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -07001202 snat_session_t *s;
1203 dlist_elt_t *head, *elt;
Matus Fabiana6110b62018-06-13 05:39:07 -07001204 uword *bitmap = 0;
1205
1206 if (!sm->endpoint_dependent)
1207 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian704018c2017-09-04 02:17:18 -07001208
1209 m_key.addr = e_addr;
1210 m_key.port = e_port;
1211 m_key.protocol = proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001212 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001213 kv.key = m_key.as_u64;
1214 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1215 m = 0;
1216 else
1217 m = pool_elt_at_index (sm->static_mappings, value.value);
1218
1219 if (is_add)
1220 {
1221 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001222 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian704018c2017-09-04 02:17:18 -07001223
1224 if (vec_len (locals) < 2)
Matus Fabianab395ec2018-09-20 23:18:41 -07001225 return VNET_API_ERROR_INVALID_VALUE;
Matus Fabian704018c2017-09-04 02:17:18 -07001226
Matus Fabian704018c2017-09-04 02:17:18 -07001227 /* Find external address in allocated addresses and reserve port for
1228 address and port pair mapping when dynamic translations enabled */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001229 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001230 {
1231 for (i = 0; i < vec_len (sm->addresses); i++)
1232 {
1233 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1234 {
1235 a = sm->addresses + i;
1236 /* External port must be unused */
1237 switch (proto)
1238 {
Matus Fabian704018c2017-09-04 02:17:18 -07001239#define _(N, j, n, s) \
1240 case SNAT_PROTOCOL_##N: \
1241 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1242 return VNET_API_ERROR_INVALID_VALUE; \
1243 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1244 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001245 { \
1246 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +08001247 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001248 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001249 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001250 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001251#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001252 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02001253 nat_elog_info ("unknown protocol");
Matus Fabianab395ec2018-09-20 23:18:41 -07001254 return VNET_API_ERROR_INVALID_VALUE_2;
1255 }
1256 break;
1257 }
1258 }
1259 /* External address must be allocated */
1260 if (!a)
1261 return VNET_API_ERROR_NO_SUCH_ENTRY;
1262 }
Matus Fabian704018c2017-09-04 02:17:18 -07001263
1264 pool_get (sm->static_mappings, m);
Dave Barachb7b92992018-10-17 10:38:51 -04001265 clib_memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -08001266 m->tag = vec_dup (tag);
Matus Fabian704018c2017-09-04 02:17:18 -07001267 m->external_addr = e_addr;
Matus Fabian704018c2017-09-04 02:17:18 -07001268 m->external_port = e_port;
1269 m->proto = proto;
Matus Fabianb932d262017-12-18 05:38:24 -08001270 m->twice_nat = twice_nat;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001271 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001272 if (out2in_only)
1273 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
Matus Fabianea5b5be2018-09-03 05:02:23 -07001274 m->affinity = affinity;
1275
1276 if (affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001277 m->affinity_per_service_list_head_index =
1278 nat_affinity_get_per_service_list_head_index ();
Matus Fabianea5b5be2018-09-03 05:02:23 -07001279 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001280 m->affinity_per_service_list_head_index = ~0;
Matus Fabian704018c2017-09-04 02:17:18 -07001281
1282 m_key.addr = m->external_addr;
1283 m_key.port = m->external_port;
1284 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001285 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001286 kv.key = m_key.as_u64;
1287 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -07001288 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1289 {
Filip Vargae6e09a42019-07-31 12:45:48 +02001290 nat_elog_err ("static_mapping_by_external key add failed");
Matus Fabianab395ec2018-09-20 23:18:41 -07001291 return VNET_API_ERROR_UNSPECIFIED;
1292 }
Matus Fabian704018c2017-09-04 02:17:18 -07001293
Matus Fabian092b3cd2017-09-19 05:42:38 -07001294 m_key.fib_index = m->fib_index;
Matus Fabian704018c2017-09-04 02:17:18 -07001295 for (i = 0; i < vec_len (locals); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -07001296 {
1297 locals[i].fib_index =
1298 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1299 locals[i].vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +00001300 nat_fib_src_low);
Matus Fabianab395ec2018-09-20 23:18:41 -07001301 m_key.addr = locals[i].addr;
1302 m_key.fib_index = locals[i].fib_index;
1303 if (!out2in_only)
1304 {
1305 m_key.port = locals[i].port;
1306 kv.key = m_key.as_u64;
1307 kv.value = m - sm->static_mappings;
1308 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1309 }
1310 locals[i].prefix = (i == 0) ? locals[i].probability :
1311 (locals[i - 1].prefix + locals[i].probability);
Matus Fabianb6865082018-12-06 03:11:09 -08001312 pool_get (m->locals, local);
1313 *local = locals[i];
Matus Fabianab395ec2018-09-20 23:18:41 -07001314 if (sm->num_workers > 1)
1315 {
1316 ip4_header_t ip = {
1317 .src_address = locals[i].addr,
1318 };
1319 bitmap =
1320 clib_bitmap_set (bitmap,
Filip Varga22bb4172019-08-12 14:24:39 +02001321 sm->worker_in2out_cb (&ip, m->fib_index, 0),
1322 1);
Matus Fabianab395ec2018-09-20 23:18:41 -07001323 }
1324 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001325
1326 /* Assign workers */
1327 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001328 {
1329 /* *INDENT-OFF* */
Matus Fabiana6110b62018-06-13 05:39:07 -07001330 clib_bitmap_foreach (i, bitmap,
1331 ({
1332 vec_add1(m->workers, i);
1333 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001334 /* *INDENT-ON* */
1335 }
Matus Fabian704018c2017-09-04 02:17:18 -07001336 }
1337 else
1338 {
1339 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001340 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabian704018c2017-09-04 02:17:18 -07001341
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001342 if (!is_lb_static_mapping (m))
1343 return VNET_API_ERROR_INVALID_VALUE;
1344
Matus Fabian704018c2017-09-04 02:17:18 -07001345 /* Free external address port */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001346 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001347 {
1348 for (i = 0; i < vec_len (sm->addresses); i++)
1349 {
1350 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1351 {
1352 a = sm->addresses + i;
1353 switch (proto)
1354 {
Matus Fabian704018c2017-09-04 02:17:18 -07001355#define _(N, j, n, s) \
1356 case SNAT_PROTOCOL_##N: \
1357 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1358 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001359 { \
1360 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +08001361 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001362 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001363 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001364 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001365#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001366 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02001367 nat_elog_info ("unknown protocol");
Matus Fabianab395ec2018-09-20 23:18:41 -07001368 return VNET_API_ERROR_INVALID_VALUE_2;
1369 }
1370 break;
1371 }
1372 }
1373 }
Matus Fabian704018c2017-09-04 02:17:18 -07001374
1375 m_key.addr = m->external_addr;
1376 m_key.port = m->external_port;
1377 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001378 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001379 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07001380 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1381 {
Filip Vargae6e09a42019-07-31 12:45:48 +02001382 nat_elog_err ("static_mapping_by_external key del failed");
Matus Fabianab395ec2018-09-20 23:18:41 -07001383 return VNET_API_ERROR_UNSPECIFIED;
1384 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001385
Matus Fabianab395ec2018-09-20 23:18:41 -07001386 /* *INDENT-OFF* */
Matus Fabianb6865082018-12-06 03:11:09 -08001387 pool_foreach (local, m->locals,
1388 ({
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001389 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
Neale Ranns3bab8f92019-12-04 06:11:00 +00001390 nat_fib_src_low);
Matus Fabian704018c2017-09-04 02:17:18 -07001391 m_key.addr = local->addr;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001392 if (!out2in_only)
Matus Fabian704018c2017-09-04 02:17:18 -07001393 {
Matus Fabian240b5ef2018-01-11 04:09:17 -08001394 m_key.port = local->port;
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001395 m_key.fib_index = local->fib_index;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001396 kv.key = m_key.as_u64;
1397 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1398 {
Filip Vargae6e09a42019-07-31 12:45:48 +02001399 nat_elog_err ("static_mapping_by_local key del failed");
Matus Fabian240b5ef2018-01-11 04:09:17 -08001400 return VNET_API_ERROR_UNSPECIFIED;
1401 }
Matus Fabian704018c2017-09-04 02:17:18 -07001402 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001403
Matus Fabiana6110b62018-06-13 05:39:07 -07001404 if (sm->num_workers > 1)
Matus Fabian704018c2017-09-04 02:17:18 -07001405 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001406 ip4_header_t ip = {
1407 .src_address = local->addr,
1408 };
1409 tsm = vec_elt_at_index (sm->per_thread_data,
Filip Varga22bb4172019-08-12 14:24:39 +02001410 sm->worker_in2out_cb (&ip, m->fib_index, 0));
Matus Fabian704018c2017-09-04 02:17:18 -07001411 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001412 else
1413 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1414
Matus Fabianb932d262017-12-18 05:38:24 -08001415 /* Delete sessions */
1416 u_key.addr = local->addr;
Matus Fabianb6865082018-12-06 03:11:09 -08001417 u_key.fib_index = local->fib_index;
Matus Fabianb932d262017-12-18 05:38:24 -08001418 kv.key = u_key.as_u64;
1419 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1420 {
1421 u = pool_elt_at_index (tsm->users, value.value);
1422 if (u->nstaticsessions)
1423 {
1424 head_index = u->sessions_per_user_list_head_index;
1425 head = pool_elt_at_index (tsm->list_pool, head_index);
1426 elt_index = head->next;
1427 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1428 ses_index = elt->value;
1429 while (ses_index != ~0)
1430 {
1431 s = pool_elt_at_index (tsm->sessions, ses_index);
1432 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1433 ses_index = elt->value;
1434
Matus Fabian13c08182018-04-11 00:36:57 -07001435 if (!(is_lb_session (s)))
1436 continue;
1437
shubing guo060c3a72018-08-10 13:59:50 +08001438 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
Matus Fabianb932d262017-12-18 05:38:24 -08001439 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1440 continue;
1441
Matus Fabian34931eb2019-02-26 09:05:23 -08001442 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
Matus Fabian229c1aa2018-05-28 04:09:52 -07001443 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb932d262017-12-18 05:38:24 -08001444 }
1445 }
1446 }
Matus Fabianb6865082018-12-06 03:11:09 -08001447 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001448 /* *INDENT-ON* */
Matus Fabianea5b5be2018-09-03 05:02:23 -07001449 if (m->affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001450 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
Matus Fabianb6865082018-12-06 03:11:09 -08001451 pool_free (m->locals);
Matus Fabianab395ec2018-09-20 23:18:41 -07001452 vec_free (m->tag);
1453 vec_free (m->workers);
Matus Fabian704018c2017-09-04 02:17:18 -07001454
1455 pool_put (sm->static_mappings, m);
1456 }
1457
1458 return 0;
1459}
1460
Matus Fabianb932d262017-12-18 05:38:24 -08001461int
Matus Fabianb6865082018-12-06 03:11:09 -08001462nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1463 ip4_address_t l_addr, u16 l_port,
1464 snat_protocol_t proto, u32 vrf_id,
1465 u8 probability, u8 is_add)
1466{
1467 snat_main_t *sm = &snat_main;
1468 snat_static_mapping_t *m = 0;
1469 snat_session_key_t m_key;
1470 clib_bihash_kv_8_8_t kv, value;
1471 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1472 snat_main_per_thread_data_t *tsm;
1473 snat_user_key_t u_key;
1474 snat_user_t *u;
1475 snat_session_t *s;
1476 dlist_elt_t *head, *elt;
1477 u32 elt_index, head_index, ses_index, *locals = 0;
1478 uword *bitmap = 0;
1479 int i;
1480
1481 if (!sm->endpoint_dependent)
1482 return VNET_API_ERROR_FEATURE_DISABLED;
1483
1484 m_key.addr = e_addr;
1485 m_key.port = e_port;
1486 m_key.protocol = proto;
1487 m_key.fib_index = 0;
1488 kv.key = m_key.as_u64;
1489 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1490 m = pool_elt_at_index (sm->static_mappings, value.value);
1491
1492 if (!m)
1493 return VNET_API_ERROR_NO_SUCH_ENTRY;
1494
1495 if (!is_lb_static_mapping (m))
1496 return VNET_API_ERROR_INVALID_VALUE;
1497
1498 /* *INDENT-OFF* */
1499 pool_foreach (local, m->locals,
1500 ({
1501 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1502 (local->vrf_id == vrf_id))
1503 {
1504 match_local = local;
1505 break;
1506 }
1507 }));
1508 /* *INDENT-ON* */
1509
1510 if (is_add)
1511 {
1512 if (match_local)
1513 return VNET_API_ERROR_VALUE_EXIST;
1514
1515 pool_get (m->locals, local);
1516 clib_memset (local, 0, sizeof (*local));
1517 local->addr.as_u32 = l_addr.as_u32;
1518 local->port = l_port;
1519 local->probability = probability;
1520 local->vrf_id = vrf_id;
1521 local->fib_index =
1522 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +00001523 nat_fib_src_low);
Matus Fabianb6865082018-12-06 03:11:09 -08001524
1525 if (!is_out2in_only_static_mapping (m))
1526 {
1527 m_key.addr = l_addr;
1528 m_key.port = l_port;
1529 m_key.fib_index = local->fib_index;
1530 kv.key = m_key.as_u64;
1531 kv.value = m - sm->static_mappings;
1532 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +02001533 nat_elog_err ("static_mapping_by_local key add failed");
Matus Fabianb6865082018-12-06 03:11:09 -08001534 }
1535 }
1536 else
1537 {
1538 if (!match_local)
1539 return VNET_API_ERROR_NO_SUCH_ENTRY;
1540
1541 if (pool_elts (m->locals) < 3)
1542 return VNET_API_ERROR_UNSPECIFIED;
1543
1544 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
Neale Ranns3bab8f92019-12-04 06:11:00 +00001545 nat_fib_src_low);
Matus Fabianb6865082018-12-06 03:11:09 -08001546
1547 if (!is_out2in_only_static_mapping (m))
1548 {
1549 m_key.addr = l_addr;
1550 m_key.port = l_port;
1551 m_key.fib_index = match_local->fib_index;
1552 kv.key = m_key.as_u64;
1553 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
Filip Vargae6e09a42019-07-31 12:45:48 +02001554 nat_elog_err ("static_mapping_by_local key del failed");
Matus Fabianb6865082018-12-06 03:11:09 -08001555 }
1556
1557 if (sm->num_workers > 1)
1558 {
1559 ip4_header_t ip = {
1560 .src_address = local->addr,
1561 };
1562 tsm = vec_elt_at_index (sm->per_thread_data,
Filip Varga22bb4172019-08-12 14:24:39 +02001563 sm->worker_in2out_cb (&ip, m->fib_index,
1564 0));
Matus Fabianb6865082018-12-06 03:11:09 -08001565 }
1566 else
1567 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1568
1569 /* Delete sessions */
1570 u_key.addr = match_local->addr;
1571 u_key.fib_index = match_local->fib_index;
1572 kv.key = u_key.as_u64;
1573 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1574 {
1575 u = pool_elt_at_index (tsm->users, value.value);
1576 if (u->nstaticsessions)
1577 {
1578 head_index = u->sessions_per_user_list_head_index;
1579 head = pool_elt_at_index (tsm->list_pool, head_index);
1580 elt_index = head->next;
1581 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1582 ses_index = elt->value;
1583 while (ses_index != ~0)
1584 {
1585 s = pool_elt_at_index (tsm->sessions, ses_index);
1586 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1587 ses_index = elt->value;
1588
1589 if (!(is_lb_session (s)))
1590 continue;
1591
1592 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1593 (clib_net_to_host_u16 (s->in2out.port) !=
1594 match_local->port))
1595 continue;
1596
Matus Fabian34931eb2019-02-26 09:05:23 -08001597 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
Matus Fabianb6865082018-12-06 03:11:09 -08001598 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1599 }
1600 }
1601 }
1602
1603 pool_put (m->locals, match_local);
1604 }
1605
1606 vec_free (m->workers);
1607
1608 /* *INDENT-OFF* */
1609 pool_foreach (local, m->locals,
1610 ({
1611 vec_add1 (locals, local - m->locals);
1612 if (sm->num_workers > 1)
1613 {
1614 ip4_header_t ip;
1615 ip.src_address.as_u32 = local->addr.as_u32,
1616 bitmap = clib_bitmap_set (bitmap,
Filip Varga22bb4172019-08-12 14:24:39 +02001617 sm->worker_in2out_cb (&ip, local->fib_index, 0),
Matus Fabianb6865082018-12-06 03:11:09 -08001618 1);
1619 }
1620 }));
1621 /* *INDENT-ON* */
1622
Matus Fabiand2bad812018-12-21 04:01:00 -08001623 ASSERT (vec_len (locals) > 1);
1624
Matus Fabianb6865082018-12-06 03:11:09 -08001625 local = pool_elt_at_index (m->locals, locals[0]);
1626 local->prefix = local->probability;
1627 for (i = 1; i < vec_len (locals); i++)
1628 {
1629 local = pool_elt_at_index (m->locals, locals[i]);
1630 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1631 local->prefix = local->probability + prev_local->prefix;
1632 }
1633
1634 /* Assign workers */
1635 if (sm->num_workers > 1)
1636 {
1637 /* *INDENT-OFF* */
1638 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1639 /* *INDENT-ON* */
1640 }
1641
1642 return 0;
1643}
1644
1645int
Matus Fabianab395ec2018-09-20 23:18:41 -07001646snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1647 u8 twice_nat)
Matus Fabian36532bd2017-01-23 23:42:28 -08001648{
1649 snat_address_t *a = 0;
1650 snat_session_t *ses;
1651 u32 *ses_to_be_removed = 0, *ses_index;
Matus Fabian36532bd2017-01-23 23:42:28 -08001652 snat_main_per_thread_data_t *tsm;
1653 snat_static_mapping_t *m;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001654 snat_interface_t *interface;
Matus Fabian36532bd2017-01-23 23:42:28 -08001655 int i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001656 snat_address_t *addresses =
1657 twice_nat ? sm->twice_nat_addresses : sm->addresses;
Matus Fabian36532bd2017-01-23 23:42:28 -08001658
1659 /* Find SNAT address */
Matus Fabianab395ec2018-09-20 23:18:41 -07001660 for (i = 0; i < vec_len (addresses); i++)
Matus Fabian36532bd2017-01-23 23:42:28 -08001661 {
Matus Fabianb932d262017-12-18 05:38:24 -08001662 if (addresses[i].addr.as_u32 == addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07001663 {
1664 a = addresses + i;
1665 break;
1666 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001667 }
1668 if (!a)
1669 return VNET_API_ERROR_NO_SUCH_ENTRY;
1670
1671 if (delete_sm)
1672 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001673 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001674 pool_foreach (m, sm->static_mappings,
1675 ({
1676 if (m->external_addr.as_u32 == addr.as_u32)
1677 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1678 m->local_port, m->external_port,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001679 m->vrf_id, is_addr_only_static_mapping(m), ~0,
Matus Fabiane82488f2018-01-18 03:38:45 -08001680 m->proto, 0, m->twice_nat,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001681 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
Matus Fabian36532bd2017-01-23 23:42:28 -08001682 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001683 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001684 }
1685 else
1686 {
1687 /* Check if address is used in some static mapping */
Matus Fabianab395ec2018-09-20 23:18:41 -07001688 if (is_snat_address_used_in_static_mapping (sm, addr))
1689 {
Filip Vargae6e09a42019-07-31 12:45:48 +02001690 nat_elog_notice ("address used in static mapping");
Matus Fabianab395ec2018-09-20 23:18:41 -07001691 return VNET_API_ERROR_UNSPECIFIED;
1692 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001693 }
1694
Matus Fabianf8d84902017-07-23 23:41:03 -07001695 if (a->fib_index != ~0)
Neale Ranns3bab8f92019-12-04 06:11:00 +00001696 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
Matus Fabianf8d84902017-07-23 23:41:03 -07001697
Matus Fabian36532bd2017-01-23 23:42:28 -08001698 /* Delete sessions using address */
Matus Fabian09d96f42017-02-02 01:43:00 -08001699 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
Matus Fabian36532bd2017-01-23 23:42:28 -08001700 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001701 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001702 vec_foreach (tsm, sm->per_thread_data)
1703 {
1704 pool_foreach (ses, tsm->sessions, ({
1705 if (ses->out2in.addr.as_u32 == addr.as_u32)
1706 {
Matus Fabian34931eb2019-02-26 09:05:23 -08001707 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
Matus Fabianb932d262017-12-18 05:38:24 -08001708 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
Matus Fabian36532bd2017-01-23 23:42:28 -08001709 }
1710 }));
1711
1712 vec_foreach (ses_index, ses_to_be_removed)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001713 {
1714 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1715 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1716 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001717
1718 vec_free (ses_to_be_removed);
Matus Fabianab395ec2018-09-20 23:18:41 -07001719 }
1720 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001721 }
1722
dongjuandf865202018-09-11 11:20:30 +00001723#define _(N, i, n, s) \
1724 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1725 vec_free (a->busy_##n##_ports_per_thread);
1726 foreach_snat_protocol
1727#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001728 if (twice_nat)
Matus Fabianb932d262017-12-18 05:38:24 -08001729 {
1730 vec_del1 (sm->twice_nat_addresses, i);
1731 return 0;
1732 }
1733 else
1734 vec_del1 (sm->addresses, i);
Matus Fabian36532bd2017-01-23 23:42:28 -08001735
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001736 /* Delete external address from FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001737 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001738 pool_foreach (interface, sm->interfaces,
1739 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001740 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001741 continue;
1742
Matus Fabian066f0342017-02-10 03:48:01 -08001743 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
Matus Fabiandccbee32017-01-31 22:20:30 -08001744 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001745 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001746 pool_foreach (interface, sm->output_feature_interfaces,
1747 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001748 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001749 continue;
1750
1751 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1752 break;
1753 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001754 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001755
Matus Fabian36532bd2017-01-23 23:42:28 -08001756 return 0;
1757}
1758
Matus Fabianab395ec2018-09-20 23:18:41 -07001759int
1760snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
Matus Fabian588144a2016-10-24 03:30:00 -07001761{
1762 snat_main_t *sm = &snat_main;
1763 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001764 const char *feature_name, *del_feature_name;
1765 snat_address_t *ap;
1766 snat_static_mapping_t *m;
1767 snat_det_map_t *dm;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001768 nat_outside_fib_t *outside_fib;
1769 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07001770 sw_if_index);
Matus Fabian588144a2016-10-24 03:30:00 -07001771
Juraj Slobodacba69362017-12-19 02:09:32 +01001772 if (sm->out2in_dpo && !is_inside)
1773 return VNET_API_ERROR_UNSUPPORTED;
1774
Matus Fabianab395ec2018-09-20 23:18:41 -07001775 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001776 pool_foreach (i, sm->output_feature_interfaces,
1777 ({
1778 if (i->sw_if_index == sw_if_index)
1779 return VNET_API_ERROR_VALUE_EXIST;
1780 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001781 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001782
Matus Fabian588144a2016-10-24 03:30:00 -07001783 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
Matus Fabianab395ec2018-09-20 23:18:41 -07001784 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
Matus Fabian588144a2016-10-24 03:30:00 -07001785 else
Matus Fabian475f0552016-10-19 06:17:52 -07001786 {
Matus Fabian066f0342017-02-10 03:48:01 -08001787 if (sm->num_workers > 1 && !sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001788 feature_name =
1789 is_inside ? "nat44-in2out-worker-handoff" :
1790 "nat44-out2in-worker-handoff";
Matus Fabian066f0342017-02-10 03:48:01 -08001791 else if (sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001792 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
Matus Fabiana6110b62018-06-13 05:39:07 -07001793 else if (sm->endpoint_dependent)
Filip Varga9a6dc8a2019-09-09 16:55:19 +02001794 {
1795 feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1796 }
Matus Fabian475f0552016-10-19 06:17:52 -07001797 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001798 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
Matus Fabian475f0552016-10-19 06:17:52 -07001799 }
Matus Fabian588144a2016-10-24 03:30:00 -07001800
Matus Fabian066f0342017-02-10 03:48:01 -08001801 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Filip Varga9a6dc8a2019-09-09 16:55:19 +02001802 sm->fq_in2out_index =
1803 vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001804
Matus Fabian066f0342017-02-10 03:48:01 -08001805 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Filip Varga9a6dc8a2019-09-09 16:55:19 +02001806 sm->fq_out2in_index =
1807 vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001808
Matus Fabian8008d7c2018-07-09 01:34:20 -07001809 if (!is_inside)
1810 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001811 /* *INDENT-OFF* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001812 vec_foreach (outside_fib, sm->outside_fibs)
1813 {
1814 if (outside_fib->fib_index == fib_index)
1815 {
1816 if (is_del)
1817 {
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05001818 outside_fib->refcount--;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001819 if (!outside_fib->refcount)
1820 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1821 }
1822 else
1823 outside_fib->refcount++;
1824 goto feature_set;
1825 }
1826 }
Matus Fabianab395ec2018-09-20 23:18:41 -07001827 /* *INDENT-ON* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001828 if (!is_del)
Matus Fabianab395ec2018-09-20 23:18:41 -07001829 {
1830 vec_add2 (sm->outside_fibs, outside_fib, 1);
1831 outside_fib->refcount = 1;
1832 outside_fib->fib_index = fib_index;
1833 }
Matus Fabian8008d7c2018-07-09 01:34:20 -07001834 }
1835feature_set:
Matus Fabianab395ec2018-09-20 23:18:41 -07001836 /* *INDENT-OFF* */
Matus Fabian588144a2016-10-24 03:30:00 -07001837 pool_foreach (i, sm->interfaces,
1838 ({
1839 if (i->sw_if_index == sw_if_index)
1840 {
1841 if (is_del)
Matus Fabian36ea2d62017-10-24 04:13:49 -07001842 {
1843 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1844 {
1845 if (is_inside)
1846 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1847 else
1848 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1849
1850 if (sm->num_workers > 1 && !sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001851 {
1852 del_feature_name = "nat44-handoff-classify";
1853 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1854 "nat44-out2in-worker-handoff";
1855 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001856 else if (sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001857 {
1858 del_feature_name = "nat44-det-classify";
1859 feature_name = !is_inside ? "nat44-det-in2out" :
1860 "nat44-det-out2in";
1861 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001862 else if (sm->endpoint_dependent)
1863 {
1864 del_feature_name = "nat44-ed-classify";
Filip Varga9a6dc8a2019-09-09 16:55:19 +02001865 feature_name = !is_inside ? "nat-pre-in2out" :
1866 "nat-pre-out2in";
Matus Fabiana6110b62018-06-13 05:39:07 -07001867 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001868 else
Milan Lenco2aa22902018-01-22 14:05:14 +01001869 {
1870 del_feature_name = "nat44-classify";
1871 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1872 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001873
Klement Sekeraf126e742019-10-10 09:46:06 +00001874 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1875 if (rv)
1876 return rv;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001877 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1878 sw_if_index, 0, 0, 0);
1879 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1880 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001881 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001882 {
1883 if (sm->endpoint_dependent)
1884 vnet_feature_enable_disable ("ip4-local",
1885 "nat44-ed-hairpinning",
1886 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001887 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001888 vnet_feature_enable_disable ("ip4-local",
1889 "nat44-hairpinning",
1890 sw_if_index, 1, 0, 0);
1891 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001892 }
1893 else
1894 {
Klement Sekeraf126e742019-10-10 09:46:06 +00001895 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
1896 if (rv)
1897 return rv;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001898 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1899 sw_if_index, 0, 0, 0);
1900 pool_put (sm->interfaces, i);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001901 if (is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001902 {
1903 if (sm->endpoint_dependent)
1904 vnet_feature_enable_disable ("ip4-local",
1905 "nat44-ed-hairpinning",
1906 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001907 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001908 vnet_feature_enable_disable ("ip4-local",
1909 "nat44-hairpinning",
1910 sw_if_index, 0, 0, 0);
1911 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001912 }
1913 }
Matus Fabian588144a2016-10-24 03:30:00 -07001914 else
Matus Fabian36ea2d62017-10-24 04:13:49 -07001915 {
1916 if ((nat_interface_is_inside(i) && is_inside) ||
1917 (nat_interface_is_outside(i) && !is_inside))
1918 return 0;
1919
1920 if (sm->num_workers > 1 && !sm->deterministic)
1921 {
1922 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1923 "nat44-out2in-worker-handoff";
1924 feature_name = "nat44-handoff-classify";
1925 }
1926 else if (sm->deterministic)
1927 {
1928 del_feature_name = !is_inside ? "nat44-det-in2out" :
1929 "nat44-det-out2in";
1930 feature_name = "nat44-det-classify";
1931 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001932 else if (sm->endpoint_dependent)
1933 {
Filip Varga9a6dc8a2019-09-09 16:55:19 +02001934 del_feature_name = !is_inside ? "nat-pre-in2out" :
1935 "nat-pre-out2in";
1936
Matus Fabiana6110b62018-06-13 05:39:07 -07001937 feature_name = "nat44-ed-classify";
1938 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001939 else
1940 {
1941 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1942 feature_name = "nat44-classify";
1943 }
1944
Klement Sekeraf126e742019-10-10 09:46:06 +00001945 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1946 if (rv)
1947 return rv;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001948 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1949 sw_if_index, 0, 0, 0);
1950 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1951 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001952 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001953 {
1954 if (sm->endpoint_dependent)
1955 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1956 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001957 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001958 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1959 sw_if_index, 0, 0, 0);
1960 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001961 goto set_flags;
1962 }
Matus Fabian588144a2016-10-24 03:30:00 -07001963
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001964 goto fib;
Matus Fabian588144a2016-10-24 03:30:00 -07001965 }
1966 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001967 /* *INDENT-ON* */
Matus Fabian588144a2016-10-24 03:30:00 -07001968
1969 if (is_del)
1970 return VNET_API_ERROR_NO_SUCH_ENTRY;
1971
1972 pool_get (sm->interfaces, i);
1973 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001974 i->flags = 0;
Matus Fabianab395ec2018-09-20 23:18:41 -07001975 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1976 0);
Matus Fabian36ea2d62017-10-24 04:13:49 -07001977
Klement Sekeraf126e742019-10-10 09:46:06 +00001978 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
1979 if (rv)
1980 return rv;
1981
Matus Fabian35dfedc2018-04-26 02:12:20 -07001982 if (is_inside && !sm->out2in_dpo)
Matus Fabiana6110b62018-06-13 05:39:07 -07001983 {
1984 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001985 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1986 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001987 else if (!sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001988 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1989 sw_if_index, 1, 0, 0);
Matus Fabiana6110b62018-06-13 05:39:07 -07001990 }
Matus Fabian35dfedc2018-04-26 02:12:20 -07001991
Matus Fabian36ea2d62017-10-24 04:13:49 -07001992set_flags:
1993 if (is_inside)
Matus Fabian35dfedc2018-04-26 02:12:20 -07001994 {
1995 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1996 return 0;
1997 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001998 else
1999 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian588144a2016-10-24 03:30:00 -07002000
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002001 /* Add/delete external addresses to FIB */
2002fib:
Matus Fabianab395ec2018-09-20 23:18:41 -07002003 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002004 vec_foreach (ap, sm->addresses)
Matus Fabian066f0342017-02-10 03:48:01 -08002005 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002006
2007 pool_foreach (m, sm->static_mappings,
2008 ({
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002009 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002010 continue;
2011
Matus Fabian066f0342017-02-10 03:48:01 -08002012 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2013 }));
2014
2015 pool_foreach (dm, sm->det_maps,
2016 ({
2017 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002018 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002019 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08002020
Matus Fabian588144a2016-10-24 03:30:00 -07002021 return 0;
2022}
2023
Matus Fabianab395ec2018-09-20 23:18:41 -07002024int
2025snat_interface_add_del_output_feature (u32 sw_if_index,
2026 u8 is_inside, int is_del)
Matus Fabian93d84c92017-07-19 08:06:01 -07002027{
2028 snat_main_t *sm = &snat_main;
2029 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07002030 snat_address_t *ap;
2031 snat_static_mapping_t *m;
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05002032 nat_outside_fib_t *outside_fib;
2033 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2034 sw_if_index);
2035
Matus Fabian93d84c92017-07-19 08:06:01 -07002036
2037 if (sm->deterministic ||
2038 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2039 return VNET_API_ERROR_UNSUPPORTED;
2040
Matus Fabianab395ec2018-09-20 23:18:41 -07002041 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08002042 pool_foreach (i, sm->interfaces,
2043 ({
2044 if (i->sw_if_index == sw_if_index)
2045 return VNET_API_ERROR_VALUE_EXIST;
2046 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002047 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08002048
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05002049 if (!is_inside)
2050 {
2051 /* *INDENT-OFF* */
2052 vec_foreach (outside_fib, sm->outside_fibs)
2053 {
2054 if (outside_fib->fib_index == fib_index)
2055 {
2056 if (is_del)
2057 {
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002058 outside_fib->refcount--;
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05002059 if (!outside_fib->refcount)
2060 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2061 }
2062 else
2063 outside_fib->refcount++;
2064 goto feature_set;
2065 }
2066 }
2067 /* *INDENT-ON* */
2068 if (!is_del)
2069 {
2070 vec_add2 (sm->outside_fibs, outside_fib, 1);
2071 outside_fib->refcount = 1;
2072 outside_fib->fib_index = fib_index;
2073 }
2074 }
2075
2076feature_set:
Matus Fabian93d84c92017-07-19 08:06:01 -07002077 if (is_inside)
Matus Fabian161c59c2017-07-21 03:46:03 -07002078 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002079 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002080 {
Klement Sekeraf126e742019-10-10 09:46:06 +00002081 int rv =
2082 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2083 if (rv)
2084 return rv;
2085 rv =
2086 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2087 !is_del);
2088 if (rv)
2089 return rv;
Matus Fabianab395ec2018-09-20 23:18:41 -07002090 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2091 sw_if_index, !is_del, 0, 0);
2092 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2093 sw_if_index, !is_del, 0, 0);
2094 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002095 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002096 {
Klement Sekeraf126e742019-10-10 09:46:06 +00002097 int rv =
2098 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2099 if (rv)
2100 return rv;
2101 rv =
2102 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2103 !is_del);
2104 if (rv)
2105 return rv;
Matus Fabianab395ec2018-09-20 23:18:41 -07002106 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2107 sw_if_index, !is_del, 0, 0);
2108 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2109 sw_if_index, !is_del, 0, 0);
2110 }
Matus Fabian161c59c2017-07-21 03:46:03 -07002111 goto fq;
2112 }
Matus Fabian93d84c92017-07-19 08:06:01 -07002113
2114 if (sm->num_workers > 1)
2115 {
Klement Sekeraf126e742019-10-10 09:46:06 +00002116 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2117 if (rv)
2118 return rv;
2119 rv =
2120 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2121 if (rv)
2122 return rv;
Matus Fabiana6110b62018-06-13 05:39:07 -07002123 vnet_feature_enable_disable ("ip4-unicast",
Matus Fabianab395ec2018-09-20 23:18:41 -07002124 "nat44-out2in-worker-handoff",
2125 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002126 vnet_feature_enable_disable ("ip4-output",
Matus Fabianab395ec2018-09-20 23:18:41 -07002127 "nat44-in2out-output-worker-handoff",
2128 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002129 }
2130 else
2131 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002132 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002133 {
Klement Sekeraf126e742019-10-10 09:46:06 +00002134 int rv =
2135 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2136 if (rv)
2137 return rv;
2138 rv =
2139 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2140 !is_del);
2141 if (rv)
2142 return rv;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02002143 vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
Matus Fabianab395ec2018-09-20 23:18:41 -07002144 sw_if_index, !is_del, 0, 0);
2145 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2146 sw_if_index, !is_del, 0, 0);
2147 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002148 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002149 {
Klement Sekeraf126e742019-10-10 09:46:06 +00002150 int rv =
2151 ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2152 if (rv)
2153 return rv;
2154 rv =
2155 ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2156 !is_del);
2157 if (rv)
2158 return rv;
Matus Fabianab395ec2018-09-20 23:18:41 -07002159 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2160 sw_if_index, !is_del, 0, 0);
2161 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2162 sw_if_index, !is_del, 0, 0);
2163 }
Matus Fabian93d84c92017-07-19 08:06:01 -07002164 }
2165
Matus Fabian161c59c2017-07-21 03:46:03 -07002166fq:
Matus Fabian93d84c92017-07-19 08:06:01 -07002167 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2168 sm->fq_in2out_output_index =
Filip Varga9a6dc8a2019-09-09 16:55:19 +02002169 vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002170
2171 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07002172 sm->fq_out2in_index =
Filip Varga9a6dc8a2019-09-09 16:55:19 +02002173 vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002174
Matus Fabianab395ec2018-09-20 23:18:41 -07002175 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002176 pool_foreach (i, sm->output_feature_interfaces,
2177 ({
2178 if (i->sw_if_index == sw_if_index)
2179 {
2180 if (is_del)
2181 pool_put (sm->output_feature_interfaces, i);
2182 else
2183 return VNET_API_ERROR_VALUE_EXIST;
2184
2185 goto fib;
2186 }
2187 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002188 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002189
2190 if (is_del)
2191 return VNET_API_ERROR_NO_SUCH_ENTRY;
2192
2193 pool_get (sm->output_feature_interfaces, i);
2194 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07002195 i->flags = 0;
2196 if (is_inside)
2197 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2198 else
2199 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian93d84c92017-07-19 08:06:01 -07002200
2201 /* Add/delete external addresses to FIB */
2202fib:
2203 if (is_inside)
2204 return 0;
2205
Matus Fabianab395ec2018-09-20 23:18:41 -07002206 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002207 vec_foreach (ap, sm->addresses)
2208 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2209
2210 pool_foreach (m, sm->static_mappings,
2211 ({
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002212 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabian93d84c92017-07-19 08:06:01 -07002213 continue;
2214
2215 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2216 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002217 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002218
2219 return 0;
2220}
2221
Matus Fabianab395ec2018-09-20 23:18:41 -07002222int
2223snat_set_workers (uword * bitmap)
Matus Fabian475f0552016-10-19 06:17:52 -07002224{
2225 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07002226 int i, j = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002227
2228 if (sm->num_workers < 2)
2229 return VNET_API_ERROR_FEATURE_DISABLED;
2230
2231 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2232 return VNET_API_ERROR_INVALID_WORKER;
2233
2234 vec_free (sm->workers);
Matus Fabianab395ec2018-09-20 23:18:41 -07002235 /* *INDENT-OFF* */
Matus Fabian475f0552016-10-19 06:17:52 -07002236 clib_bitmap_foreach (i, bitmap,
2237 ({
2238 vec_add1(sm->workers, i);
Matus Fabian10491392018-01-05 05:03:35 -08002239 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
Filip Varga22bb4172019-08-12 14:24:39 +02002240 sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
Matus Fabian7801ca22017-08-03 00:58:05 -07002241 j++;
Matus Fabian475f0552016-10-19 06:17:52 -07002242 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002243 /* *INDENT-ON* */
Matus Fabian475f0552016-10-19 06:17:52 -07002244
Matus Fabian7801ca22017-08-03 00:58:05 -07002245 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2246 sm->num_snat_thread = _vec_len (sm->workers);
2247
Matus Fabian475f0552016-10-19 06:17:52 -07002248 return 0;
2249}
2250
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002251static void
2252snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2253 u32 old_fib_index)
2254{
2255 snat_main_t *sm = &snat_main;
2256 nat_outside_fib_t *outside_fib;
2257 snat_interface_t *i;
2258 u8 is_add = 1;
Filip Varga16ad6172019-06-11 10:45:21 +02002259 u8 match = 0;
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002260
2261 if (new_fib_index == old_fib_index)
2262 return;
2263
2264 if (!vec_len (sm->outside_fibs))
2265 return;
2266
Filip Varga16ad6172019-06-11 10:45:21 +02002267 /* *INDENT-OFF* */
2268 pool_foreach (i, sm->interfaces,
2269 ({
2270 if (i->sw_if_index == sw_if_index)
2271 {
2272 if (!(nat_interface_is_outside (i)))
2273 return;
2274 match = 1;
2275 }
2276 }));
Dmitry Vakhrushev6c57a4a2019-08-20 14:44:51 -04002277
2278 pool_foreach (i, sm->output_feature_interfaces,
2279 ({
2280 if (i->sw_if_index == sw_if_index)
2281 {
2282 if (!(nat_interface_is_outside (i)))
2283 return;
2284 match = 1;
2285 }
2286 }));
Filip Varga16ad6172019-06-11 10:45:21 +02002287 /* *INDENT-ON* */
2288
2289 if (!match)
2290 return;
2291
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002292 vec_foreach (outside_fib, sm->outside_fibs)
2293 {
2294 if (outside_fib->fib_index == old_fib_index)
2295 {
2296 outside_fib->refcount--;
2297 if (!outside_fib->refcount)
2298 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2299 break;
2300 }
2301 }
2302
2303 vec_foreach (outside_fib, sm->outside_fibs)
2304 {
2305 if (outside_fib->fib_index == new_fib_index)
2306 {
2307 outside_fib->refcount++;
2308 is_add = 0;
2309 break;
2310 }
2311 }
2312
2313 if (is_add)
2314 {
2315 vec_add2 (sm->outside_fibs, outside_fib, 1);
2316 outside_fib->refcount = 1;
2317 outside_fib->fib_index = new_fib_index;
2318 }
2319}
2320
2321static void
2322snat_ip4_table_bind (ip4_main_t * im,
2323 uword opaque,
2324 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2325{
2326 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2327}
Dave Barach8b275372017-01-16 10:54:02 -05002328
Dave Barachcab65ec2017-01-11 13:01:14 -05002329static void
2330snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002331 uword opaque,
2332 u32 sw_if_index,
2333 ip4_address_t * address,
2334 u32 address_length,
2335 u32 if_address_index, u32 is_delete);
Dave Barachcab65ec2017-01-11 13:01:14 -05002336
Matus Fabian4772e7a2018-04-04 00:38:02 -07002337static void
2338nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002339 uword opaque,
2340 u32 sw_if_index,
2341 ip4_address_t * address,
2342 u32 address_length,
2343 u32 if_address_index, u32 is_delete);
Matus Fabian4772e7a2018-04-04 00:38:02 -07002344
Matus Fabian27697102017-11-09 01:43:47 -08002345static int
2346nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002347 u32 fib_index,
2348 u32 thread_index,
2349 snat_session_key_t * k,
2350 u16 port_per_thread, u32 snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08002351
Matus Fabianab395ec2018-09-20 23:18:41 -07002352static clib_error_t *
2353snat_init (vlib_main_t * vm)
Dave Barach20c02cb2016-06-26 10:42:08 -04002354{
Matus Fabianab395ec2018-09-20 23:18:41 -07002355 snat_main_t *sm = &snat_main;
2356 clib_error_t *error = 0;
2357 ip4_main_t *im = &ip4_main;
2358 ip_lookup_main_t *lm = &im->lookup_main;
Matus Fabian475f0552016-10-19 06:17:52 -07002359 uword *p;
2360 vlib_thread_registration_t *tr;
2361 vlib_thread_main_t *tm = vlib_get_thread_main ();
2362 uword *bitmap = 0;
2363 u32 i;
Dave Barachcab65ec2017-01-11 13:01:14 -05002364 ip4_add_del_interface_address_callback_t cb4;
Filip Vargae69e4232019-02-13 01:42:59 -08002365 vlib_node_t *node;
Dave Barach20c02cb2016-06-26 10:42:08 -04002366
Dave Barach20c02cb2016-06-26 10:42:08 -04002367 sm->vlib_main = vm;
Matus Fabianab395ec2018-09-20 23:18:41 -07002368 sm->vnet_main = vnet_get_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -04002369 sm->ip4_main = im;
2370 sm->ip4_lookup_main = lm;
Dave Barach39d69112019-11-27 11:42:13 -05002371 sm->api_main = vlibapi_get_main ();
Matus Fabian475f0552016-10-19 06:17:52 -07002372 sm->first_worker_index = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002373 sm->num_workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07002374 sm->num_snat_thread = 1;
Matus Fabian475f0552016-10-19 06:17:52 -07002375 sm->workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07002376 sm->port_per_thread = 0xffff - 1024;
Matus Fabian475f0552016-10-19 06:17:52 -07002377 sm->fq_in2out_index = ~0;
Matthew Smith26e035b2019-04-01 16:27:00 -05002378 sm->fq_in2out_output_index = ~0;
Matus Fabian475f0552016-10-19 06:17:52 -07002379 sm->fq_out2in_index = ~0;
Filip Vargae6eaa242019-11-27 17:40:29 +01002380
2381
Matus Fabian27697102017-11-09 01:43:47 -08002382 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002383 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Juraj Sloboda7b929792017-11-23 13:20:48 +01002384 sm->forwarding_enabled = 0;
Matus Fabian229c1aa2018-05-28 04:09:52 -07002385 sm->log_class = vlib_log_register_class ("nat", 0);
Filip Varga22bb4172019-08-12 14:24:39 +02002386 sm->log_level = SNAT_LOG_ERROR;
Matus Fabianbb4e0222018-09-13 02:36:25 -07002387 sm->mss_clamping = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002388
Filip Vargae69e4232019-02-13 01:42:59 -08002389 node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2390 sm->error_node_index = node->index;
2391
Filip Varga9a6dc8a2019-09-09 16:55:19 +02002392 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2393 sm->pre_in2out_node_index = node->index;
2394 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2395 sm->pre_out2in_node_index = node->index;
2396
2397 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2398 sm->pre_in2out_node_index = node->index;
2399
2400 node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2401 sm->pre_out2in_node_index = node->index;
2402
Filip Vargae69e4232019-02-13 01:42:59 -08002403 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2404 sm->in2out_node_index = node->index;
2405 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2406 sm->in2out_output_node_index = node->index;
2407 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2408 sm->in2out_fast_node_index = node->index;
2409 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2410 sm->in2out_slowpath_node_index = node->index;
2411 node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2412 sm->in2out_slowpath_output_node_index = node->index;
Filip Vargae69e4232019-02-13 01:42:59 -08002413
2414 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2415 sm->ed_in2out_node_index = node->index;
2416 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2417 sm->ed_in2out_slowpath_node_index = node->index;
Filip Vargae69e4232019-02-13 01:42:59 -08002418
2419 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2420 sm->out2in_node_index = node->index;
2421 node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2422 sm->out2in_fast_node_index = node->index;
Filip Vargae69e4232019-02-13 01:42:59 -08002423
2424 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2425 sm->ed_out2in_node_index = node->index;
2426 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2427 sm->ed_out2in_slowpath_node_index = node->index;
Filip Vargae69e4232019-02-13 01:42:59 -08002428
2429 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2430 sm->det_in2out_node_index = node->index;
2431 node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2432 sm->det_out2in_node_index = node->index;
2433
2434 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2435 sm->hairpinning_node_index = node->index;
2436 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2437 sm->hairpin_dst_node_index = node->index;
2438 node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2439 sm->hairpin_src_node_index = node->index;
2440 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2441 sm->ed_hairpinning_node_index = node->index;
2442 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2443 sm->ed_hairpin_dst_node_index = node->index;
2444 node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2445 sm->ed_hairpin_src_node_index = node->index;
2446
Matus Fabian475f0552016-10-19 06:17:52 -07002447 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2448 if (p)
2449 {
2450 tr = (vlib_thread_registration_t *) p[0];
2451 if (tr)
Matus Fabianab395ec2018-09-20 23:18:41 -07002452 {
2453 sm->num_workers = tr->count;
2454 sm->first_worker_index = tr->first_index;
2455 }
Matus Fabian475f0552016-10-19 06:17:52 -07002456 }
2457
Matus Fabian7801ca22017-08-03 00:58:05 -07002458 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2459
Matus Fabian475f0552016-10-19 06:17:52 -07002460 /* Use all available workers by default */
2461 if (sm->num_workers > 1)
2462 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002463 for (i = 0; i < sm->num_workers; i++)
2464 bitmap = clib_bitmap_set (bitmap, i, 1);
2465 snat_set_workers (bitmap);
Matus Fabian475f0552016-10-19 06:17:52 -07002466 clib_bitmap_free (bitmap);
2467 }
Matus Fabian7801ca22017-08-03 00:58:05 -07002468 else
2469 {
2470 sm->per_thread_data[0].snat_thread_index = 0;
2471 }
Dave Barach20c02cb2016-06-26 10:42:08 -04002472
Matus Fabianab395ec2018-09-20 23:18:41 -07002473 error = snat_api_init (vm, sm);
Matus Fabian08ce4322017-06-19 05:28:27 -07002474 if (error)
2475 return error;
Dave Barach20c02cb2016-06-26 10:42:08 -04002476
Dave Barachcab65ec2017-01-11 13:01:14 -05002477 /* Set up the interface address add/del callback */
2478 cb4.function = snat_ip4_add_del_interface_address_cb;
2479 cb4.function_opaque = 0;
2480
2481 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2482
Matus Fabian4772e7a2018-04-04 00:38:02 -07002483 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2484 cb4.function_opaque = 0;
2485
2486 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2487
Juraj Slobodacba69362017-12-19 02:09:32 +01002488 nat_dpo_module_init ();
2489
Matus Fabianfd0d5082018-12-18 01:08:51 -08002490 /* Init counters */
2491 sm->total_users.name = "total-users";
2492 sm->total_users.stat_segment_name = "/nat44/total-users";
2493 vlib_validate_simple_counter (&sm->total_users, 0);
2494 vlib_zero_simple_counter (&sm->total_users, 0);
2495 sm->total_sessions.name = "total-sessions";
2496 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2497 vlib_validate_simple_counter (&sm->total_sessions, 0);
2498 vlib_zero_simple_counter (&sm->total_sessions, 0);
2499
Matus Fabianeea28d72017-01-13 04:15:54 -08002500 /* Init IPFIX logging */
Matus Fabianab395ec2018-09-20 23:18:41 -07002501 snat_ipfix_logging_init (vm);
Matus Fabianeea28d72017-01-13 04:15:54 -08002502
Matus Fabianefcd1e92017-08-15 06:59:19 -07002503 /* Init NAT64 */
Matus Fabianab395ec2018-09-20 23:18:41 -07002504 error = nat64_init (vm);
Matus Fabianefcd1e92017-08-15 06:59:19 -07002505 if (error)
2506 return error;
Matus Fabian06596c52017-06-06 04:53:28 -07002507
Matus Fabianab395ec2018-09-20 23:18:41 -07002508 dslite_init (vm);
Matus Fabian8ebe6252017-11-06 05:04:53 -08002509
Filip Vargae69e4232019-02-13 01:42:59 -08002510 nat66_init (vm);
Matus Fabianf2a23cc2018-01-22 03:41:53 -08002511
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002512 ip4_table_bind_callback_t cbt4 = {
2513 .function = snat_ip4_table_bind,
2514 };
2515 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2516
Neale Ranns3bab8f92019-12-04 06:11:00 +00002517 nat_fib_src_hi = fib_source_allocate ("nat-hi",
2518 FIB_SOURCE_PRIORITY_HI,
2519 FIB_SOURCE_BH_SIMPLE);
2520 nat_fib_src_low = fib_source_allocate ("nat-low",
2521 FIB_SOURCE_PRIORITY_LOW,
2522 FIB_SOURCE_BH_SIMPLE);
2523
Klement Sekeraf126e742019-10-10 09:46:06 +00002524 return error;
Dave Barach20c02cb2016-06-26 10:42:08 -04002525}
2526
2527VLIB_INIT_FUNCTION (snat_init);
2528
Matus Fabianab395ec2018-09-20 23:18:41 -07002529void
2530snat_free_outside_address_and_port (snat_address_t * addresses,
2531 u32 thread_index, snat_session_key_t * k)
Dave Barach20c02cb2016-06-26 10:42:08 -04002532{
2533 snat_address_t *a;
shubing guo762a4932018-08-13 17:16:46 +08002534 u32 address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04002535 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
Matus Fabian2ba92e32017-08-21 07:05:03 -07002536
Matus Fabianab395ec2018-09-20 23:18:41 -07002537 for (address_index = 0; address_index < vec_len (addresses);
2538 address_index++)
shubing guo762a4932018-08-13 17:16:46 +08002539 {
2540 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07002541 break;
shubing guo762a4932018-08-13 17:16:46 +08002542 }
2543
Matus Fabian8ebe6252017-11-06 05:04:53 -08002544 ASSERT (address_index < vec_len (addresses));
Dave Barach20c02cb2016-06-26 10:42:08 -04002545
Matus Fabian8ebe6252017-11-06 05:04:53 -08002546 a = addresses + address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04002547
Matus Fabian09d96f42017-02-02 01:43:00 -08002548 switch (k->protocol)
2549 {
2550#define _(N, i, n, s) \
2551 case SNAT_PROTOCOL_##N: \
2552 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2553 port_host_byte_order) == 1); \
2554 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2555 port_host_byte_order, 0); \
2556 a->busy_##n##_ports--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07002557 a->busy_##n##_ports_per_thread[thread_index]--; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002558 break;
2559 foreach_snat_protocol
2560#undef _
2561 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002562 nat_elog_info ("unknown protocol");
Matus Fabian09d96f42017-02-02 01:43:00 -08002563 return;
2564 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07002565}
Dave Barach20c02cb2016-06-26 10:42:08 -04002566
Matus Fabian34931eb2019-02-26 09:05:23 -08002567static int
2568nat_set_outside_address_and_port (snat_address_t * addresses,
2569 u32 thread_index, snat_session_key_t * k)
2570{
2571 snat_address_t *a = 0;
2572 u32 address_index;
2573 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2574
2575 for (address_index = 0; address_index < vec_len (addresses);
2576 address_index++)
2577 {
2578 if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2579 continue;
2580
2581 a = addresses + address_index;
2582 switch (k->protocol)
2583 {
2584#define _(N, j, n, s) \
2585 case SNAT_PROTOCOL_##N: \
2586 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, port_host_byte_order)) \
2587 return VNET_API_ERROR_INSTANCE_IN_USE; \
2588 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port_host_byte_order, 1); \
2589 a->busy_##n##_ports_per_thread[thread_index]++; \
2590 a->busy_##n##_ports++; \
2591 return 0;
2592 foreach_snat_protocol
2593#undef _
2594 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002595 nat_elog_info ("unknown protocol");
Matus Fabian34931eb2019-02-26 09:05:23 -08002596 return 1;
2597 }
2598 }
2599
2600 return VNET_API_ERROR_NO_SUCH_ENTRY;
2601}
2602
Matus Fabianab395ec2018-09-20 23:18:41 -07002603int
2604snat_static_mapping_match (snat_main_t * sm,
2605 snat_session_key_t match,
2606 snat_session_key_t * mapping,
2607 u8 by_external,
2608 u8 * is_addr_only,
2609 twice_nat_type_t * twice_nat,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002610 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2611 u8 * is_identity_nat)
Matus Fabiandb649882016-08-26 05:45:27 -07002612{
2613 clib_bihash_kv_8_8_t kv, value;
2614 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -08002615 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -07002616 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
Matus Fabianb6865082018-12-06 03:11:09 -08002617 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
Matus Fabianea5b5be2018-09-03 05:02:23 -07002618 u8 backend_index;
Matus Fabianb6865082018-12-06 03:11:09 -08002619 nat44_lb_addr_port_t *local;
Matus Fabiandb649882016-08-26 05:45:27 -07002620
Matus Fabian8008d7c2018-07-09 01:34:20 -07002621 m_key.fib_index = match.fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -07002622 if (by_external)
Matus Fabian8008d7c2018-07-09 01:34:20 -07002623 {
2624 mapping_hash = &sm->static_mapping_by_external;
2625 m_key.fib_index = 0;
2626 }
Matus Fabiandb649882016-08-26 05:45:27 -07002627
2628 m_key.addr = match.addr;
2629 m_key.port = clib_net_to_host_u16 (match.port);
Matus Fabian09d96f42017-02-02 01:43:00 -08002630 m_key.protocol = match.protocol;
Matus Fabiandb649882016-08-26 05:45:27 -07002631
2632 kv.key = m_key.as_u64;
2633
2634 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2635 {
2636 /* Try address only mapping */
2637 m_key.port = 0;
Matus Fabian09d96f42017-02-02 01:43:00 -08002638 m_key.protocol = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07002639 kv.key = m_key.as_u64;
2640 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
Matus Fabianab395ec2018-09-20 23:18:41 -07002641 return 1;
Matus Fabiandb649882016-08-26 05:45:27 -07002642 }
2643
2644 m = pool_elt_at_index (sm->static_mappings, value.value);
2645
2646 if (by_external)
2647 {
Matus Fabian82b4ceb2018-10-11 04:28:48 -07002648 if (is_lb_static_mapping (m))
Matus Fabianab395ec2018-09-20 23:18:41 -07002649 {
2650 if (PREDICT_FALSE (lb != 0))
2651 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
Filip Varga67eb4bb2019-07-31 14:36:39 +02002652 if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2653 match.addr,
2654 match.protocol,
2655 match.port,
2656 &backend_index))
Matus Fabianab395ec2018-09-20 23:18:41 -07002657 {
Matus Fabianb6865082018-12-06 03:11:09 -08002658 local = pool_elt_at_index (m->locals, backend_index);
2659 mapping->addr = local->addr;
2660 mapping->port = clib_host_to_net_u16 (local->port);
2661 mapping->fib_index = local->fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07002662 goto end;
2663 }
Filip Varga67eb4bb2019-07-31 14:36:39 +02002664 // pick locals matching this worker
2665 if (PREDICT_FALSE (sm->num_workers > 1))
2666 {
2667 u32 thread_index = vlib_get_thread_index ();
2668 /* *INDENT-OFF* */
2669 pool_foreach_index (i, m->locals,
2670 ({
2671 local = pool_elt_at_index (m->locals, i);
2672
2673 ip4_header_t ip = {
2674 .src_address = local->addr,
2675 };
2676
Filip Varga22bb4172019-08-12 14:24:39 +02002677 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
Filip Varga67eb4bb2019-07-31 14:36:39 +02002678 thread_index)
2679 {
2680 vec_add1 (tmp, i);
2681 }
2682 }));
2683 /* *INDENT-ON* */
2684 ASSERT (vec_len (tmp) != 0);
2685 }
2686 else
2687 {
2688 /* *INDENT-OFF* */
2689 pool_foreach_index (i, m->locals,
2690 ({
2691 vec_add1 (tmp, i);
2692 }));
2693 /* *INDENT-ON* */
2694 }
Matus Fabianb6865082018-12-06 03:11:09 -08002695 hi = vec_len (tmp) - 1;
2696 local = pool_elt_at_index (m->locals, tmp[hi]);
2697 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
Matus Fabianab395ec2018-09-20 23:18:41 -07002698 while (lo < hi)
2699 {
2700 mid = ((hi - lo) >> 1) + lo;
Matus Fabianb6865082018-12-06 03:11:09 -08002701 local = pool_elt_at_index (m->locals, tmp[mid]);
2702 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
Matus Fabianab395ec2018-09-20 23:18:41 -07002703 }
Matus Fabianb6865082018-12-06 03:11:09 -08002704 local = pool_elt_at_index (m->locals, tmp[lo]);
2705 if (!(local->prefix >= rand))
Matus Fabianab395ec2018-09-20 23:18:41 -07002706 return 1;
Matus Fabianb6865082018-12-06 03:11:09 -08002707 mapping->addr = local->addr;
2708 mapping->port = clib_host_to_net_u16 (local->port);
2709 mapping->fib_index = local->fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07002710 if (m->affinity)
2711 {
2712 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2713 match.protocol, match.port,
Matus Fabianb6865082018-12-06 03:11:09 -08002714 tmp[lo], m->affinity,
Matus Fabianab395ec2018-09-20 23:18:41 -07002715 m->affinity_per_service_list_head_index))
Filip Vargae6e09a42019-07-31 12:45:48 +02002716 nat_elog_info ("create affinity record failed");
Matus Fabianab395ec2018-09-20 23:18:41 -07002717 }
Matus Fabianb6865082018-12-06 03:11:09 -08002718 vec_free (tmp);
Matus Fabianab395ec2018-09-20 23:18:41 -07002719 }
Matus Fabian704018c2017-09-04 02:17:18 -07002720 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002721 {
2722 if (PREDICT_FALSE (lb != 0))
2723 *lb = NO_LB_NAT;
2724 mapping->fib_index = m->fib_index;
2725 mapping->addr = m->local_addr;
2726 /* Address only mapping doesn't change port */
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002727 mapping->port = is_addr_only_static_mapping (m) ? match.port
Matus Fabianab395ec2018-09-20 23:18:41 -07002728 : clib_host_to_net_u16 (m->local_port);
2729 }
Matus Fabian704018c2017-09-04 02:17:18 -07002730 mapping->protocol = m->proto;
Matus Fabiandb649882016-08-26 05:45:27 -07002731 }
2732 else
2733 {
2734 mapping->addr = m->external_addr;
2735 /* Address only mapping doesn't change port */
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002736 mapping->port = is_addr_only_static_mapping (m) ? match.port
Matus Fabianab395ec2018-09-20 23:18:41 -07002737 : clib_host_to_net_u16 (m->external_port);
Matus Fabiandb649882016-08-26 05:45:27 -07002738 mapping->fib_index = sm->outside_fib_index;
2739 }
2740
Matus Fabianea5b5be2018-09-03 05:02:23 -07002741end:
Matus Fabianab395ec2018-09-20 23:18:41 -07002742 if (PREDICT_FALSE (is_addr_only != 0))
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002743 *is_addr_only = is_addr_only_static_mapping (m);
Juraj Slobodad3677682017-04-14 03:24:45 +02002744
Matus Fabianab395ec2018-09-20 23:18:41 -07002745 if (PREDICT_FALSE (twice_nat != 0))
Matus Fabianb932d262017-12-18 05:38:24 -08002746 *twice_nat = m->twice_nat;
2747
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002748 if (PREDICT_FALSE (is_identity_nat != 0))
2749 *is_identity_nat = is_identity_static_mapping (m);
2750
Matus Fabiandb649882016-08-26 05:45:27 -07002751 return 0;
2752}
2753
Matus Fabian7801ca22017-08-03 00:58:05 -07002754static_always_inline u16
Matus Fabian8ebe6252017-11-06 05:04:53 -08002755snat_random_port (u16 min, u16 max)
Matus Fabian7801ca22017-08-03 00:58:05 -07002756{
Matus Fabian8ebe6252017-11-06 05:04:53 -08002757 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07002758 return min + random_u32 (&sm->random_seed) /
Matus Fabianab395ec2018-09-20 23:18:41 -07002759 (random_u32_max () / (max - min + 1) + 1);
Matus Fabian7801ca22017-08-03 00:58:05 -07002760}
2761
Matus Fabian27697102017-11-09 01:43:47 -08002762int
2763snat_alloc_outside_address_and_port (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002764 u32 fib_index,
2765 u32 thread_index,
2766 snat_session_key_t * k,
2767 u16 port_per_thread,
2768 u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002769{
2770 snat_main_t *sm = &snat_main;
2771
Matus Fabianab395ec2018-09-20 23:18:41 -07002772 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2773 port_per_thread, snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08002774}
2775
2776static int
2777nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002778 u32 fib_index,
2779 u32 thread_index,
2780 snat_session_key_t * k,
2781 u16 port_per_thread, u32 snat_thread_index)
Dave Barach20c02cb2016-06-26 10:42:08 -04002782{
Matus Fabianab395ec2018-09-20 23:18:41 -07002783 int i;
Matus Fabian51e759f2017-12-07 23:22:51 -08002784 snat_address_t *a, *ga = 0;
Dave Barach20c02cb2016-06-26 10:42:08 -04002785 u32 portnum;
2786
Matus Fabian8ebe6252017-11-06 05:04:53 -08002787 for (i = 0; i < vec_len (addresses); i++)
Dave Barach20c02cb2016-06-26 10:42:08 -04002788 {
Matus Fabian8ebe6252017-11-06 05:04:53 -08002789 a = addresses + i;
Matus Fabian09d96f42017-02-02 01:43:00 -08002790 switch (k->protocol)
Matus Fabianab395ec2018-09-20 23:18:41 -07002791 {
Matus Fabian09d96f42017-02-02 01:43:00 -08002792#define _(N, j, n, s) \
2793 case SNAT_PROTOCOL_##N: \
Matus Fabian8ebe6252017-11-06 05:04:53 -08002794 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002795 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002796 if (a->fib_index == fib_index) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002797 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002798 while (1) \
2799 { \
2800 portnum = (port_per_thread * \
2801 snat_thread_index) + \
2802 snat_random_port(1, port_per_thread) + 1024; \
2803 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2804 continue; \
2805 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2806 a->busy_##n##_ports_per_thread[thread_index]++; \
2807 a->busy_##n##_ports++; \
2808 k->addr = a->addr; \
2809 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002810 return 0; \
2811 } \
2812 } \
2813 else if (a->fib_index == ~0) \
2814 { \
2815 ga = a; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002816 } \
2817 } \
2818 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07002819 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -08002820#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07002821 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002822 nat_elog_info ("unknown protocol");
Matus Fabianab395ec2018-09-20 23:18:41 -07002823 return 1;
2824 }
Matus Fabian09d96f42017-02-02 01:43:00 -08002825
Dave Barach20c02cb2016-06-26 10:42:08 -04002826 }
Matus Fabian51e759f2017-12-07 23:22:51 -08002827
2828 if (ga)
2829 {
2830 a = ga;
2831 switch (k->protocol)
2832 {
2833#define _(N, j, n, s) \
2834 case SNAT_PROTOCOL_##N: \
2835 while (1) \
2836 { \
2837 portnum = (port_per_thread * \
2838 snat_thread_index) + \
2839 snat_random_port(1, port_per_thread) + 1024; \
2840 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2841 continue; \
2842 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2843 a->busy_##n##_ports_per_thread[thread_index]++; \
2844 a->busy_##n##_ports++; \
2845 k->addr = a->addr; \
2846 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002847 return 0; \
2848 }
2849 break;
2850 foreach_snat_protocol
2851#undef _
2852 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002853 nat_elog_info ("unknown protocol");
Matus Fabian51e759f2017-12-07 23:22:51 -08002854 return 1;
2855 }
2856 }
2857
Dave Barach20c02cb2016-06-26 10:42:08 -04002858 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002859 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Dave Barach20c02cb2016-06-26 10:42:08 -04002860 return 1;
2861}
2862
Matus Fabian27697102017-11-09 01:43:47 -08002863static int
2864nat_alloc_addr_and_port_mape (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002865 u32 fib_index,
2866 u32 thread_index,
2867 snat_session_key_t * k,
2868 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002869{
2870 snat_main_t *sm = &snat_main;
2871 snat_address_t *a = addresses;
2872 u16 m, ports, portnum, A, j;
2873 m = 16 - (sm->psid_offset + sm->psid_length);
2874 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2875
2876 if (!vec_len (addresses))
2877 goto exhausted;
2878
2879 switch (k->protocol)
2880 {
2881#define _(N, i, n, s) \
2882 case SNAT_PROTOCOL_##N: \
2883 if (a->busy_##n##_ports < ports) \
2884 { \
2885 while (1) \
2886 { \
2887 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2888 j = snat_random_port(0, pow2_mask(m)); \
2889 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2890 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2891 continue; \
2892 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2893 a->busy_##n##_ports++; \
2894 k->addr = a->addr; \
2895 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian27697102017-11-09 01:43:47 -08002896 return 0; \
2897 } \
2898 } \
2899 break;
2900 foreach_snat_protocol
2901#undef _
2902 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002903 nat_elog_info ("unknown protocol");
Matus Fabian27697102017-11-09 01:43:47 -08002904 return 1;
2905 }
2906
2907exhausted:
2908 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002909 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Matus Fabian27697102017-11-09 01:43:47 -08002910 return 1;
2911}
Dave Barach20c02cb2016-06-26 10:42:08 -04002912
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002913static int
2914nat_alloc_addr_and_port_range (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002915 u32 fib_index,
2916 u32 thread_index,
2917 snat_session_key_t * k,
2918 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002919{
2920 snat_main_t *sm = &snat_main;
2921 snat_address_t *a = addresses;
2922 u16 portnum, ports;
2923
2924 ports = sm->end_port - sm->start_port + 1;
2925
2926 if (!vec_len (addresses))
2927 goto exhausted;
2928
2929 switch (k->protocol)
2930 {
2931#define _(N, i, n, s) \
2932 case SNAT_PROTOCOL_##N: \
2933 if (a->busy_##n##_ports < ports) \
2934 { \
2935 while (1) \
2936 { \
2937 portnum = snat_random_port(sm->start_port, sm->end_port); \
2938 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2939 continue; \
2940 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2941 a->busy_##n##_ports++; \
2942 k->addr = a->addr; \
2943 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002944 return 0; \
2945 } \
2946 } \
2947 break;
2948 foreach_snat_protocol
2949#undef _
2950 default:
Filip Vargae6e09a42019-07-31 12:45:48 +02002951 nat_elog_info ("unknown protocol");
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002952 return 1;
2953 }
2954
2955exhausted:
2956 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002957 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002958 return 1;
2959}
2960
Juraj Slobodacba69362017-12-19 02:09:32 +01002961void
2962nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2963{
2964 dpo_id_t dpo_v4 = DPO_INVALID;
2965 fib_prefix_t pfx = {
2966 .fp_proto = FIB_PROTOCOL_IP4,
2967 .fp_len = 32,
2968 .fp_addr.ip4.as_u32 = addr.as_u32,
2969 };
2970
2971 if (is_add)
2972 {
2973 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
Neale Ranns3bab8f92019-12-04 06:11:00 +00002974 fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
Matus Fabianab395ec2018-09-20 23:18:41 -07002975 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
Juraj Slobodacba69362017-12-19 02:09:32 +01002976 dpo_reset (&dpo_v4);
2977 }
2978 else
2979 {
Neale Ranns3bab8f92019-12-04 06:11:00 +00002980 fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
Juraj Slobodacba69362017-12-19 02:09:32 +01002981 }
2982}
2983
Matus Fabian229c1aa2018-05-28 04:09:52 -07002984u8 *
2985format_session_kvp (u8 * s, va_list * args)
2986{
2987 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2988 snat_session_key_t k;
2989
2990 k.as_u64 = v->key;
2991
2992 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2993
2994 return s;
2995}
2996
2997u8 *
2998format_static_mapping_kvp (u8 * s, va_list * args)
2999{
3000 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3001 snat_session_key_t k;
3002
3003 k.as_u64 = v->key;
3004
Matus Fabian878c6462018-08-23 00:33:35 -07003005 s = format (s, "%U static-mapping-index %llu",
Matus Fabianab395ec2018-09-20 23:18:41 -07003006 format_static_mapping_key, &k, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003007
3008 return s;
3009}
3010
3011u8 *
3012format_user_kvp (u8 * s, va_list * args)
3013{
3014 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3015 snat_user_key_t k;
3016
3017 k.as_u64 = v->key;
3018
3019 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07003020 k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003021
3022 return s;
3023}
3024
3025u8 *
3026format_ed_session_kvp (u8 * s, va_list * args)
3027{
3028 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3029 nat_ed_ses_key_t k;
3030
3031 k.as_u64[0] = v->key[0];
3032 k.as_u64[1] = v->key[1];
3033
Matus Fabianab395ec2018-09-20 23:18:41 -07003034 s =
3035 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
3036 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
3037 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
3038 format_ip_protocol, k.proto, k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003039
3040 return s;
3041}
3042
Matus Fabian066f0342017-02-10 03:48:01 -08003043static u32
Filip Varga22bb4172019-08-12 14:24:39 +02003044snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3045 u8 is_output)
Matus Fabian066f0342017-02-10 03:48:01 -08003046{
3047 snat_main_t *sm = &snat_main;
Matus Fabian066f0342017-02-10 03:48:01 -08003048 u32 next_worker_index = 0;
Matus Fabian7865b5c2017-09-26 01:23:01 -07003049 u32 hash;
Matus Fabian066f0342017-02-10 03:48:01 -08003050
Matus Fabian7865b5c2017-09-26 01:23:01 -07003051 next_worker_index = sm->first_worker_index;
3052 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
Matus Fabianab395ec2018-09-20 23:18:41 -07003053 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
Matus Fabian066f0342017-02-10 03:48:01 -08003054
Matus Fabian7865b5c2017-09-26 01:23:01 -07003055 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3056 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
Matus Fabian066f0342017-02-10 03:48:01 -08003057 else
Matus Fabian7865b5c2017-09-26 01:23:01 -07003058 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
Matus Fabian066f0342017-02-10 03:48:01 -08003059
3060 return next_worker_index;
3061}
3062
3063static u32
Klement Sekeraf126e742019-10-10 09:46:06 +00003064snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
3065 u32 rx_fib_index0, u8 is_output)
Matus Fabian066f0342017-02-10 03:48:01 -08003066{
3067 snat_main_t *sm = &snat_main;
Matus Fabianed3c1602017-09-21 05:07:12 -07003068 udp_header_t *udp;
3069 u16 port;
3070 snat_session_key_t m_key;
3071 clib_bihash_kv_8_8_t kv, value;
3072 snat_static_mapping_t *m;
Matus Fabianed3c1602017-09-21 05:07:12 -07003073 u32 proto;
Matus Fabian10491392018-01-05 05:03:35 -08003074 u32 next_worker_index = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08003075
Matus Fabianed3c1602017-09-21 05:07:12 -07003076 /* first try static mappings without port */
3077 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
Matus Fabian066f0342017-02-10 03:48:01 -08003078 {
Matus Fabianed3c1602017-09-21 05:07:12 -07003079 m_key.addr = ip0->dst_address;
3080 m_key.port = 0;
3081 m_key.protocol = 0;
3082 m_key.fib_index = rx_fib_index0;
3083 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07003084 if (!clib_bihash_search_8_8
3085 (&sm->static_mapping_by_external, &kv, &value))
3086 {
3087 m = pool_elt_at_index (sm->static_mappings, value.value);
3088 return m->workers[0];
3089 }
Matus Fabian066f0342017-02-10 03:48:01 -08003090 }
3091
Matus Fabianed3c1602017-09-21 05:07:12 -07003092 proto = ip_proto_to_snat_proto (ip0->protocol);
3093 udp = ip4_next_header (ip0);
3094 port = udp->dst_port;
Matus Fabian066f0342017-02-10 03:48:01 -08003095
Matus Fabianed3c1602017-09-21 05:07:12 -07003096 /* unknown protocol */
3097 if (PREDICT_FALSE (proto == ~0))
Matus Fabian066f0342017-02-10 03:48:01 -08003098 {
Matus Fabiana6110b62018-06-13 05:39:07 -07003099 /* use current thread */
Matus Fabianed3c1602017-09-21 05:07:12 -07003100 return vlib_get_thread_index ();
3101 }
3102
3103 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3104 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003105 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3106 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Klement Sekeraf126e742019-10-10 09:46:06 +00003107 if (!icmp_type_is_error_message
3108 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3109 port = vnet_buffer (b)->ip.reass.l4_src_port;
Matus Fabian066f0342017-02-10 03:48:01 -08003110 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003111 {
Klement Sekeraf126e742019-10-10 09:46:06 +00003112 /* if error message, then it's not fragmented and we can access it */
Matus Fabianab395ec2018-09-20 23:18:41 -07003113 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3114 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3115 void *l4_header = ip4_next_header (inner_ip);
3116 switch (proto)
3117 {
3118 case SNAT_PROTOCOL_ICMP:
3119 icmp = (icmp46_header_t *) l4_header;
3120 echo = (icmp_echo_header_t *) (icmp + 1);
3121 port = echo->identifier;
3122 break;
3123 case SNAT_PROTOCOL_UDP:
3124 case SNAT_PROTOCOL_TCP:
3125 port = ((tcp_udp_header_t *) l4_header)->src_port;
3126 break;
3127 default:
3128 return vlib_get_thread_index ();
3129 }
3130 }
Matus Fabian066f0342017-02-10 03:48:01 -08003131 }
Matus Fabian066f0342017-02-10 03:48:01 -08003132
Matus Fabianed3c1602017-09-21 05:07:12 -07003133 /* try static mappings with port */
3134 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3135 {
3136 m_key.addr = ip0->dst_address;
3137 m_key.port = clib_net_to_host_u16 (port);
3138 m_key.protocol = proto;
3139 m_key.fib_index = rx_fib_index0;
3140 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07003141 if (!clib_bihash_search_8_8
3142 (&sm->static_mapping_by_external, &kv, &value))
3143 {
3144 m = pool_elt_at_index (sm->static_mappings, value.value);
3145 return m->workers[0];
3146 }
Matus Fabianed3c1602017-09-21 05:07:12 -07003147 }
3148
3149 /* worker by outside port */
Matus Fabian10491392018-01-05 05:03:35 -08003150 next_worker_index = sm->first_worker_index;
3151 next_worker_index +=
3152 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3153 return next_worker_index;
Matus Fabian066f0342017-02-10 03:48:01 -08003154}
3155
Matus Fabiana6110b62018-06-13 05:39:07 -07003156static u32
Filip Varga22bb4172019-08-12 14:24:39 +02003157nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3158 u8 is_output)
3159{
3160 snat_main_t *sm = &snat_main;
3161 u32 next_worker_index = sm->first_worker_index;
3162 u32 hash;
3163
3164 clib_bihash_kv_16_8_t kv16, value16;
3165 snat_main_per_thread_data_t *tsm;
3166 udp_header_t *udp;
3167
3168 if (PREDICT_FALSE (is_output))
3169 {
3170 u32 fib_index = sm->outside_fib_index;
3171 nat_outside_fib_t *outside_fib;
3172 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3173 fib_prefix_t pfx = {
3174 .fp_proto = FIB_PROTOCOL_IP4,
3175 .fp_len = 32,
3176 .fp_addr = {
3177 .ip4.as_u32 = ip->dst_address.as_u32,
3178 }
3179 ,
3180 };
3181
3182 udp = ip4_next_header (ip);
3183
3184 switch (vec_len (sm->outside_fibs))
3185 {
3186 case 0:
3187 fib_index = sm->outside_fib_index;
3188 break;
3189 case 1:
3190 fib_index = sm->outside_fibs[0].fib_index;
3191 break;
3192 default:
3193 /* *INDENT-OFF* */
3194 vec_foreach (outside_fib, sm->outside_fibs)
3195 {
3196 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3197 if (FIB_NODE_INDEX_INVALID != fei)
3198 {
3199 if (fib_entry_get_resolving_interface (fei) != ~0)
3200 {
3201 fib_index = outside_fib->fib_index;
3202 break;
3203 }
3204 }
3205 }
3206 /* *INDENT-ON* */
3207 break;
3208 }
3209
3210 make_ed_kv (&kv16, &ip->src_address, &ip->dst_address,
3211 ip->protocol, fib_index, udp->src_port, udp->dst_port);
3212
3213 /* *INDENT-OFF* */
3214 vec_foreach (tsm, sm->per_thread_data)
3215 {
3216 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3217 &kv16, &value16)))
3218 {
3219 next_worker_index += tsm->thread_index;
3220
3221 nat_elog_debug_handoff (
3222 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3223 next_worker_index, fib_index,
3224 clib_net_to_host_u32 (ip->src_address.as_u32),
3225 clib_net_to_host_u32 (ip->dst_address.as_u32));
3226
3227 return next_worker_index;
3228 }
3229 }
3230 /* *INDENT-ON* */
3231 }
3232
3233 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3234 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3235
3236 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3237 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3238 else
3239 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3240
3241 if (PREDICT_TRUE (!is_output))
3242 {
3243 nat_elog_debug_handoff ("HANDOFF IN2OUT",
3244 next_worker_index, rx_fib_index,
3245 clib_net_to_host_u32 (ip->src_address.as_u32),
3246 clib_net_to_host_u32 (ip->dst_address.as_u32));
3247 }
3248 else
3249 {
3250 nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3251 next_worker_index, rx_fib_index,
3252 clib_net_to_host_u32 (ip->src_address.as_u32),
3253 clib_net_to_host_u32 (ip->dst_address.as_u32));
3254 }
3255
3256 return next_worker_index;
3257}
3258
3259static u32
Klement Sekeraf126e742019-10-10 09:46:06 +00003260nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
3261 u32 rx_fib_index, u8 is_output)
Matus Fabiana6110b62018-06-13 05:39:07 -07003262{
3263 snat_main_t *sm = &snat_main;
3264 clib_bihash_kv_8_8_t kv, value;
Filip Varga22bb4172019-08-12 14:24:39 +02003265 clib_bihash_kv_16_8_t kv16, value16;
3266 snat_main_per_thread_data_t *tsm;
3267
Matus Fabiana6110b62018-06-13 05:39:07 -07003268 u32 proto, next_worker_index = 0;
3269 udp_header_t *udp;
3270 u16 port;
3271 snat_static_mapping_t *m;
3272 u32 hash;
3273
Filip Varga22bb4172019-08-12 14:24:39 +02003274 proto = ip_proto_to_snat_proto (ip->protocol);
3275
3276 if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3277 {
3278 udp = ip4_next_header (ip);
3279
3280 make_ed_kv (&kv16, &ip->dst_address, &ip->src_address,
3281 ip->protocol, rx_fib_index, udp->dst_port, udp->src_port);
3282
3283 /* *INDENT-OFF* */
3284 vec_foreach (tsm, sm->per_thread_data)
3285 {
3286 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3287 &kv16, &value16)))
3288 {
3289 next_worker_index = sm->first_worker_index + tsm->thread_index;
3290 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3291 next_worker_index, rx_fib_index,
3292 clib_net_to_host_u32 (ip->src_address.as_u32),
3293 clib_net_to_host_u32 (ip->dst_address.as_u32));
3294 return next_worker_index;
3295 }
3296 }
3297 /* *INDENT-ON* */
3298 }
3299 else if (proto == SNAT_PROTOCOL_ICMP)
3300 {
3301 nat_ed_ses_key_t key;
3302
Klement Sekeraf126e742019-10-10 09:46:06 +00003303 if (!get_icmp_o2i_ed_key (b, ip, &key))
Filip Varga22bb4172019-08-12 14:24:39 +02003304 {
3305
3306 key.fib_index = rx_fib_index;
3307 kv16.key[0] = key.as_u64[0];
3308 kv16.key[1] = key.as_u64[1];
3309
3310 /* *INDENT-OFF* */
3311 vec_foreach (tsm, sm->per_thread_data)
3312 {
3313 if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3314 &kv16, &value16)))
3315 {
3316 next_worker_index = sm->first_worker_index +
3317 tsm->thread_index;
3318 nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3319 next_worker_index, rx_fib_index,
3320 clib_net_to_host_u32 (ip->src_address.as_u32),
3321 clib_net_to_host_u32 (ip->dst_address.as_u32));
3322 return next_worker_index;
3323 }
3324 }
3325 /* *INDENT-ON* */
3326 }
3327 }
3328
Matus Fabiana6110b62018-06-13 05:39:07 -07003329 /* first try static mappings without port */
3330 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3331 {
Filip Vargaacf878b2019-07-15 14:19:44 -04003332 make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -07003333 if (!clib_bihash_search_8_8
3334 (&sm->static_mapping_by_external, &kv, &value))
3335 {
3336 m = pool_elt_at_index (sm->static_mappings, value.value);
Filip Varga22bb4172019-08-12 14:24:39 +02003337 next_worker_index = m->workers[0];
3338 goto done;
Matus Fabianab395ec2018-09-20 23:18:41 -07003339 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003340 }
3341
Matus Fabiana6110b62018-06-13 05:39:07 -07003342 /* unknown protocol */
3343 if (PREDICT_FALSE (proto == ~0))
3344 {
3345 /* use current thread */
Filip Varga22bb4172019-08-12 14:24:39 +02003346 next_worker_index = vlib_get_thread_index ();
3347 goto done;
Matus Fabiana6110b62018-06-13 05:39:07 -07003348 }
3349
3350 udp = ip4_next_header (ip);
3351 port = udp->dst_port;
3352
3353 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3354 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003355 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3356 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Klement Sekeraf126e742019-10-10 09:46:06 +00003357 if (!icmp_type_is_error_message
3358 (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3359 port = vnet_buffer (b)->ip.reass.l4_src_port;
Matus Fabiana6110b62018-06-13 05:39:07 -07003360 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003361 {
Klement Sekeraf126e742019-10-10 09:46:06 +00003362 /* if error message, then it's not fragmented and we can access it */
Matus Fabianab395ec2018-09-20 23:18:41 -07003363 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3364 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3365 void *l4_header = ip4_next_header (inner_ip);
3366 switch (proto)
3367 {
3368 case SNAT_PROTOCOL_ICMP:
3369 icmp = (icmp46_header_t *) l4_header;
3370 echo = (icmp_echo_header_t *) (icmp + 1);
3371 port = echo->identifier;
3372 break;
3373 case SNAT_PROTOCOL_UDP:
3374 case SNAT_PROTOCOL_TCP:
3375 port = ((tcp_udp_header_t *) l4_header)->src_port;
3376 break;
3377 default:
Filip Varga22bb4172019-08-12 14:24:39 +02003378 next_worker_index = vlib_get_thread_index ();
3379 goto done;
Matus Fabianab395ec2018-09-20 23:18:41 -07003380 }
3381 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003382 }
3383
3384 /* try static mappings with port */
3385 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3386 {
Filip Vargaacf878b2019-07-15 14:19:44 -04003387 make_sm_kv (&kv, &ip->dst_address, proto, 0,
Matus Fabianab395ec2018-09-20 23:18:41 -07003388 clib_net_to_host_u16 (port));
3389 if (!clib_bihash_search_8_8
3390 (&sm->static_mapping_by_external, &kv, &value))
3391 {
3392 m = pool_elt_at_index (sm->static_mappings, value.value);
Matus Fabian82b4ceb2018-10-11 04:28:48 -07003393 if (!is_lb_static_mapping (m))
Filip Varga22bb4172019-08-12 14:24:39 +02003394 {
3395 next_worker_index = m->workers[0];
3396 goto done;
3397 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003398
Matus Fabianab395ec2018-09-20 23:18:41 -07003399 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3400 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
Matus Fabiana6110b62018-06-13 05:39:07 -07003401
Matus Fabianab395ec2018-09-20 23:18:41 -07003402 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
Filip Varga22bb4172019-08-12 14:24:39 +02003403 next_worker_index =
3404 m->workers[hash & (_vec_len (m->workers) - 1)];
Matus Fabianab395ec2018-09-20 23:18:41 -07003405 else
Filip Varga22bb4172019-08-12 14:24:39 +02003406 next_worker_index = m->workers[hash % _vec_len (m->workers)];
3407 goto done;
Matus Fabianab395ec2018-09-20 23:18:41 -07003408 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003409 }
3410
3411 /* worker by outside port */
3412 next_worker_index = sm->first_worker_index;
3413 next_worker_index +=
3414 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3415
Filip Varga22bb4172019-08-12 14:24:39 +02003416done:
3417 nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3418 clib_net_to_host_u32 (ip->src_address.as_u32),
3419 clib_net_to_host_u32 (ip->dst_address.as_u32));
Matus Fabiana6110b62018-06-13 05:39:07 -07003420 return next_worker_index;
3421}
3422
Matus Fabian34931eb2019-02-26 09:05:23 -08003423void
3424nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3425 ip4_address_t * out_addr, u16 out_port,
3426 ip4_address_t * eh_addr, u16 eh_port,
3427 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3428 u32 fib_index, u16 flags, u32 thread_index)
3429{
3430 snat_main_t *sm = &snat_main;
3431 snat_session_key_t key;
3432 snat_user_t *u;
3433 snat_session_t *s;
3434 clib_bihash_kv_8_8_t kv;
3435 f64 now = vlib_time_now (sm->vlib_main);
3436 nat_outside_fib_t *outside_fib;
3437 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3438 snat_main_per_thread_data_t *tsm;
3439 fib_prefix_t pfx = {
3440 .fp_proto = FIB_PROTOCOL_IP4,
3441 .fp_len = 32,
3442 .fp_addr = {
3443 .ip4.as_u32 = eh_addr->as_u32,
3444 },
3445 };
3446
3447 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3448
3449 key.addr.as_u32 = out_addr->as_u32;
3450 key.port = out_port;
3451 key.protocol = proto;
3452
3453 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3454 {
3455 if (nat_set_outside_address_and_port
3456 (sm->addresses, thread_index, &key))
3457 return;
3458 }
3459
3460 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3461 if (!u)
3462 return;
3463
3464 s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3465 if (!s)
3466 return;
3467
3468 s->last_heard = now;
3469 s->flags = flags;
3470 s->ext_host_addr.as_u32 = eh_addr->as_u32;
3471 s->ext_host_port = eh_port;
3472 user_session_increment (sm, u, snat_is_session_static (s));
3473 switch (vec_len (sm->outside_fibs))
3474 {
3475 case 0:
3476 key.fib_index = sm->outside_fib_index;
3477 break;
3478 case 1:
3479 key.fib_index = sm->outside_fibs[0].fib_index;
3480 break;
3481 default:
3482 /* *INDENT-OFF* */
3483 vec_foreach (outside_fib, sm->outside_fibs)
3484 {
3485 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3486 if (FIB_NODE_INDEX_INVALID != fei)
3487 {
3488 if (fib_entry_get_resolving_interface (fei) != ~0)
3489 {
3490 key.fib_index = outside_fib->fib_index;
3491 break;
3492 }
3493 }
3494 }
3495 /* *INDENT-ON* */
3496 break;
3497 }
3498 s->out2in = key;
3499 kv.key = key.as_u64;
3500 kv.value = s - tsm->sessions;
3501 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +02003502 nat_elog_warn ("out2in key add failed");
Matus Fabian34931eb2019-02-26 09:05:23 -08003503
3504 key.addr.as_u32 = in_addr->as_u32;
3505 key.port = in_port;
3506 key.fib_index = fib_index;
3507 s->in2out = key;
3508 kv.key = key.as_u64;
3509 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +02003510 nat_elog_warn ("in2out key add failed");
Matus Fabian34931eb2019-02-26 09:05:23 -08003511}
3512
3513void
3514nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3515 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3516 u32 ti)
3517{
3518 snat_main_t *sm = &snat_main;
3519 snat_session_key_t key;
3520 clib_bihash_kv_8_8_t kv, value;
3521 u32 thread_index;
3522 snat_session_t *s;
3523 snat_main_per_thread_data_t *tsm;
3524
3525 if (sm->num_workers > 1)
3526 thread_index =
3527 sm->first_worker_index +
3528 (sm->workers[(clib_net_to_host_u16 (out_port) -
3529 1024) / sm->port_per_thread]);
3530 else
3531 thread_index = sm->num_workers;
3532 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3533
3534 key.addr.as_u32 = out_addr->as_u32;
3535 key.port = out_port;
3536 key.protocol = proto;
3537 key.fib_index = fib_index;
3538 kv.key = key.as_u64;
3539 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3540 return;
3541
3542 s = pool_elt_at_index (tsm->sessions, value.value);
3543 nat_free_session_data (sm, s, thread_index, 1);
3544 nat44_delete_session (sm, s, thread_index);
3545}
3546
3547void
3548nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3549 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3550 u32 total_pkts, u64 total_bytes, u32 thread_index)
3551{
3552 snat_main_t *sm = &snat_main;
3553 snat_session_key_t key;
3554 clib_bihash_kv_8_8_t kv, value;
3555 snat_session_t *s;
3556 snat_main_per_thread_data_t *tsm;
3557
3558 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3559
3560 key.addr.as_u32 = out_addr->as_u32;
3561 key.port = out_port;
3562 key.protocol = proto;
3563 key.fib_index = fib_index;
3564 kv.key = key.as_u64;
3565 if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3566 return;
3567
3568 s = pool_elt_at_index (tsm->sessions, value.value);
3569 s->total_pkts = total_pkts;
3570 s->total_bytes = total_bytes;
3571}
3572
3573void
3574nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3575 ip4_address_t * out_addr, u16 out_port,
3576 ip4_address_t * eh_addr, u16 eh_port,
3577 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3578 u32 fib_index, u16 flags, u32 thread_index)
3579{
3580 snat_main_t *sm = &snat_main;
3581 snat_session_key_t key;
3582 snat_user_t *u;
3583 snat_session_t *s;
3584 clib_bihash_kv_16_8_t kv;
3585 f64 now = vlib_time_now (sm->vlib_main);
3586 nat_outside_fib_t *outside_fib;
3587 fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3588 snat_main_per_thread_data_t *tsm;
3589 fib_prefix_t pfx = {
3590 .fp_proto = FIB_PROTOCOL_IP4,
3591 .fp_len = 32,
3592 .fp_addr = {
3593 .ip4.as_u32 = eh_addr->as_u32,
3594 },
3595 };
3596
3597 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3598
3599 key.addr.as_u32 = out_addr->as_u32;
3600 key.port = out_port;
3601 key.protocol = proto;
3602
3603 if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3604 {
3605 if (nat_set_outside_address_and_port
3606 (sm->addresses, thread_index, &key))
3607 return;
3608 }
3609
3610 key.addr.as_u32 = ehn_addr->as_u32;
3611 key.port = ehn_port;
3612 if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3613 {
3614 if (nat_set_outside_address_and_port
3615 (sm->twice_nat_addresses, thread_index, &key))
3616 return;
3617 }
3618
3619 u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3620 if (!u)
3621 return;
3622
3623 s = nat_ed_session_alloc (sm, u, thread_index, now);
3624 if (!s)
3625 return;
3626
3627 s->last_heard = now;
3628 s->flags = flags;
3629 s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3630 s->ext_host_nat_port = s->ext_host_port = eh_port;
3631 if (is_twice_nat_session (s))
3632 {
3633 s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3634 s->ext_host_nat_port = ehn_port;
3635 }
3636 user_session_increment (sm, u, snat_is_session_static (s));
3637 switch (vec_len (sm->outside_fibs))
3638 {
3639 case 0:
3640 key.fib_index = sm->outside_fib_index;
3641 break;
3642 case 1:
3643 key.fib_index = sm->outside_fibs[0].fib_index;
3644 break;
3645 default:
3646 /* *INDENT-OFF* */
3647 vec_foreach (outside_fib, sm->outside_fibs)
3648 {
3649 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3650 if (FIB_NODE_INDEX_INVALID != fei)
3651 {
3652 if (fib_entry_get_resolving_interface (fei) != ~0)
3653 {
3654 key.fib_index = outside_fib->fib_index;
3655 break;
3656 }
3657 }
3658 }
3659 /* *INDENT-ON* */
3660 break;
3661 }
3662 key.addr.as_u32 = out_addr->as_u32;
3663 key.port = out_port;
3664 s->out2in = key;
3665 kv.value = s - tsm->sessions;
3666
3667 key.addr.as_u32 = in_addr->as_u32;
3668 key.port = in_port;
3669 key.fib_index = fib_index;
3670 s->in2out = key;
3671
3672 make_ed_kv (&kv, in_addr, &s->ext_host_nat_addr,
3673 snat_proto_to_ip_proto (proto), fib_index, in_port,
3674 s->ext_host_nat_port);
3675 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +02003676 nat_elog_warn ("in2out key add failed");
Matus Fabian34931eb2019-02-26 09:05:23 -08003677
3678 make_ed_kv (&kv, out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3679 s->out2in.fib_index, out_port, eh_port);
3680 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
Filip Vargae6e09a42019-07-31 12:45:48 +02003681 nat_elog_warn ("out2in key add failed");
Matus Fabian34931eb2019-02-26 09:05:23 -08003682}
3683
3684void
3685nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3686 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3687 u32 fib_index, u32 ti)
3688{
3689 snat_main_t *sm = &snat_main;
3690 nat_ed_ses_key_t key;
3691 clib_bihash_kv_16_8_t kv, value;
3692 u32 thread_index;
3693 snat_session_t *s;
3694 snat_main_per_thread_data_t *tsm;
3695
3696 if (sm->num_workers > 1)
3697 thread_index =
3698 sm->first_worker_index +
3699 (sm->workers[(clib_net_to_host_u16 (out_port) -
3700 1024) / sm->port_per_thread]);
3701 else
3702 thread_index = sm->num_workers;
3703 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3704
3705 key.l_addr.as_u32 = out_addr->as_u32;
3706 key.l_port = out_port;
3707 key.r_addr.as_u32 = eh_addr->as_u32;
3708 key.r_port = eh_port;
3709 key.proto = proto;
3710 key.fib_index = fib_index;
3711 kv.key[0] = key.as_u64[0];
3712 kv.key[1] = key.as_u64[1];
3713 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3714 return;
3715
3716 s = pool_elt_at_index (tsm->sessions, value.value);
3717 nat_free_session_data (sm, s, thread_index, 1);
3718 nat44_delete_session (sm, s, thread_index);
3719}
3720
3721void
3722nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3723 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3724 u32 fib_index, u32 total_pkts, u64 total_bytes,
3725 u32 thread_index)
3726{
3727 snat_main_t *sm = &snat_main;
3728 nat_ed_ses_key_t key;
3729 clib_bihash_kv_16_8_t kv, value;
3730 snat_session_t *s;
3731 snat_main_per_thread_data_t *tsm;
3732
3733 tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3734
3735 key.l_addr.as_u32 = out_addr->as_u32;
3736 key.l_port = out_port;
3737 key.r_addr.as_u32 = eh_addr->as_u32;
3738 key.r_port = eh_port;
3739 key.proto = proto;
3740 key.fib_index = fib_index;
3741 kv.key[0] = key.as_u64[0];
3742 kv.key[1] = key.as_u64[1];
3743 if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3744 return;
3745
3746 s = pool_elt_at_index (tsm->sessions, value.value);
3747 s->total_pkts = total_pkts;
3748 s->total_bytes = total_bytes;
3749}
3750
Matus Fabianeea28d72017-01-13 04:15:54 -08003751static clib_error_t *
Dave Barach20c02cb2016-06-26 10:42:08 -04003752snat_config (vlib_main_t * vm, unformat_input_t * input)
3753{
Matus Fabianab395ec2018-09-20 23:18:41 -07003754 snat_main_t *sm = &snat_main;
3755 nat66_main_t *nm = &nat66_main;
Filip Vargae6eaa242019-11-27 17:40:29 +01003756 dslite_main_t *dm = &dslite_main;
3757 snat_main_per_thread_data_t *tsm;
3758
3759 u32 static_mapping_buckets = 1024;
3760 u32 static_mapping_memory_size = 64 << 20;
3761
3762 u32 nat64_bib_buckets = 1024;
3763 u32 nat64_bib_memory_size = 128 << 20;
3764
3765 u32 nat64_st_buckets = 2048;
3766 u32 nat64_st_memory_size = 256 << 20;
3767
Dave Barach20c02cb2016-06-26 10:42:08 -04003768 u32 user_buckets = 128;
Matus Fabianab395ec2018-09-20 23:18:41 -07003769 u32 user_memory_size = 64 << 20;
Filip Vargae6eaa242019-11-27 17:40:29 +01003770 u32 translation_buckets = 1024;
3771 u32 translation_memory_size = 128 << 20;
3772
3773 u32 max_translations_per_user = ~0;
3774
Dave Barach20c02cb2016-06-26 10:42:08 -04003775 u32 outside_vrf_id = 0;
Juraj Sloboda9341e342018-04-13 12:00:46 +02003776 u32 outside_ip6_vrf_id = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07003777 u32 inside_vrf_id = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07003778 u8 static_mapping_only = 0;
3779 u8 static_mapping_connection_tracking = 0;
Filip Vargae6eaa242019-11-27 17:40:29 +01003780
3781 u32 udp_timeout = SNAT_UDP_TIMEOUT;
3782 u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
3783
3784 u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3785 u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
Dave Barach20c02cb2016-06-26 10:42:08 -04003786
Matus Fabian066f0342017-02-10 03:48:01 -08003787 sm->deterministic = 0;
Juraj Slobodacba69362017-12-19 02:09:32 +01003788 sm->out2in_dpo = 0;
Matus Fabiana6110b62018-06-13 05:39:07 -07003789 sm->endpoint_dependent = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08003790
Dave Barach20c02cb2016-06-26 10:42:08 -04003791 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3792 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003793 if (unformat
3794 (input, "translation hash buckets %d", &translation_buckets))
3795 ;
Filip Vargae6eaa242019-11-27 17:40:29 +01003796 else if (unformat (input, "udp timeout %d", &udp_timeout))
3797 ;
3798 else if (unformat (input, "icmp timeout %d", &icmp_timeout))
3799 ;
3800 else if (unformat (input, "tcp transitory timeout %d",
3801 &tcp_transitory_timeout));
3802 else if (unformat (input, "tcp established timeout %d",
3803 &tcp_established_timeout));
Dave Barach20c02cb2016-06-26 10:42:08 -04003804 else if (unformat (input, "translation hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003805 &translation_memory_size));
Dave Barach20c02cb2016-06-26 10:42:08 -04003806 else if (unformat (input, "user hash buckets %d", &user_buckets))
Matus Fabianab395ec2018-09-20 23:18:41 -07003807 ;
3808 else if (unformat (input, "user hash memory %d", &user_memory_size))
3809 ;
Dave Barach20c02cb2016-06-26 10:42:08 -04003810 else if (unformat (input, "max translations per user %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003811 &max_translations_per_user))
3812 ;
3813 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3814 ;
3815 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3816 ;
3817 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3818 ;
Matus Fabiandb649882016-08-26 05:45:27 -07003819 else if (unformat (input, "static mapping only"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003820 {
3821 static_mapping_only = 1;
3822 if (unformat (input, "connection tracking"))
3823 static_mapping_connection_tracking = 1;
3824 }
Matus Fabian066f0342017-02-10 03:48:01 -08003825 else if (unformat (input, "deterministic"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003826 sm->deterministic = 1;
Matus Fabian51e759f2017-12-07 23:22:51 -08003827 else if (unformat (input, "nat64 bib hash buckets %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003828 &nat64_bib_buckets))
3829 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08003830 else if (unformat (input, "nat64 bib hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003831 &nat64_bib_memory_size))
3832 ;
3833 else
3834 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3835 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08003836 else if (unformat (input, "nat64 st hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003837 &nat64_st_memory_size))
3838 ;
Juraj Slobodacba69362017-12-19 02:09:32 +01003839 else if (unformat (input, "out2in dpo"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003840 sm->out2in_dpo = 1;
Juraj Slobodac5c6a332018-01-09 16:08:32 +01003841 else if (unformat (input, "dslite ce"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003842 dslite_set_ce (dm, 1);
Matus Fabiana6110b62018-06-13 05:39:07 -07003843 else if (unformat (input, "endpoint-dependent"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003844 sm->endpoint_dependent = 1;
Matus Fabian066f0342017-02-10 03:48:01 -08003845 else
Matus Fabiandb649882016-08-26 05:45:27 -07003846 return clib_error_return (0, "unknown input '%U'",
Dave Barach20c02cb2016-06-26 10:42:08 -04003847 format_unformat_error, input);
3848 }
3849
Matus Fabian69ce30d2018-08-22 01:27:10 -07003850 if (sm->deterministic && sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07003851 return clib_error_return (0,
3852 "deterministic and endpoint-dependent modes are mutually exclusive");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003853
3854 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07003855 return clib_error_return (0,
3856 "static mapping only mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003857
3858 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07003859 return clib_error_return (0,
3860 "out2in dpo mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003861
Filip Vargae6eaa242019-11-27 17:40:29 +01003862 /* optionally configurable timeouts for testing purposes */
3863 sm->udp_timeout = udp_timeout;
3864 sm->icmp_timeout = icmp_timeout;
3865 sm->tcp_transitory_timeout = tcp_transitory_timeout;
3866 sm->tcp_established_timeout = tcp_established_timeout;
3867
Dave Barach20c02cb2016-06-26 10:42:08 -04003868 sm->user_buckets = user_buckets;
3869 sm->user_memory_size = user_memory_size;
Filip Vargae6eaa242019-11-27 17:40:29 +01003870
3871 sm->translation_buckets = translation_buckets;
3872 sm->translation_memory_size = translation_memory_size;
3873
3874 /* do not exceed load factor 10 */
3875 sm->max_translations = 10 * translation_buckets;
3876 sm->max_translations_per_user = max_translations_per_user == ~0 ?
3877 sm->max_translations : max_translations_per_user;
3878
Dave Barach20c02cb2016-06-26 10:42:08 -04003879 sm->outside_vrf_id = outside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08003880 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07003881 outside_vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +00003882 nat_fib_src_hi);
Juraj Sloboda9341e342018-04-13 12:00:46 +02003883 nm->outside_vrf_id = outside_ip6_vrf_id;
3884 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
Matus Fabianab395ec2018-09-20 23:18:41 -07003885 outside_ip6_vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +00003886 nat_fib_src_hi);
Matus Fabiandb649882016-08-26 05:45:27 -07003887 sm->inside_vrf_id = inside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08003888 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07003889 inside_vrf_id,
Neale Ranns3bab8f92019-12-04 06:11:00 +00003890 nat_fib_src_hi);
Matus Fabiandb649882016-08-26 05:45:27 -07003891 sm->static_mapping_only = static_mapping_only;
3892 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
Dave Barach20c02cb2016-06-26 10:42:08 -04003893
Matus Fabianab395ec2018-09-20 23:18:41 -07003894 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
3895 nat64_st_memory_size);
Matus Fabian51e759f2017-12-07 23:22:51 -08003896
Matus Fabian066f0342017-02-10 03:48:01 -08003897 if (sm->deterministic)
Matus Fabiandb649882016-08-26 05:45:27 -07003898 {
Matus Fabian066f0342017-02-10 03:48:01 -08003899 sm->in2out_node_index = snat_det_in2out_node.index;
Matus Fabian93d84c92017-07-19 08:06:01 -07003900 sm->in2out_output_node_index = ~0;
Matus Fabian066f0342017-02-10 03:48:01 -08003901 sm->out2in_node_index = snat_det_out2in_node.index;
Juraj Sloboda7a1bde02017-04-03 08:43:58 +02003902 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
3903 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
Matus Fabiandb649882016-08-26 05:45:27 -07003904 }
Matus Fabian066f0342017-02-10 03:48:01 -08003905 else
3906 {
Matus Fabiana6110b62018-06-13 05:39:07 -07003907 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07003908 {
Filip Varga22bb4172019-08-12 14:24:39 +02003909 sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
Matus Fabianab395ec2018-09-20 23:18:41 -07003910 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02003911
3912 sm->handoff_out2in_index = nat_pre_out2in_node.index;
3913 sm->handoff_in2out_index = nat_pre_in2out_node.index;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02003914 sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
3915
Matus Fabianab395ec2018-09-20 23:18:41 -07003916 sm->in2out_node_index = nat44_ed_in2out_node.index;
3917 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
3918 sm->out2in_node_index = nat44_ed_out2in_node.index;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02003919
Matus Fabianab395ec2018-09-20 23:18:41 -07003920 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
3921 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
3922 nat_affinity_init (vm);
Matus Fabian34931eb2019-02-26 09:05:23 -08003923 nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
3924 nat_ha_sref_ed_cb);
Matus Fabianab395ec2018-09-20 23:18:41 -07003925 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003926 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003927 {
3928 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
3929 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02003930
3931 sm->handoff_out2in_index = snat_in2out_node.index;
3932 sm->handoff_in2out_index = snat_out2in_node.index;
Filip Varga9a6dc8a2019-09-09 16:55:19 +02003933 sm->handoff_in2out_output_index = snat_in2out_output_node.index;
3934
Matus Fabianab395ec2018-09-20 23:18:41 -07003935 sm->in2out_node_index = snat_in2out_node.index;
3936 sm->in2out_output_node_index = snat_in2out_output_node.index;
3937 sm->out2in_node_index = snat_out2in_node.index;
3938 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
3939 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
Matus Fabian34931eb2019-02-26 09:05:23 -08003940 nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
Matus Fabianab395ec2018-09-20 23:18:41 -07003941 }
Matus Fabian066f0342017-02-10 03:48:01 -08003942 if (!static_mapping_only ||
Matus Fabianab395ec2018-09-20 23:18:41 -07003943 (static_mapping_only && static_mapping_connection_tracking))
3944 {
3945 /* *INDENT-OFF* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07003946 vec_foreach (tsm, sm->per_thread_data)
3947 {
Matus Fabiana6110b62018-06-13 05:39:07 -07003948 if (sm->endpoint_dependent)
3949 {
3950 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3951 translation_buckets,
3952 translation_memory_size);
3953 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3954 format_ed_session_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07003955
Matus Fabiana6110b62018-06-13 05:39:07 -07003956 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3957 translation_buckets,
3958 translation_memory_size);
3959 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3960 format_ed_session_kvp);
3961 }
3962 else
3963 {
3964 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3965 translation_buckets,
3966 translation_memory_size);
3967 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
3968 format_session_kvp);
3969
3970 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3971 translation_buckets,
3972 translation_memory_size);
3973 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
3974 format_session_kvp);
3975 }
Matus Fabian092b3cd2017-09-19 05:42:38 -07003976
3977 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3978 user_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003979 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
3980 format_user_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07003981 }
Matus Fabianab395ec2018-09-20 23:18:41 -07003982 /* *INDENT-ON* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07003983
Matus Fabianab395ec2018-09-20 23:18:41 -07003984 }
Juraj Sloboda557a71c2017-02-22 05:16:06 -08003985 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003986 {
3987 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
3988 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
3989 }
Matus Fabian066f0342017-02-10 03:48:01 -08003990 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07003991 "static_mapping_by_local", static_mapping_buckets,
3992 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003993 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07003994 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08003995
3996 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07003997 "static_mapping_by_external",
3998 static_mapping_buckets,
3999 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07004000 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07004001 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08004002 }
4003
Dave Barach20c02cb2016-06-26 10:42:08 -04004004 return 0;
4005}
4006
Matus Fabian2ba92e32017-08-21 07:05:03 -07004007VLIB_CONFIG_FUNCTION (snat_config, "nat");
Dave Barach20c02cb2016-06-26 10:42:08 -04004008
Dave Barachcab65ec2017-01-11 13:01:14 -05004009static void
Matus Fabian4772e7a2018-04-04 00:38:02 -07004010nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07004011 uword opaque,
4012 u32 sw_if_index,
4013 ip4_address_t * address,
4014 u32 address_length,
4015 u32 if_address_index, u32 is_delete)
Matus Fabian4772e7a2018-04-04 00:38:02 -07004016{
4017 snat_main_t *sm = &snat_main;
4018 snat_static_map_resolve_t *rp;
4019 snat_static_mapping_t *m;
4020 snat_session_key_t m_key;
4021 clib_bihash_kv_8_8_t kv, value;
4022 int i, rv;
4023 ip4_address_t l_addr;
4024
4025 for (i = 0; i < vec_len (sm->to_resolve); i++)
4026 {
4027 rp = sm->to_resolve + i;
4028 if (rp->addr_only == 0)
Matus Fabianab395ec2018-09-20 23:18:41 -07004029 continue;
Matus Fabian4772e7a2018-04-04 00:38:02 -07004030 if (rp->sw_if_index == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07004031 goto match;
Matus Fabian4772e7a2018-04-04 00:38:02 -07004032 }
4033
4034 return;
4035
4036match:
4037 m_key.addr.as_u32 = address->as_u32;
4038 m_key.port = rp->addr_only ? 0 : rp->e_port;
4039 m_key.protocol = rp->addr_only ? 0 : rp->proto;
4040 m_key.fib_index = sm->outside_fib_index;
4041 kv.key = m_key.as_u64;
4042 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4043 m = 0;
4044 else
4045 m = pool_elt_at_index (sm->static_mappings, value.value);
4046
4047 if (!is_delete)
4048 {
4049 /* Don't trip over lease renewal, static config */
4050 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07004051 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07004052 }
4053 else
4054 {
4055 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07004056 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07004057 }
4058
4059 /* Indetity mapping? */
4060 if (rp->l_addr.as_u32 == 0)
4061 l_addr.as_u32 = address[0].as_u32;
4062 else
4063 l_addr.as_u32 = rp->l_addr.as_u32;
4064 /* Add the static mapping */
4065 rv = snat_add_static_mapping (l_addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07004066 address[0],
4067 rp->l_port,
4068 rp->e_port,
4069 rp->vrf_id,
4070 rp->addr_only, ~0 /* sw_if_index */ ,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07004071 rp->proto, !is_delete, rp->twice_nat,
4072 rp->out2in_only, rp->tag, rp->identity_nat);
Matus Fabian4772e7a2018-04-04 00:38:02 -07004073 if (rv)
Filip Vargae6e09a42019-07-31 12:45:48 +02004074 nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
Matus Fabian4772e7a2018-04-04 00:38:02 -07004075}
4076
4077static void
Dave Barachcab65ec2017-01-11 13:01:14 -05004078snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07004079 uword opaque,
4080 u32 sw_if_index,
4081 ip4_address_t * address,
4082 u32 address_length,
4083 u32 if_address_index, u32 is_delete)
Dave Barachcab65ec2017-01-11 13:01:14 -05004084{
4085 snat_main_t *sm = &snat_main;
Dave Barach8b275372017-01-16 10:54:02 -05004086 snat_static_map_resolve_t *rp;
Matus Fabianab7a8052017-11-28 04:29:41 -08004087 ip4_address_t l_addr;
Dave Barachcab65ec2017-01-11 13:01:14 -05004088 int i, j;
Dave Barach8b275372017-01-16 10:54:02 -05004089 int rv;
Matus Fabianb932d262017-12-18 05:38:24 -08004090 u8 twice_nat = 0;
4091 snat_address_t *addresses = sm->addresses;
Dave Barachcab65ec2017-01-11 13:01:14 -05004092
Matus Fabianab395ec2018-09-20 23:18:41 -07004093 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05004094 {
4095 if (sw_if_index == sm->auto_add_sw_if_indices[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07004096 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08004097 }
Dave Barachcab65ec2017-01-11 13:01:14 -05004098
Matus Fabianab395ec2018-09-20 23:18:41 -07004099 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
Matus Fabianb932d262017-12-18 05:38:24 -08004100 {
4101 twice_nat = 1;
4102 addresses = sm->twice_nat_addresses;
4103 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07004104 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08004105 }
4106
4107 return;
4108
4109match:
4110 if (!is_delete)
4111 {
4112 /* Don't trip over lease renewal, static config */
Matus Fabianab395ec2018-09-20 23:18:41 -07004113 for (j = 0; j < vec_len (addresses); j++)
4114 if (addresses[j].addr.as_u32 == address->as_u32)
4115 return;
Matus Fabianb932d262017-12-18 05:38:24 -08004116
Matus Fabiana6110b62018-06-13 05:39:07 -07004117 (void) snat_add_address (sm, address, ~0, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08004118 /* Scan static map resolution vector */
4119 for (j = 0; j < vec_len (sm->to_resolve); j++)
Matus Fabianab395ec2018-09-20 23:18:41 -07004120 {
4121 rp = sm->to_resolve + j;
4122 if (rp->addr_only)
4123 continue;
4124 /* On this interface? */
4125 if (rp->sw_if_index == sw_if_index)
4126 {
4127 /* Indetity mapping? */
4128 if (rp->l_addr.as_u32 == 0)
4129 l_addr.as_u32 = address[0].as_u32;
4130 else
4131 l_addr.as_u32 = rp->l_addr.as_u32;
4132 /* Add the static mapping */
4133 rv = snat_add_static_mapping (l_addr,
4134 address[0],
4135 rp->l_port,
4136 rp->e_port,
4137 rp->vrf_id,
4138 rp->addr_only,
4139 ~0 /* sw_if_index */ ,
4140 rp->proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07004141 rp->is_add, rp->twice_nat,
4142 rp->out2in_only, rp->tag,
4143 rp->identity_nat);
Matus Fabianab395ec2018-09-20 23:18:41 -07004144 if (rv)
Filip Vargae6e09a42019-07-31 12:45:48 +02004145 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4146 "i4", rv);
Matus Fabianab395ec2018-09-20 23:18:41 -07004147 }
4148 }
Matus Fabianb932d262017-12-18 05:38:24 -08004149 return;
4150 }
4151 else
4152 {
Matus Fabianab395ec2018-09-20 23:18:41 -07004153 (void) snat_del_address (sm, address[0], 1, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08004154 return;
Dave Barachcab65ec2017-01-11 13:01:14 -05004155 }
4156}
4157
4158
Matus Fabianab395ec2018-09-20 23:18:41 -07004159int
4160snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4161 u8 twice_nat)
Dave Barachcab65ec2017-01-11 13:01:14 -05004162{
Matus Fabianab395ec2018-09-20 23:18:41 -07004163 ip4_main_t *ip4_main = sm->ip4_main;
4164 ip4_address_t *first_int_addr;
Matus Fabian36532bd2017-01-23 23:42:28 -08004165 snat_static_map_resolve_t *rp;
4166 u32 *indices_to_delete = 0;
4167 int i, j;
Matus Fabianb932d262017-12-18 05:38:24 -08004168 u32 *auto_add_sw_if_indices =
Matus Fabianab395ec2018-09-20 23:18:41 -07004169 twice_nat ? sm->
4170 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
Dave Barachcab65ec2017-01-11 13:01:14 -05004171
Matus Fabianab395ec2018-09-20 23:18:41 -07004172 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
4173 );
Dave Barachcab65ec2017-01-11 13:01:14 -05004174
Matus Fabianab395ec2018-09-20 23:18:41 -07004175 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05004176 {
Matus Fabianb932d262017-12-18 05:38:24 -08004177 if (auto_add_sw_if_indices[i] == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07004178 {
4179 if (is_del)
4180 {
4181 /* if have address remove it */
4182 if (first_int_addr)
4183 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4184 else
4185 {
4186 for (j = 0; j < vec_len (sm->to_resolve); j++)
4187 {
4188 rp = sm->to_resolve + j;
4189 if (rp->sw_if_index == sw_if_index)
4190 vec_add1 (indices_to_delete, j);
4191 }
4192 if (vec_len (indices_to_delete))
4193 {
4194 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4195 vec_del1 (sm->to_resolve, j);
4196 vec_free (indices_to_delete);
4197 }
4198 }
4199 if (twice_nat)
4200 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4201 else
4202 vec_del1 (sm->auto_add_sw_if_indices, i);
4203 }
4204 else
4205 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian8bf68e82017-01-12 04:24:35 -08004206
Matus Fabianab395ec2018-09-20 23:18:41 -07004207 return 0;
4208 }
Dave Barachcab65ec2017-01-11 13:01:14 -05004209 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07004210
Matus Fabian8bf68e82017-01-12 04:24:35 -08004211 if (is_del)
4212 return VNET_API_ERROR_NO_SUCH_ENTRY;
4213
Dave Barachcab65ec2017-01-11 13:01:14 -05004214 /* add to the auto-address list */
Matus Fabianb932d262017-12-18 05:38:24 -08004215 if (twice_nat)
Matus Fabianab395ec2018-09-20 23:18:41 -07004216 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
Matus Fabianb932d262017-12-18 05:38:24 -08004217 else
Matus Fabianab395ec2018-09-20 23:18:41 -07004218 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
Dave Barachcab65ec2017-01-11 13:01:14 -05004219
4220 /* If the address is already bound - or static - add it now */
4221 if (first_int_addr)
Matus Fabianab395ec2018-09-20 23:18:41 -07004222 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
Dave Barachcab65ec2017-01-11 13:01:14 -05004223
4224 return 0;
4225}
4226
Matus Fabian5ba86f72017-10-26 03:37:38 -07004227int
Matus Fabianab395ec2018-09-20 23:18:41 -07004228nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4229 snat_protocol_t proto, u32 vrf_id, int is_in)
Matus Fabian5ba86f72017-10-26 03:37:38 -07004230{
4231 snat_main_per_thread_data_t *tsm;
4232 clib_bihash_kv_8_8_t kv, value;
4233 ip4_header_t ip;
4234 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4235 snat_session_key_t key;
4236 snat_session_t *s;
4237 clib_bihash_8_8_t *t;
Matus Fabian5ba86f72017-10-26 03:37:38 -07004238
Matus Fabiana6110b62018-06-13 05:39:07 -07004239 if (sm->endpoint_dependent)
4240 return VNET_API_ERROR_UNSUPPORTED;
4241
Matus Fabian5ba86f72017-10-26 03:37:38 -07004242 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
Matus Fabian4888b502018-03-27 01:07:25 -07004243 if (sm->num_workers > 1)
Matus Fabian5ba86f72017-10-26 03:37:38 -07004244 tsm =
4245 vec_elt_at_index (sm->per_thread_data,
Filip Varga22bb4172019-08-12 14:24:39 +02004246 sm->worker_in2out_cb (&ip, fib_index, 0));
Matus Fabian5ba86f72017-10-26 03:37:38 -07004247 else
4248 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4249
4250 key.addr.as_u32 = addr->as_u32;
4251 key.port = clib_host_to_net_u16 (port);
4252 key.protocol = proto;
4253 key.fib_index = fib_index;
4254 kv.key = key.as_u64;
4255 t = is_in ? &tsm->in2out : &tsm->out2in;
4256 if (!clib_bihash_search_8_8 (t, &kv, &value))
4257 {
Matus Fabian70a26ac2018-05-14 06:20:28 -07004258 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabianab395ec2018-09-20 23:18:41 -07004259 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07004260
Matus Fabian5ba86f72017-10-26 03:37:38 -07004261 s = pool_elt_at_index (tsm->sessions, value.value);
Matus Fabian34931eb2019-02-26 09:05:23 -08004262 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
Matus Fabian229c1aa2018-05-28 04:09:52 -07004263 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian5ba86f72017-10-26 03:37:38 -07004264 return 0;
4265 }
4266
4267 return VNET_API_ERROR_NO_SUCH_ENTRY;
4268}
4269
Matus Fabian70a26ac2018-05-14 06:20:28 -07004270int
Matus Fabianab395ec2018-09-20 23:18:41 -07004271nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4272 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4273 u32 vrf_id, int is_in)
Matus Fabian70a26ac2018-05-14 06:20:28 -07004274{
4275 ip4_header_t ip;
4276 clib_bihash_16_8_t *t;
4277 nat_ed_ses_key_t key;
4278 clib_bihash_kv_16_8_t kv, value;
Matus Fabian70a26ac2018-05-14 06:20:28 -07004279 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4280 snat_session_t *s;
Matus Fabiana6110b62018-06-13 05:39:07 -07004281 snat_main_per_thread_data_t *tsm;
4282
4283 if (!sm->endpoint_dependent)
4284 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07004285
4286 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4287 if (sm->num_workers > 1)
Matus Fabiana6110b62018-06-13 05:39:07 -07004288 tsm =
4289 vec_elt_at_index (sm->per_thread_data,
Filip Varga22bb4172019-08-12 14:24:39 +02004290 sm->worker_in2out_cb (&ip, fib_index, 0));
Matus Fabian70a26ac2018-05-14 06:20:28 -07004291 else
Matus Fabiana6110b62018-06-13 05:39:07 -07004292 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabian70a26ac2018-05-14 06:20:28 -07004293
Matus Fabiana6110b62018-06-13 05:39:07 -07004294 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
Matus Fabian70a26ac2018-05-14 06:20:28 -07004295 key.l_addr.as_u32 = addr->as_u32;
4296 key.r_addr.as_u32 = eh_addr->as_u32;
4297 key.l_port = clib_host_to_net_u16 (port);
4298 key.r_port = clib_host_to_net_u16 (eh_port);
4299 key.proto = proto;
Matus Fabianab395ec2018-09-20 23:18:41 -07004300 key.fib_index = fib_index;
Matus Fabian70a26ac2018-05-14 06:20:28 -07004301 kv.key[0] = key.as_u64[0];
4302 kv.key[1] = key.as_u64[1];
4303 if (clib_bihash_search_16_8 (t, &kv, &value))
4304 return VNET_API_ERROR_NO_SUCH_ENTRY;
4305
Matus Fabiana6110b62018-06-13 05:39:07 -07004306 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabian70a26ac2018-05-14 06:20:28 -07004307 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabiana6110b62018-06-13 05:39:07 -07004308 s = pool_elt_at_index (tsm->sessions, value.value);
Matus Fabian34931eb2019-02-26 09:05:23 -08004309 nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
Matus Fabiana6110b62018-06-13 05:39:07 -07004310 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian70a26ac2018-05-14 06:20:28 -07004311 return 0;
4312}
4313
Matus Fabian82119542018-01-25 01:13:22 -08004314void
4315nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
Matus Fabian5ba86f72017-10-26 03:37:38 -07004316{
4317 snat_main_t *sm = &snat_main;
Matus Fabian5ba86f72017-10-26 03:37:38 -07004318
Matus Fabian5d28c7a2018-09-04 03:55:45 -07004319 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
Matus Fabian82119542018-01-25 01:13:22 -08004320 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4321 sm->psid = psid;
4322 sm->psid_offset = psid_offset;
4323 sm->psid_length = psid_length;
Matus Fabian5ba86f72017-10-26 03:37:38 -07004324}
4325
Matus Fabian82119542018-01-25 01:13:22 -08004326void
Matus Fabian5d28c7a2018-09-04 03:55:45 -07004327nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4328{
4329 snat_main_t *sm = &snat_main;
4330
4331 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4332 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4333 sm->start_port = start_port;
4334 sm->end_port = end_port;
4335}
4336
4337void
Matus Fabian82119542018-01-25 01:13:22 -08004338nat_set_alloc_addr_and_port_default (void)
Matus Fabian27697102017-11-09 01:43:47 -08004339{
4340 snat_main_t *sm = &snat_main;
Matus Fabian27697102017-11-09 01:43:47 -08004341
Matus Fabian5d28c7a2018-09-04 03:55:45 -07004342 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Matus Fabian82119542018-01-25 01:13:22 -08004343 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian066f0342017-02-10 03:48:01 -08004344}
4345
Filip Varga9a6dc8a2019-09-09 16:55:19 +02004346VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4347 vlib_node_runtime_t * node,
4348 vlib_frame_t * frame)
4349{
4350 return 0;
4351}
4352
4353/* *INDENT-OFF* */
4354VLIB_REGISTER_NODE (nat_default_node) = {
4355 .name = "nat-default",
4356 .vector_size = sizeof (u32),
4357 .format_trace = 0,
4358 .type = VLIB_NODE_TYPE_INTERNAL,
4359 .n_errors = 0,
4360 .n_next_nodes = NAT_N_NEXT,
4361 .next_nodes = {
4362 [NAT_NEXT_DROP] = "error-drop",
4363 [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4364 [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4365 [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4366 [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4367 [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4368 [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
Filip Varga9a6dc8a2019-09-09 16:55:19 +02004369 [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4370 [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
Filip Varga9a6dc8a2019-09-09 16:55:19 +02004371 },
4372};
4373/* *INDENT-ON* */
4374
Matus Fabianab395ec2018-09-20 23:18:41 -07004375/*
4376 * fd.io coding-style-patch-verification: ON
4377 *
4378 * Local Variables:
4379 * eval: (c-set-style "gnu")
4380 * End:
4381 */