blob: 4e9d5023b3f5a484ab20f268e8788bc01820b15b [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 Fabianefcd1e92017-08-15 06:59:19 -070029#include <nat/nat_reass.h>
Matus Fabian229c1aa2018-05-28 04:09:52 -070030#include <nat/nat_inlines.h>
Matus Fabianea5b5be2018-09-03 05:02:23 -070031#include <nat/nat_affinity.h>
Matus Fabianad1f3e12018-11-28 21:26:34 -080032#include <nat/nat_syslog.h>
Matus Fabiane1ae29a2017-01-27 00:47:58 -080033#include <vnet/fib/fib_table.h>
34#include <vnet/fib/ip4_fib.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040035
Damjan Marion3b46cba2017-01-23 21:13:45 +010036#include <vpp/app/version.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040037
38snat_main_t snat_main;
39
Matus Fabianab395ec2018-09-20 23:18:41 -070040/* *INDENT-OFF* */
Dave Barach20c02cb2016-06-26 10:42:08 -040041
Dave Barach20c02cb2016-06-26 10:42:08 -040042/* Hook up input features */
Damjan Marion8b3191e2016-11-09 19:54:20 +010043VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
44 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070045 .node_name = "nat44-in2out",
Matus Fabian16f05462018-02-08 05:28:28 -080046 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Dave Barach20c02cb2016-06-26 10:42:08 -040047};
Damjan Marion8b3191e2016-11-09 19:54:20 +010048VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
49 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070050 .node_name = "nat44-out2in",
Matus Fabiana6110b62018-06-13 05:39:07 -070051 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
Dave Barach525c9d02018-05-26 10:48:55 -040052 "ip4-dhcp-client-detect"),
Dave Barach20c02cb2016-06-26 10:42:08 -040053};
Matus Fabian36ea2d62017-10-24 04:13:49 -070054VNET_FEATURE_INIT (ip4_nat_classify, static) = {
55 .arc_name = "ip4-unicast",
56 .node_name = "nat44-classify",
Matus Fabian16f05462018-02-08 05:28:28 -080057 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -070058};
Matus Fabian066f0342017-02-10 03:48:01 -080059VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
60 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070061 .node_name = "nat44-det-in2out",
Matus Fabian16f05462018-02-08 05:28:28 -080062 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian066f0342017-02-10 03:48:01 -080063};
64VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
65 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070066 .node_name = "nat44-det-out2in",
Matus Fabiana6110b62018-06-13 05:39:07 -070067 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
68 "ip4-dhcp-client-detect"),
Matus Fabian066f0342017-02-10 03:48:01 -080069};
Matus Fabian36ea2d62017-10-24 04:13:49 -070070VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
71 .arc_name = "ip4-unicast",
72 .node_name = "nat44-det-classify",
Matus Fabian16f05462018-02-08 05:28:28 -080073 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -070074};
Matus Fabiana6110b62018-06-13 05:39:07 -070075VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
76 .arc_name = "ip4-unicast",
77 .node_name = "nat44-ed-in2out",
78 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
79};
80VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
81 .arc_name = "ip4-unicast",
82 .node_name = "nat44-ed-out2in",
83 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
84 "ip4-dhcp-client-detect"),
85};
86VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
87 .arc_name = "ip4-unicast",
88 .node_name = "nat44-ed-classify",
89 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
90};
Matus Fabian475f0552016-10-19 06:17:52 -070091VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
92 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070093 .node_name = "nat44-in2out-worker-handoff",
Matus Fabian16f05462018-02-08 05:28:28 -080094 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian475f0552016-10-19 06:17:52 -070095};
96VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
97 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070098 .node_name = "nat44-out2in-worker-handoff",
Matus Fabiana6110b62018-06-13 05:39:07 -070099 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
100 "ip4-dhcp-client-detect"),
Matus Fabian475f0552016-10-19 06:17:52 -0700101};
Matus Fabian36ea2d62017-10-24 04:13:49 -0700102VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
103 .arc_name = "ip4-unicast",
104 .node_name = "nat44-handoff-classify",
Matus Fabian16f05462018-02-08 05:28:28 -0800105 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -0700106};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100107VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
108 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700109 .node_name = "nat44-in2out-fast",
Matus Fabian16f05462018-02-08 05:28:28 -0800110 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabiandb649882016-08-26 05:45:27 -0700111};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100112VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
113 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700114 .node_name = "nat44-out2in-fast",
Matus Fabiana6110b62018-06-13 05:39:07 -0700115 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
116 "ip4-dhcp-client-detect"),
Matus Fabiandb649882016-08-26 05:45:27 -0700117};
Matus Fabian161c59c2017-07-21 03:46:03 -0700118VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
119 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700120 .node_name = "nat44-hairpin-dst",
Matus Fabian16f05462018-02-08 05:28:28 -0800121 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700122};
Matus Fabiana6110b62018-06-13 05:39:07 -0700123VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
124 .arc_name = "ip4-unicast",
125 .node_name = "nat44-ed-hairpin-dst",
126 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
127};
Matus Fabiandb649882016-08-26 05:45:27 -0700128
Matus Fabian93d84c92017-07-19 08:06:01 -0700129/* Hook up output features */
130VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
131 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700132 .node_name = "nat44-in2out-output",
Matus Fabian16f05462018-02-08 05:28:28 -0800133 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700134};
Matus Fabian93d84c92017-07-19 08:06:01 -0700135VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
136 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700137 .node_name = "nat44-in2out-output-worker-handoff",
Matus Fabian16f05462018-02-08 05:28:28 -0800138 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700139};
Matus Fabian161c59c2017-07-21 03:46:03 -0700140VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
141 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700142 .node_name = "nat44-hairpin-src",
Matus Fabian16f05462018-02-08 05:28:28 -0800143 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700144};
Matus Fabiana6110b62018-06-13 05:39:07 -0700145VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
146 .arc_name = "ip4-output",
147 .node_name = "nat44-ed-in2out-output",
148 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
149};
150VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
151 .arc_name = "ip4-output",
152 .node_name = "nat44-ed-hairpin-src",
153 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
154};
Matus Fabian93d84c92017-07-19 08:06:01 -0700155
Matus Fabian87da4762017-10-04 08:03:56 -0700156/* Hook up ip4-local features */
157VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
158{
159 .arc_name = "ip4-local",
160 .node_name = "nat44-hairpinning",
161 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
162};
Matus Fabiana6110b62018-06-13 05:39:07 -0700163VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
164{
165 .arc_name = "ip4-local",
166 .node_name = "nat44-ed-hairpinning",
167 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
168};
Matus Fabian87da4762017-10-04 08:03:56 -0700169
Matus Fabian93d84c92017-07-19 08:06:01 -0700170
Damjan Marion3b46cba2017-01-23 21:13:45 +0100171VLIB_PLUGIN_REGISTER () = {
172 .version = VPP_BUILD_VER,
Damjan Marion1bfb0dd2017-03-22 11:08:39 +0100173 .description = "Network Address Translation",
Damjan Marion3b46cba2017-01-23 21:13:45 +0100174};
175/* *INDENT-ON* */
Dave Barach20c02cb2016-06-26 10:42:08 -0400176
Matus Fabianb932d262017-12-18 05:38:24 -0800177void
178nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
179{
180 snat_session_key_t key;
181 clib_bihash_kv_8_8_t kv;
182 nat_ed_ses_key_t ed_key;
183 clib_bihash_kv_16_8_t ed_kv;
Matus Fabianb932d262017-12-18 05:38:24 -0800184 snat_main_per_thread_data_t *tsm =
185 vec_elt_at_index (sm->per_thread_data, thread_index);
186
Matus Fabian36ed73a2018-04-18 01:39:17 -0700187 if (is_fwd_bypass_session (s))
188 {
189 ed_key.l_addr = s->in2out.addr;
190 ed_key.r_addr = s->ext_host_addr;
191 ed_key.l_port = s->in2out.port;
192 ed_key.r_port = s->ext_host_port;
193 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
194 ed_key.fib_index = 0;
195 ed_kv.key[0] = ed_key.as_u64[0];
196 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700197 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700198 nat_log_warn ("in2out_ed key del failed");
Matus Fabian36ed73a2018-04-18 01:39:17 -0700199 return;
200 }
201
Matus Fabiana6110b62018-06-13 05:39:07 -0700202 /* session lookup tables */
Matus Fabianb932d262017-12-18 05:38:24 -0800203 if (is_ed_session (s))
204 {
Matus Fabianea5b5be2018-09-03 05:02:23 -0700205 if (is_affinity_sessions (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700206 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
207 s->in2out.protocol, s->out2in.port);
Matus Fabianb932d262017-12-18 05:38:24 -0800208 ed_key.l_addr = s->out2in.addr;
209 ed_key.r_addr = s->ext_host_addr;
210 ed_key.fib_index = s->out2in.fib_index;
211 if (snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700212 {
213 ed_key.proto = s->in2out.port;
214 ed_key.r_port = 0;
215 ed_key.l_port = 0;
216 }
Matus Fabianb932d262017-12-18 05:38:24 -0800217 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700218 {
219 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
220 ed_key.l_port = s->out2in.port;
221 ed_key.r_port = s->ext_host_port;
222 }
Matus Fabianb932d262017-12-18 05:38:24 -0800223 ed_kv.key[0] = ed_key.as_u64[0];
224 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700225 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700226 nat_log_warn ("out2in_ed key del failed");
Matus Fabianb932d262017-12-18 05:38:24 -0800227 ed_key.l_addr = s->in2out.addr;
228 ed_key.fib_index = s->in2out.fib_index;
229 if (!snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700230 ed_key.l_port = s->in2out.port;
Matus Fabianb932d262017-12-18 05:38:24 -0800231 if (is_twice_nat_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700232 {
233 ed_key.r_addr = s->ext_host_nat_addr;
234 ed_key.r_port = s->ext_host_nat_port;
235 }
Matus Fabianb932d262017-12-18 05:38:24 -0800236 ed_kv.key[0] = ed_key.as_u64[0];
237 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700238 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700239 nat_log_warn ("in2out_ed key del failed");
Matus Fabianad1f3e12018-11-28 21:26:34 -0800240
241 nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
242 &s->in2out.addr, s->in2out.port,
243 &s->ext_host_nat_addr, s->ext_host_nat_port,
244 &s->out2in.addr, s->out2in.port,
245 &s->ext_host_addr, s->ext_host_port,
246 s->in2out.protocol, is_twice_nat_session (s));
Matus Fabianb932d262017-12-18 05:38:24 -0800247 }
Matus Fabiana6110b62018-06-13 05:39:07 -0700248 else
249 {
250 kv.key = s->in2out.as_u64;
251 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700252 nat_log_warn ("in2out key del failed");
Matus Fabiana6110b62018-06-13 05:39:07 -0700253 kv.key = s->out2in.as_u64;
254 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700255 nat_log_warn ("out2in key del failed");
Matus Fabianad1f3e12018-11-28 21:26:34 -0800256
257 nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
258 &s->in2out.addr, s->in2out.port,
259 &s->out2in.addr, s->out2in.port,
260 s->in2out.protocol);
Matus Fabiana6110b62018-06-13 05:39:07 -0700261 }
Matus Fabianb932d262017-12-18 05:38:24 -0800262
263 if (snat_is_unk_proto_session (s))
264 return;
265
266 /* log NAT event */
Filip Varga8254ab82019-01-21 00:05:03 -0800267 snat_ipfix_logging_nat44_ses_delete (thread_index,
268 s->in2out.addr.as_u32,
Matus Fabianab395ec2018-09-20 23:18:41 -0700269 s->out2in.addr.as_u32,
270 s->in2out.protocol,
271 s->in2out.port,
272 s->out2in.port, s->in2out.fib_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800273
274 /* Twice NAT address and port for external host */
Matus Fabian70a26ac2018-05-14 06:20:28 -0700275 if (is_twice_nat_session (s))
Matus Fabianb932d262017-12-18 05:38:24 -0800276 {
shubing guo762a4932018-08-13 17:16:46 +0800277 key.protocol = s->in2out.protocol;
278 key.port = s->ext_host_nat_port;
279 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
280 snat_free_outside_address_and_port (sm->twice_nat_addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -0700281 thread_index, &key);
Matus Fabianb932d262017-12-18 05:38:24 -0800282 }
283
Matus Fabianb932d262017-12-18 05:38:24 -0800284 if (snat_is_session_static (s))
285 return;
286
Matus Fabianab395ec2018-09-20 23:18:41 -0700287 snat_free_outside_address_and_port (sm->addresses, thread_index,
288 &s->out2in);
Matus Fabianb932d262017-12-18 05:38:24 -0800289}
290
291snat_user_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700292nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
293 u32 thread_index)
Matus Fabianb932d262017-12-18 05:38:24 -0800294{
295 snat_user_t *u = 0;
296 snat_user_key_t user_key;
297 clib_bihash_kv_8_8_t kv, value;
298 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabianab395ec2018-09-20 23:18:41 -0700299 dlist_elt_t *per_user_list_head_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800300
301 user_key.addr.as_u32 = addr->as_u32;
302 user_key.fib_index = fib_index;
303 kv.key = user_key.as_u64;
304
305 /* Ever heard of the "user" = src ip4 address before? */
306 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
307 {
308 /* no, make a new one */
309 pool_get (tsm->users, u);
Dave Barachb7b92992018-10-17 10:38:51 -0400310 clib_memset (u, 0, sizeof (*u));
Matus Fabianb932d262017-12-18 05:38:24 -0800311 u->addr.as_u32 = addr->as_u32;
312 u->fib_index = fib_index;
313
314 pool_get (tsm->list_pool, per_user_list_head_elt);
315
316 u->sessions_per_user_list_head_index = per_user_list_head_elt -
Matus Fabianab395ec2018-09-20 23:18:41 -0700317 tsm->list_pool;
Matus Fabianb932d262017-12-18 05:38:24 -0800318
319 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
320
321 kv.value = u - tsm->users;
322
323 /* add user */
324 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
Matus Fabianab395ec2018-09-20 23:18:41 -0700325 nat_log_warn ("user_hash keay add failed");
Matus Fabianfd0d5082018-12-18 01:08:51 -0800326
327 vlib_set_simple_counter (&sm->total_users, thread_index, 0,
328 pool_elts (tsm->users));
Matus Fabianb932d262017-12-18 05:38:24 -0800329 }
330 else
331 {
332 u = pool_elt_at_index (tsm->users, value.value);
333 }
334
335 return u;
336}
337
338snat_session_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700339nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
340 u32 thread_index)
Matus Fabianb932d262017-12-18 05:38:24 -0800341{
342 snat_session_t *s;
343 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
344 u32 oldest_per_user_translation_list_index, session_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700345 dlist_elt_t *oldest_per_user_translation_list_elt;
346 dlist_elt_t *per_user_translation_list_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800347
348 /* Over quota? Recycle the least recently used translation */
349 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
350 {
351 oldest_per_user_translation_list_index =
Matus Fabianab395ec2018-09-20 23:18:41 -0700352 clib_dlist_remove_head (tsm->list_pool,
353 u->sessions_per_user_list_head_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800354
355 ASSERT (oldest_per_user_translation_list_index != ~0);
356
357 /* Add it back to the end of the LRU list */
358 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700359 u->sessions_per_user_list_head_index,
360 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800361 /* Get the list element */
362 oldest_per_user_translation_list_elt =
Matus Fabianab395ec2018-09-20 23:18:41 -0700363 pool_elt_at_index (tsm->list_pool,
364 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800365
366 /* Get the session index from the list element */
367 session_index = oldest_per_user_translation_list_elt->value;
368
369 /* Get the session */
370 s = pool_elt_at_index (tsm->sessions, session_index);
371 nat_free_session_data (sm, s, thread_index);
Matus Fabianab395ec2018-09-20 23:18:41 -0700372 if (snat_is_session_static (s))
373 u->nstaticsessions--;
Matus Fabian132dc492018-05-09 04:51:03 -0700374 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700375 u->nsessions--;
Matus Fabianb932d262017-12-18 05:38:24 -0800376 s->flags = 0;
377 s->total_bytes = 0;
378 s->total_pkts = 0;
Matus Fabianebdf1902018-05-04 03:57:42 -0700379 s->state = 0;
380 s->ext_host_addr.as_u32 = 0;
381 s->ext_host_port = 0;
382 s->ext_host_nat_addr.as_u32 = 0;
383 s->ext_host_nat_port = 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800384 }
385 else
386 {
387 pool_get (tsm->sessions, s);
Dave Barachb7b92992018-10-17 10:38:51 -0400388 clib_memset (s, 0, sizeof (*s));
Matus Fabianb932d262017-12-18 05:38:24 -0800389
390 /* Create list elts */
391 pool_get (tsm->list_pool, per_user_translation_list_elt);
392 clib_dlist_init (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700393 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianb932d262017-12-18 05:38:24 -0800394
395 per_user_translation_list_elt->value = s - tsm->sessions;
396 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
397 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
398
399 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700400 s->per_user_list_head_index,
401 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianad1f3e12018-11-28 21:26:34 -0800402
403 s->user_index = u - tsm->users;
Matus Fabianfd0d5082018-12-18 01:08:51 -0800404 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
405 pool_elts (tsm->sessions));
Matus Fabianb932d262017-12-18 05:38:24 -0800406 }
407
408 return s;
409}
410
Matus Fabian878c6462018-08-23 00:33:35 -0700411snat_session_t *
Matus Fabian8fdc0152018-09-24 04:41:28 -0700412nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
413 f64 now)
Matus Fabian878c6462018-08-23 00:33:35 -0700414{
415 snat_session_t *s;
416 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabian8fdc0152018-09-24 04:41:28 -0700417 dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
418 u32 oldest_index;
419 u64 sess_timeout_time;
Matus Fabian878c6462018-08-23 00:33:35 -0700420
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800421 if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
422 goto alloc_new;
423
424 oldest_index =
425 clib_dlist_remove_head (tsm->list_pool,
426 u->sessions_per_user_list_head_index);
427 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
428 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
429 sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
430 if (now >= sess_timeout_time)
Matus Fabian878c6462018-08-23 00:33:35 -0700431 {
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800432 clib_dlist_addtail (tsm->list_pool,
433 u->sessions_per_user_list_head_index, oldest_index);
434 nat_free_session_data (sm, s, thread_index);
435 if (snat_is_session_static (s))
436 u->nstaticsessions--;
Matus Fabian8fdc0152018-09-24 04:41:28 -0700437 else
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800438 u->nsessions--;
439 s->flags = 0;
440 s->total_bytes = 0;
441 s->total_pkts = 0;
442 s->state = 0;
443 s->ext_host_addr.as_u32 = 0;
444 s->ext_host_port = 0;
445 s->ext_host_nat_addr.as_u32 = 0;
446 s->ext_host_nat_port = 0;
447 }
448 else
449 {
450 clib_dlist_addhead (tsm->list_pool,
451 u->sessions_per_user_list_head_index, oldest_index);
452 if ((u->nsessions + u->nstaticsessions) >=
453 sm->max_translations_per_user)
Matus Fabian8fdc0152018-09-24 04:41:28 -0700454 {
Matus Fabian8fdc0152018-09-24 04:41:28 -0700455 nat_log_warn ("max translations per user %U", format_ip4_address,
456 &u->addr);
457 snat_ipfix_logging_max_entries_per_user
Filip Varga8254ab82019-01-21 00:05:03 -0800458 (thread_index, sm->max_translations_per_user, u->addr.as_u32);
Matus Fabian8fdc0152018-09-24 04:41:28 -0700459 return 0;
460 }
Matus Fabian7f8a8db2018-11-22 00:12:15 -0800461 else
462 {
463 alloc_new:
464 pool_get (tsm->sessions, s);
465 clib_memset (s, 0, sizeof (*s));
466
467 /* Create list elts */
468 pool_get (tsm->list_pool, per_user_translation_list_elt);
469 clib_dlist_init (tsm->list_pool,
470 per_user_translation_list_elt - tsm->list_pool);
471
472 per_user_translation_list_elt->value = s - tsm->sessions;
473 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
474 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
475
476 clib_dlist_addtail (tsm->list_pool,
477 s->per_user_list_head_index,
478 per_user_translation_list_elt - tsm->list_pool);
479 }
Matus Fabianfd0d5082018-12-18 01:08:51 -0800480
481 vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
482 pool_elts (tsm->sessions));
Matus Fabian878c6462018-08-23 00:33:35 -0700483 }
484
Matus Fabian878c6462018-08-23 00:33:35 -0700485 return s;
486}
487
Matus Fabian066f0342017-02-10 03:48:01 -0800488void
489snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
Matus Fabianab395ec2018-09-20 23:18:41 -0700490 int is_add)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800491{
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800492 fib_prefix_t prefix = {
Matus Fabian066f0342017-02-10 03:48:01 -0800493 .fp_len = p_len,
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800494 .fp_proto = FIB_PROTOCOL_IP4,
495 .fp_addr = {
Matus Fabianab395ec2018-09-20 23:18:41 -0700496 .ip4.as_u32 = addr->as_u32,
497 },
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800498 };
Matus Fabianab395ec2018-09-20 23:18:41 -0700499 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800500
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800501 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700502 fib_table_entry_update_one_path (fib_index,
503 &prefix,
504 FIB_SOURCE_PLUGIN_LOW,
505 (FIB_ENTRY_FLAG_CONNECTED |
506 FIB_ENTRY_FLAG_LOCAL |
507 FIB_ENTRY_FLAG_EXCLUSIVE),
508 DPO_PROTO_IP4,
509 NULL,
510 sw_if_index,
511 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800512 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700513 fib_table_entry_delete (fib_index, &prefix, FIB_SOURCE_PLUGIN_LOW);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800514}
515
Matus Fabianab395ec2018-09-20 23:18:41 -0700516int
517snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
518 u8 twice_nat)
Dave Barach20c02cb2016-06-26 10:42:08 -0400519{
Matus Fabianab395ec2018-09-20 23:18:41 -0700520 snat_address_t *ap;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800521 snat_interface_t *i;
Matus Fabian624b8d92017-09-12 04:15:30 -0700522 vlib_thread_main_t *tm = vlib_get_thread_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -0400523
Matus Fabiana6110b62018-06-13 05:39:07 -0700524 if (twice_nat && !sm->endpoint_dependent)
525 return VNET_API_ERROR_FEATURE_DISABLED;
526
Matus Fabian860dacc2016-10-25 04:19:26 -0700527 /* Check if address already exists */
Matus Fabianab395ec2018-09-20 23:18:41 -0700528 /* *INDENT-OFF* */
Matus Fabianb932d262017-12-18 05:38:24 -0800529 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
Matus Fabian860dacc2016-10-25 04:19:26 -0700530 {
531 if (ap->addr.as_u32 == addr->as_u32)
Matus Fabiana6110b62018-06-13 05:39:07 -0700532 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian860dacc2016-10-25 04:19:26 -0700533 }
Matus Fabianab395ec2018-09-20 23:18:41 -0700534 /* *INDENT-ON* */
Matus Fabian860dacc2016-10-25 04:19:26 -0700535
Matus Fabianb932d262017-12-18 05:38:24 -0800536 if (twice_nat)
537 vec_add2 (sm->twice_nat_addresses, ap, 1);
538 else
539 vec_add2 (sm->addresses, ap, 1);
540
Dave Barach20c02cb2016-06-26 10:42:08 -0400541 ap->addr = *addr;
Matus Fabianf8d84902017-07-23 23:41:03 -0700542 if (vrf_id != ~0)
543 ap->fib_index =
Neale Ranns15002542017-09-10 04:39:11 -0700544 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Matus Fabianab395ec2018-09-20 23:18:41 -0700545 FIB_SOURCE_PLUGIN_LOW);
Matus Fabianf8d84902017-07-23 23:41:03 -0700546 else
547 ap->fib_index = ~0;
Matus Fabian09d96f42017-02-02 01:43:00 -0800548#define _(N, i, n, s) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700549 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
550 ap->busy_##n##_ports = 0; \
dongjuandf865202018-09-11 11:20:30 +0000551 ap->busy_##n##_ports_per_thread = 0;\
Matus Fabian624b8d92017-09-12 04:15:30 -0700552 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
Matus Fabian09d96f42017-02-02 01:43:00 -0800553 foreach_snat_protocol
554#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700555 if (twice_nat)
Matus Fabiana6110b62018-06-13 05:39:07 -0700556 return 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800557
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800558 /* Add external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -0700559 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800560 pool_foreach (i, sm->interfaces,
561 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100562 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800563 continue;
564
Matus Fabian066f0342017-02-10 03:48:01 -0800565 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
Matus Fabiandccbee32017-01-31 22:20:30 -0800566 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800567 }));
Matus Fabian93d84c92017-07-19 08:06:01 -0700568 pool_foreach (i, sm->output_feature_interfaces,
569 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100570 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -0700571 continue;
572
573 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
574 break;
575 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700576 /* *INDENT-ON* */
Matus Fabiana6110b62018-06-13 05:39:07 -0700577
578 return 0;
Dave Barach20c02cb2016-06-26 10:42:08 -0400579}
580
Matus Fabianab395ec2018-09-20 23:18:41 -0700581static int
582is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
Matus Fabian724b8152016-10-04 03:23:43 -0700583{
584 snat_static_mapping_t *m;
Matus Fabianab395ec2018-09-20 23:18:41 -0700585 /* *INDENT-OFF* */
Matus Fabian724b8152016-10-04 03:23:43 -0700586 pool_foreach (m, sm->static_mappings,
587 ({
Matus Fabianc3df1e92018-11-06 23:17:31 -0800588 if (is_addr_only_static_mapping (m) ||
589 is_out2in_only_static_mapping (m) ||
590 is_identity_static_mapping (m))
591 continue;
Matus Fabian724b8152016-10-04 03:23:43 -0700592 if (m->external_addr.as_u32 == addr.as_u32)
593 return 1;
594 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700595 /* *INDENT-ON* */
Matus Fabian724b8152016-10-04 03:23:43 -0700596
597 return 0;
598}
599
Matus Fabianab395ec2018-09-20 23:18:41 -0700600void
601increment_v4_address (ip4_address_t * a)
Dave Barach20c02cb2016-06-26 10:42:08 -0400602{
603 u32 v;
Matus Fabian2ba92e32017-08-21 07:05:03 -0700604
Matus Fabianab395ec2018-09-20 23:18:41 -0700605 v = clib_net_to_host_u32 (a->as_u32) + 1;
606 a->as_u32 = clib_host_to_net_u32 (v);
Dave Barach20c02cb2016-06-26 10:42:08 -0400607}
608
Matus Fabian2ba92e32017-08-21 07:05:03 -0700609static void
610snat_add_static_mapping_when_resolved (snat_main_t * sm,
Matus Fabianab395ec2018-09-20 23:18:41 -0700611 ip4_address_t l_addr,
612 u16 l_port,
613 u32 sw_if_index,
614 u16 e_port,
615 u32 vrf_id,
616 snat_protocol_t proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700617 int addr_only, int is_add, u8 * tag,
618 int twice_nat, int out2in_only,
619 int identity_nat)
Dave Barach8b275372017-01-16 10:54:02 -0500620{
621 snat_static_map_resolve_t *rp;
622
623 vec_add2 (sm->to_resolve, rp, 1);
624 rp->l_addr.as_u32 = l_addr.as_u32;
625 rp->l_port = l_port;
626 rp->sw_if_index = sw_if_index;
627 rp->e_port = e_port;
628 rp->vrf_id = vrf_id;
Matus Fabian09d96f42017-02-02 01:43:00 -0800629 rp->proto = proto;
Dave Barach8b275372017-01-16 10:54:02 -0500630 rp->addr_only = addr_only;
631 rp->is_add = is_add;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700632 rp->twice_nat = twice_nat;
633 rp->out2in_only = out2in_only;
634 rp->identity_nat = identity_nat;
Matus Fabian5f224992018-01-25 21:59:16 -0800635 rp->tag = vec_dup (tag);
Dave Barach8b275372017-01-16 10:54:02 -0500636}
Matus Fabianab395ec2018-09-20 23:18:41 -0700637
638static u32
639get_thread_idx_by_port (u16 e_port)
dongjuan58f50f12018-09-04 17:40:53 +0800640{
Matus Fabianab395ec2018-09-20 23:18:41 -0700641 snat_main_t *sm = &snat_main;
642 u32 thread_idx = sm->num_workers;
643 if (sm->num_workers > 1)
dongjuan58f50f12018-09-04 17:40:53 +0800644 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700645 thread_idx =
646 sm->first_worker_index +
647 sm->workers[(e_port - 1024) / sm->port_per_thread];
648 }
649 return thread_idx;
dongjuan58f50f12018-09-04 17:40:53 +0800650}
Dave Barach8b275372017-01-16 10:54:02 -0500651
Matus Fabianab395ec2018-09-20 23:18:41 -0700652int
653snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
654 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
655 u32 sw_if_index, snat_protocol_t proto, int is_add,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700656 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
657 u8 identity_nat)
Matus Fabiandb649882016-08-26 05:45:27 -0700658{
Matus Fabianab395ec2018-09-20 23:18:41 -0700659 snat_main_t *sm = &snat_main;
Matus Fabiandb649882016-08-26 05:45:27 -0700660 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -0800661 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -0700662 clib_bihash_kv_8_8_t kv, value;
663 snat_address_t *a = 0;
664 u32 fib_index = ~0;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800665 snat_interface_t *interface;
Matus Fabiandb649882016-08-26 05:45:27 -0700666 int i;
Matus Fabianb932d262017-12-18 05:38:24 -0800667 snat_main_per_thread_data_t *tsm;
Matus Fabianb793d092018-01-31 05:50:21 -0800668 snat_user_key_t u_key;
669 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -0700670 dlist_elt_t *head, *elt;
Matus Fabianb793d092018-01-31 05:50:21 -0800671 u32 elt_index, head_index;
672 u32 ses_index;
673 u64 user_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700674 snat_session_t *s;
Matus Fabianf13a8782018-04-06 02:54:40 -0700675 snat_static_map_resolve_t *rp, *rp_match = 0;
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700676 nat44_lb_addr_port_t *local;
Matus Fabianb6865082018-12-06 03:11:09 -0800677 u32 find = ~0;
Matus Fabiandb649882016-08-26 05:45:27 -0700678
Matus Fabiana6110b62018-06-13 05:39:07 -0700679 if (!sm->endpoint_dependent)
680 {
681 if (twice_nat || out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700682 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabiana6110b62018-06-13 05:39:07 -0700683 }
684
Dave Barach8b275372017-01-16 10:54:02 -0500685 /* If the external address is a specific interface address */
686 if (sw_if_index != ~0)
687 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700688 ip4_address_t *first_int_addr;
Matus Fabianea2600a2018-03-28 04:06:26 -0700689
690 for (i = 0; i < vec_len (sm->to_resolve); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -0700691 {
692 rp = sm->to_resolve + i;
693 if (rp->sw_if_index != sw_if_index ||
694 rp->l_addr.as_u32 != l_addr.as_u32 ||
695 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
696 continue;
Matus Fabianea2600a2018-03-28 04:06:26 -0700697
Matus Fabianab395ec2018-09-20 23:18:41 -0700698 if (!addr_only)
699 {
700 if (rp->l_port != l_port || rp->e_port != e_port
701 || rp->proto != proto)
702 continue;
703 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700704
Matus Fabianab395ec2018-09-20 23:18:41 -0700705 rp_match = rp;
706 break;
707 }
Dave Barach8b275372017-01-16 10:54:02 -0500708
709 /* Might be already set... */
Matus Fabian2ba92e32017-08-21 07:05:03 -0700710 first_int_addr = ip4_interface_first_address
Matus Fabianab395ec2018-09-20 23:18:41 -0700711 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
Dave Barach8b275372017-01-16 10:54:02 -0500712
Matus Fabianea2600a2018-03-28 04:06:26 -0700713 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700714 {
715 if (rp_match)
716 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabianea2600a2018-03-28 04:06:26 -0700717
Matus Fabianab395ec2018-09-20 23:18:41 -0700718 snat_add_static_mapping_when_resolved
719 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700720 addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
Matus Fabian4772e7a2018-04-04 00:38:02 -0700721
Matus Fabianab395ec2018-09-20 23:18:41 -0700722 /* DHCP resolution required? */
723 if (first_int_addr == 0)
724 {
725 return 0;
726 }
727 else
728 {
729 e_addr.as_u32 = first_int_addr->as_u32;
730 /* Identity mapping? */
731 if (l_addr.as_u32 == 0)
732 l_addr.as_u32 = e_addr.as_u32;
733 }
734 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700735 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700736 {
737 if (!rp_match)
738 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabianea2600a2018-03-28 04:06:26 -0700739
Matus Fabianab395ec2018-09-20 23:18:41 -0700740 vec_del1 (sm->to_resolve, i);
Matus Fabianea2600a2018-03-28 04:06:26 -0700741
Matus Fabianab395ec2018-09-20 23:18:41 -0700742 if (first_int_addr)
743 {
744 e_addr.as_u32 = first_int_addr->as_u32;
745 /* Identity mapping? */
746 if (l_addr.as_u32 == 0)
747 l_addr.as_u32 = e_addr.as_u32;
748 }
749 else
750 return 0;
751 }
Dave Barach8b275372017-01-16 10:54:02 -0500752 }
753
Matus Fabiandb649882016-08-26 05:45:27 -0700754 m_key.addr = e_addr;
755 m_key.port = addr_only ? 0 : e_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800756 m_key.protocol = addr_only ? 0 : proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700757 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700758 kv.key = m_key.as_u64;
759 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
760 m = 0;
761 else
762 m = pool_elt_at_index (sm->static_mappings, value.value);
763
764 if (is_add)
765 {
766 if (m)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700767 {
768 if (is_identity_static_mapping (m))
769 {
770 /* *INDENT-OFF* */
Matus Fabianb6865082018-12-06 03:11:09 -0800771 pool_foreach (local, m->locals,
772 ({
773 if (local->vrf_id == vrf_id)
774 return VNET_API_ERROR_VALUE_EXIST;
775 }));
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700776 /* *INDENT-ON* */
Matus Fabianb6865082018-12-06 03:11:09 -0800777 pool_get (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700778 local->vrf_id = vrf_id;
779 local->fib_index =
780 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
781 FIB_SOURCE_PLUGIN_LOW);
782 m_key.addr = m->local_addr;
783 m_key.port = m->local_port;
784 m_key.protocol = m->proto;
785 m_key.fib_index = local->fib_index;
786 kv.key = m_key.as_u64;
787 kv.value = m - sm->static_mappings;
788 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
789 return 0;
790 }
791 else
792 return VNET_API_ERROR_VALUE_EXIST;
793 }
Matus Fabiandb649882016-08-26 05:45:27 -0700794
Matus Fabianb932d262017-12-18 05:38:24 -0800795 if (twice_nat && addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700796 return VNET_API_ERROR_UNSUPPORTED;
Matus Fabianb932d262017-12-18 05:38:24 -0800797
Matus Fabiandb649882016-08-26 05:45:27 -0700798 /* Convert VRF id to FIB index */
799 if (vrf_id != ~0)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700800 fib_index =
801 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
802 FIB_SOURCE_PLUGIN_LOW);
Matus Fabiandb649882016-08-26 05:45:27 -0700803 /* If not specified use inside VRF id from SNAT plugin startup config */
804 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700805 {
806 fib_index = sm->inside_fib_index;
807 vrf_id = sm->inside_vrf_id;
808 }
Matus Fabiandb649882016-08-26 05:45:27 -0700809
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700810 if (!(out2in_only || identity_nat))
Matus Fabianab395ec2018-09-20 23:18:41 -0700811 {
812 m_key.addr = l_addr;
813 m_key.port = addr_only ? 0 : l_port;
814 m_key.protocol = addr_only ? 0 : proto;
815 m_key.fib_index = fib_index;
816 kv.key = m_key.as_u64;
817 if (!clib_bihash_search_8_8
818 (&sm->static_mapping_by_local, &kv, &value))
819 return VNET_API_ERROR_VALUE_EXIST;
820 }
Matus Fabian36a62702018-04-04 03:27:43 -0700821
Matus Fabiandb649882016-08-26 05:45:27 -0700822 /* Find external address in allocated addresses and reserve port for
823 address and port pair mapping when dynamic translations enabled */
Matus Fabiane82488f2018-01-18 03:38:45 -0800824 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700825 {
826 for (i = 0; i < vec_len (sm->addresses); i++)
827 {
828 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
829 {
830 a = sm->addresses + i;
831 /* External port must be unused */
832 switch (proto)
833 {
Matus Fabian09d96f42017-02-02 01:43:00 -0800834#define _(N, j, n, s) \
835 case SNAT_PROTOCOL_##N: \
836 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
837 return VNET_API_ERROR_INVALID_VALUE; \
838 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
839 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700840 { \
841 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +0800842 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -0700843 } \
Matus Fabian09d96f42017-02-02 01:43:00 -0800844 break;
Matus Fabianab395ec2018-09-20 23:18:41 -0700845 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -0800846#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700847 default:
848 nat_log_info ("unknown protocol");
849 return VNET_API_ERROR_INVALID_VALUE_2;
850 }
851 break;
852 }
853 }
854 /* External address must be allocated */
855 if (!a && (l_addr.as_u32 != e_addr.as_u32))
856 {
857 if (sw_if_index != ~0)
858 {
859 for (i = 0; i < vec_len (sm->to_resolve); i++)
860 {
861 rp = sm->to_resolve + i;
862 if (rp->addr_only)
863 continue;
864 if (rp->sw_if_index != sw_if_index &&
865 rp->l_addr.as_u32 != l_addr.as_u32 &&
866 rp->vrf_id != vrf_id && rp->l_port != l_port &&
867 rp->e_port != e_port && rp->proto != proto)
868 continue;
Matus Fabianf13a8782018-04-06 02:54:40 -0700869
Matus Fabianab395ec2018-09-20 23:18:41 -0700870 vec_del1 (sm->to_resolve, i);
871 break;
872 }
873 }
874 return VNET_API_ERROR_NO_SUCH_ENTRY;
875 }
876 }
Matus Fabiandb649882016-08-26 05:45:27 -0700877
878 pool_get (sm->static_mappings, m);
Dave Barachb7b92992018-10-17 10:38:51 -0400879 clib_memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -0800880 m->tag = vec_dup (tag);
Matus Fabiandb649882016-08-26 05:45:27 -0700881 m->local_addr = l_addr;
882 m->external_addr = e_addr;
Matus Fabianb932d262017-12-18 05:38:24 -0800883 m->twice_nat = twice_nat;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -0700884 if (out2in_only)
885 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
886 if (addr_only)
887 m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
888 if (identity_nat)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700889 {
890 m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
Matus Fabianb6865082018-12-06 03:11:09 -0800891 pool_get (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700892 local->vrf_id = vrf_id;
893 local->fib_index = fib_index;
894 }
895 else
896 {
897 m->vrf_id = vrf_id;
898 m->fib_index = fib_index;
899 }
Matus Fabiandb649882016-08-26 05:45:27 -0700900 if (!addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700901 {
902 m->local_port = l_port;
903 m->external_port = e_port;
904 m->proto = proto;
905 }
Matus Fabiandb649882016-08-26 05:45:27 -0700906
Matus Fabiana6110b62018-06-13 05:39:07 -0700907 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -0700908 {
909 ip4_header_t ip = {
910 .src_address = m->local_addr,
911 };
912 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index));
913 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
914 }
Matus Fabianb932d262017-12-18 05:38:24 -0800915 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700916 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -0800917
Matus Fabiandb649882016-08-26 05:45:27 -0700918 m_key.addr = m->local_addr;
919 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800920 m_key.protocol = m->proto;
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700921 m_key.fib_index = fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -0700922 kv.key = m_key.as_u64;
923 kv.value = m - sm->static_mappings;
Matus Fabiane82488f2018-01-18 03:38:45 -0800924 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700925 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
Matus Fabiandb649882016-08-26 05:45:27 -0700926
927 m_key.addr = m->external_addr;
928 m_key.port = m->external_port;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700929 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700930 kv.key = m_key.as_u64;
931 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -0700932 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
Matus Fabianb932d262017-12-18 05:38:24 -0800933
Matus Fabianb793d092018-01-31 05:50:21 -0800934 /* Delete dynamic sessions matching local address (+ local port) */
935 if (!(sm->static_mapping_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700936 {
937 u_key.addr = m->local_addr;
938 u_key.fib_index = m->fib_index;
939 kv.key = u_key.as_u64;
940 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
941 {
942 user_index = value.value;
943 u = pool_elt_at_index (tsm->users, user_index);
944 if (u->nsessions)
945 {
946 head_index = u->sessions_per_user_list_head_index;
947 head = pool_elt_at_index (tsm->list_pool, head_index);
948 elt_index = head->next;
949 elt = pool_elt_at_index (tsm->list_pool, elt_index);
950 ses_index = elt->value;
951 while (ses_index != ~0)
952 {
953 s = pool_elt_at_index (tsm->sessions, ses_index);
954 elt = pool_elt_at_index (tsm->list_pool, elt->next);
955 ses_index = elt->value;
Matus Fabianb793d092018-01-31 05:50:21 -0800956
Matus Fabianab395ec2018-09-20 23:18:41 -0700957 if (snat_is_session_static (s))
958 continue;
Matus Fabianb793d092018-01-31 05:50:21 -0800959
Matus Fabianab395ec2018-09-20 23:18:41 -0700960 if (!addr_only
961 && (clib_net_to_host_u16 (s->in2out.port) !=
962 m->local_port))
963 continue;
Matus Fabianb793d092018-01-31 05:50:21 -0800964
Matus Fabianab395ec2018-09-20 23:18:41 -0700965 nat_free_session_data (sm, s,
966 tsm - sm->per_thread_data);
967 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb793d092018-01-31 05:50:21 -0800968
Matus Fabianab395ec2018-09-20 23:18:41 -0700969 if (!addr_only && !sm->endpoint_dependent)
970 break;
971 }
972 }
973 }
974 }
Matus Fabiandb649882016-08-26 05:45:27 -0700975 }
976 else
977 {
978 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -0700979 {
980 if (sw_if_index != ~0)
981 return 0;
982 else
983 return VNET_API_ERROR_NO_SUCH_ENTRY;
984 }
Matus Fabiandb649882016-08-26 05:45:27 -0700985
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700986 if (identity_nat)
987 {
Matus Fabianc3df1e92018-11-06 23:17:31 -0800988 if (vrf_id == ~0)
989 vrf_id = sm->inside_vrf_id;
990
Matus Fabianb6865082018-12-06 03:11:09 -0800991 /* *INDENT-OFF* */
992 pool_foreach (local, m->locals,
993 ({
994 if (local->vrf_id == vrf_id)
995 find = local - m->locals;
996 }));
997 /* *INDENT-ON* */
998 if (find == ~0)
Matus Fabian82b4ceb2018-10-11 04:28:48 -0700999 return VNET_API_ERROR_NO_SUCH_ENTRY;
1000
Matus Fabianb6865082018-12-06 03:11:09 -08001001 local = pool_elt_at_index (m->locals, find);
1002 fib_index = local->fib_index;
1003 pool_put (m->locals, local);
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001004 }
1005 else
1006 fib_index = m->fib_index;
1007
Matus Fabiandb649882016-08-26 05:45:27 -07001008 /* Free external address port */
Matus Fabiane82488f2018-01-18 03:38:45 -08001009 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001010 {
1011 for (i = 0; i < vec_len (sm->addresses); i++)
1012 {
1013 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1014 {
1015 a = sm->addresses + i;
1016 switch (proto)
1017 {
Matus Fabian09d96f42017-02-02 01:43:00 -08001018#define _(N, j, n, s) \
1019 case SNAT_PROTOCOL_##N: \
1020 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1021 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001022 { \
1023 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +08001024 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001025 } \
Matus Fabian09d96f42017-02-02 01:43:00 -08001026 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001027 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -08001028#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001029 default:
1030 nat_log_info ("unknown protocol");
1031 return VNET_API_ERROR_INVALID_VALUE_2;
1032 }
1033 break;
1034 }
1035 }
1036 }
Matus Fabiandb649882016-08-26 05:45:27 -07001037
Matus Fabianb932d262017-12-18 05:38:24 -08001038 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001039 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
Matus Fabianb932d262017-12-18 05:38:24 -08001040 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001041 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -08001042
Matus Fabiandb649882016-08-26 05:45:27 -07001043 m_key.addr = m->local_addr;
1044 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -08001045 m_key.protocol = m->proto;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001046 m_key.fib_index = fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -07001047 kv.key = m_key.as_u64;
Matus Fabiane82488f2018-01-18 03:38:45 -08001048 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -07001049 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
Matus Fabiandb649882016-08-26 05:45:27 -07001050
Matus Fabiandb649882016-08-26 05:45:27 -07001051 /* Delete session(s) for static mapping if exist */
1052 if (!(sm->static_mapping_only) ||
Matus Fabianab395ec2018-09-20 23:18:41 -07001053 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1054 {
1055 u_key.addr = m->local_addr;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001056 u_key.fib_index = fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07001057 kv.key = u_key.as_u64;
1058 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1059 {
1060 user_index = value.value;
1061 u = pool_elt_at_index (tsm->users, user_index);
1062 if (u->nstaticsessions)
1063 {
1064 head_index = u->sessions_per_user_list_head_index;
1065 head = pool_elt_at_index (tsm->list_pool, head_index);
1066 elt_index = head->next;
1067 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1068 ses_index = elt->value;
1069 while (ses_index != ~0)
1070 {
1071 s = pool_elt_at_index (tsm->sessions, ses_index);
1072 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1073 ses_index = elt->value;
Matus Fabiandb649882016-08-26 05:45:27 -07001074
Matus Fabianab395ec2018-09-20 23:18:41 -07001075 if (!addr_only)
1076 {
1077 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1078 (clib_net_to_host_u16 (s->out2in.port) !=
1079 e_port))
1080 continue;
1081 }
Matus Fabian13c08182018-04-11 00:36:57 -07001082
Matus Fabianab395ec2018-09-20 23:18:41 -07001083 if (is_lb_session (s))
1084 continue;
Matus Fabian475f0552016-10-19 06:17:52 -07001085
Matus Fabianab395ec2018-09-20 23:18:41 -07001086 if (!snat_is_session_static (s))
1087 continue;
Matus Fabian70a26ac2018-05-14 06:20:28 -07001088
Matus Fabianab395ec2018-09-20 23:18:41 -07001089 nat_free_session_data (sm, s,
1090 tsm - sm->per_thread_data);
1091 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabiandb649882016-08-26 05:45:27 -07001092
Matus Fabianab395ec2018-09-20 23:18:41 -07001093 if (!addr_only && !sm->endpoint_dependent)
1094 break;
1095 }
1096 }
1097 }
1098 }
Matus Fabiandb649882016-08-26 05:45:27 -07001099
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001100 fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
Matus Fabianb6865082018-12-06 03:11:09 -08001101 if (pool_elts (m->locals))
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001102 return 0;
1103
1104 m_key.addr = m->external_addr;
1105 m_key.port = m->external_port;
1106 m_key.fib_index = 0;
1107 kv.key = m_key.as_u64;
1108 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1109
Matus Fabian5f224992018-01-25 21:59:16 -08001110 vec_free (m->tag);
Matus Fabiana6110b62018-06-13 05:39:07 -07001111 vec_free (m->workers);
Matus Fabiandb649882016-08-26 05:45:27 -07001112 /* Delete static mapping from pool */
1113 pool_put (sm->static_mappings, m);
1114 }
1115
Matus Fabianab7a8052017-11-28 04:29:41 -08001116 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001117 return 0;
1118
1119 /* Add/delete external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001120 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001121 pool_foreach (interface, sm->interfaces,
1122 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001123 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001124 continue;
1125
Matus Fabian066f0342017-02-10 03:48:01 -08001126 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
Matus Fabiandccbee32017-01-31 22:20:30 -08001127 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001128 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001129 pool_foreach (interface, sm->output_feature_interfaces,
1130 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001131 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001132 continue;
1133
1134 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1135 break;
1136 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001137 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001138
Matus Fabiandb649882016-08-26 05:45:27 -07001139 return 0;
1140}
1141
Matus Fabianab395ec2018-09-20 23:18:41 -07001142int
1143nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1144 snat_protocol_t proto,
1145 nat44_lb_addr_port_t * locals, u8 is_add,
1146 twice_nat_type_t twice_nat, u8 out2in_only,
1147 u8 * tag, u32 affinity)
Matus Fabian704018c2017-09-04 02:17:18 -07001148{
Matus Fabianab395ec2018-09-20 23:18:41 -07001149 snat_main_t *sm = &snat_main;
Matus Fabian704018c2017-09-04 02:17:18 -07001150 snat_static_mapping_t *m;
1151 snat_session_key_t m_key;
1152 clib_bihash_kv_8_8_t kv, value;
Matus Fabian704018c2017-09-04 02:17:18 -07001153 snat_address_t *a = 0;
1154 int i;
1155 nat44_lb_addr_port_t *local;
Matus Fabiana6110b62018-06-13 05:39:07 -07001156 u32 elt_index, head_index, ses_index;
Matus Fabian092b3cd2017-09-19 05:42:38 -07001157 snat_main_per_thread_data_t *tsm;
Matus Fabianb932d262017-12-18 05:38:24 -08001158 snat_user_key_t u_key;
1159 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -07001160 snat_session_t *s;
1161 dlist_elt_t *head, *elt;
Matus Fabiana6110b62018-06-13 05:39:07 -07001162 uword *bitmap = 0;
1163
1164 if (!sm->endpoint_dependent)
1165 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian704018c2017-09-04 02:17:18 -07001166
1167 m_key.addr = e_addr;
1168 m_key.port = e_port;
1169 m_key.protocol = proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001170 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001171 kv.key = m_key.as_u64;
1172 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1173 m = 0;
1174 else
1175 m = pool_elt_at_index (sm->static_mappings, value.value);
1176
1177 if (is_add)
1178 {
1179 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001180 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian704018c2017-09-04 02:17:18 -07001181
1182 if (vec_len (locals) < 2)
Matus Fabianab395ec2018-09-20 23:18:41 -07001183 return VNET_API_ERROR_INVALID_VALUE;
Matus Fabian704018c2017-09-04 02:17:18 -07001184
Matus Fabian704018c2017-09-04 02:17:18 -07001185 /* Find external address in allocated addresses and reserve port for
1186 address and port pair mapping when dynamic translations enabled */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001187 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001188 {
1189 for (i = 0; i < vec_len (sm->addresses); i++)
1190 {
1191 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1192 {
1193 a = sm->addresses + i;
1194 /* External port must be unused */
1195 switch (proto)
1196 {
Matus Fabian704018c2017-09-04 02:17:18 -07001197#define _(N, j, n, s) \
1198 case SNAT_PROTOCOL_##N: \
1199 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1200 return VNET_API_ERROR_INVALID_VALUE; \
1201 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1202 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001203 { \
1204 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +08001205 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001206 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001207 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001208 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001209#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001210 default:
1211 nat_log_info ("unknown protocol");
1212 return VNET_API_ERROR_INVALID_VALUE_2;
1213 }
1214 break;
1215 }
1216 }
1217 /* External address must be allocated */
1218 if (!a)
1219 return VNET_API_ERROR_NO_SUCH_ENTRY;
1220 }
Matus Fabian704018c2017-09-04 02:17:18 -07001221
1222 pool_get (sm->static_mappings, m);
Dave Barachb7b92992018-10-17 10:38:51 -04001223 clib_memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -08001224 m->tag = vec_dup (tag);
Matus Fabian704018c2017-09-04 02:17:18 -07001225 m->external_addr = e_addr;
Matus Fabian704018c2017-09-04 02:17:18 -07001226 m->external_port = e_port;
1227 m->proto = proto;
Matus Fabianb932d262017-12-18 05:38:24 -08001228 m->twice_nat = twice_nat;
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001229 m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001230 if (out2in_only)
1231 m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
Matus Fabianea5b5be2018-09-03 05:02:23 -07001232 m->affinity = affinity;
1233
1234 if (affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001235 m->affinity_per_service_list_head_index =
1236 nat_affinity_get_per_service_list_head_index ();
Matus Fabianea5b5be2018-09-03 05:02:23 -07001237 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001238 m->affinity_per_service_list_head_index = ~0;
Matus Fabian704018c2017-09-04 02:17:18 -07001239
1240 m_key.addr = m->external_addr;
1241 m_key.port = m->external_port;
1242 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001243 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001244 kv.key = m_key.as_u64;
1245 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -07001246 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1247 {
1248 nat_log_err ("static_mapping_by_external key add failed");
1249 return VNET_API_ERROR_UNSPECIFIED;
1250 }
Matus Fabian704018c2017-09-04 02:17:18 -07001251
Matus Fabian092b3cd2017-09-19 05:42:38 -07001252 m_key.fib_index = m->fib_index;
Matus Fabian704018c2017-09-04 02:17:18 -07001253 for (i = 0; i < vec_len (locals); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -07001254 {
1255 locals[i].fib_index =
1256 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1257 locals[i].vrf_id,
1258 FIB_SOURCE_PLUGIN_LOW);
1259 m_key.addr = locals[i].addr;
1260 m_key.fib_index = locals[i].fib_index;
1261 if (!out2in_only)
1262 {
1263 m_key.port = locals[i].port;
1264 kv.key = m_key.as_u64;
1265 kv.value = m - sm->static_mappings;
1266 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1267 }
1268 locals[i].prefix = (i == 0) ? locals[i].probability :
1269 (locals[i - 1].prefix + locals[i].probability);
Matus Fabianb6865082018-12-06 03:11:09 -08001270 pool_get (m->locals, local);
1271 *local = locals[i];
Matus Fabianab395ec2018-09-20 23:18:41 -07001272 if (sm->num_workers > 1)
1273 {
1274 ip4_header_t ip = {
1275 .src_address = locals[i].addr,
1276 };
1277 bitmap =
1278 clib_bitmap_set (bitmap,
1279 sm->worker_in2out_cb (&ip, m->fib_index), 1);
1280 }
1281 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001282
1283 /* Assign workers */
1284 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001285 {
1286 /* *INDENT-OFF* */
Matus Fabiana6110b62018-06-13 05:39:07 -07001287 clib_bitmap_foreach (i, bitmap,
1288 ({
1289 vec_add1(m->workers, i);
1290 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001291 /* *INDENT-ON* */
1292 }
Matus Fabian704018c2017-09-04 02:17:18 -07001293 }
1294 else
1295 {
1296 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001297 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabian704018c2017-09-04 02:17:18 -07001298
Matus Fabian82b4ceb2018-10-11 04:28:48 -07001299 if (!is_lb_static_mapping (m))
1300 return VNET_API_ERROR_INVALID_VALUE;
1301
Matus Fabian704018c2017-09-04 02:17:18 -07001302 /* Free external address port */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001303 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001304 {
1305 for (i = 0; i < vec_len (sm->addresses); i++)
1306 {
1307 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1308 {
1309 a = sm->addresses + i;
1310 switch (proto)
1311 {
Matus Fabian704018c2017-09-04 02:17:18 -07001312#define _(N, j, n, s) \
1313 case SNAT_PROTOCOL_##N: \
1314 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1315 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001316 { \
1317 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +08001318 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001319 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001320 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001321 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001322#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001323 default:
1324 nat_log_info ("unknown protocol");
1325 return VNET_API_ERROR_INVALID_VALUE_2;
1326 }
1327 break;
1328 }
1329 }
1330 }
Matus Fabian704018c2017-09-04 02:17:18 -07001331
1332 m_key.addr = m->external_addr;
1333 m_key.port = m->external_port;
1334 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001335 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001336 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07001337 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1338 {
1339 nat_log_err ("static_mapping_by_external key del failed");
1340 return VNET_API_ERROR_UNSPECIFIED;
1341 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001342
Matus Fabianab395ec2018-09-20 23:18:41 -07001343 /* *INDENT-OFF* */
Matus Fabianb6865082018-12-06 03:11:09 -08001344 pool_foreach (local, m->locals,
1345 ({
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001346 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1347 FIB_SOURCE_PLUGIN_LOW);
Matus Fabian704018c2017-09-04 02:17:18 -07001348 m_key.addr = local->addr;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001349 if (!out2in_only)
Matus Fabian704018c2017-09-04 02:17:18 -07001350 {
Matus Fabian240b5ef2018-01-11 04:09:17 -08001351 m_key.port = local->port;
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001352 m_key.fib_index = local->fib_index;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001353 kv.key = m_key.as_u64;
1354 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1355 {
Matus Fabian229c1aa2018-05-28 04:09:52 -07001356 nat_log_err ("static_mapping_by_local key del failed");
Matus Fabian240b5ef2018-01-11 04:09:17 -08001357 return VNET_API_ERROR_UNSPECIFIED;
1358 }
Matus Fabian704018c2017-09-04 02:17:18 -07001359 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001360
Matus Fabiana6110b62018-06-13 05:39:07 -07001361 if (sm->num_workers > 1)
Matus Fabian704018c2017-09-04 02:17:18 -07001362 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001363 ip4_header_t ip = {
1364 .src_address = local->addr,
1365 };
1366 tsm = vec_elt_at_index (sm->per_thread_data,
1367 sm->worker_in2out_cb (&ip, m->fib_index));
Matus Fabian704018c2017-09-04 02:17:18 -07001368 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001369 else
1370 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1371
Matus Fabianb932d262017-12-18 05:38:24 -08001372 /* Delete sessions */
1373 u_key.addr = local->addr;
Matus Fabianb6865082018-12-06 03:11:09 -08001374 u_key.fib_index = local->fib_index;
Matus Fabianb932d262017-12-18 05:38:24 -08001375 kv.key = u_key.as_u64;
1376 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1377 {
1378 u = pool_elt_at_index (tsm->users, value.value);
1379 if (u->nstaticsessions)
1380 {
1381 head_index = u->sessions_per_user_list_head_index;
1382 head = pool_elt_at_index (tsm->list_pool, head_index);
1383 elt_index = head->next;
1384 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1385 ses_index = elt->value;
1386 while (ses_index != ~0)
1387 {
1388 s = pool_elt_at_index (tsm->sessions, ses_index);
1389 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1390 ses_index = elt->value;
1391
Matus Fabian13c08182018-04-11 00:36:57 -07001392 if (!(is_lb_session (s)))
1393 continue;
1394
shubing guo060c3a72018-08-10 13:59:50 +08001395 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
Matus Fabianb932d262017-12-18 05:38:24 -08001396 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1397 continue;
1398
1399 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
Matus Fabian229c1aa2018-05-28 04:09:52 -07001400 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb932d262017-12-18 05:38:24 -08001401 }
1402 }
1403 }
Matus Fabianb6865082018-12-06 03:11:09 -08001404 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001405 /* *INDENT-ON* */
Matus Fabianea5b5be2018-09-03 05:02:23 -07001406 if (m->affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001407 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
Matus Fabianb6865082018-12-06 03:11:09 -08001408 pool_free (m->locals);
Matus Fabianab395ec2018-09-20 23:18:41 -07001409 vec_free (m->tag);
1410 vec_free (m->workers);
Matus Fabian704018c2017-09-04 02:17:18 -07001411
1412 pool_put (sm->static_mappings, m);
1413 }
1414
1415 return 0;
1416}
1417
Matus Fabianb932d262017-12-18 05:38:24 -08001418int
Matus Fabianb6865082018-12-06 03:11:09 -08001419nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1420 ip4_address_t l_addr, u16 l_port,
1421 snat_protocol_t proto, u32 vrf_id,
1422 u8 probability, u8 is_add)
1423{
1424 snat_main_t *sm = &snat_main;
1425 snat_static_mapping_t *m = 0;
1426 snat_session_key_t m_key;
1427 clib_bihash_kv_8_8_t kv, value;
1428 nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1429 snat_main_per_thread_data_t *tsm;
1430 snat_user_key_t u_key;
1431 snat_user_t *u;
1432 snat_session_t *s;
1433 dlist_elt_t *head, *elt;
1434 u32 elt_index, head_index, ses_index, *locals = 0;
1435 uword *bitmap = 0;
1436 int i;
1437
1438 if (!sm->endpoint_dependent)
1439 return VNET_API_ERROR_FEATURE_DISABLED;
1440
1441 m_key.addr = e_addr;
1442 m_key.port = e_port;
1443 m_key.protocol = proto;
1444 m_key.fib_index = 0;
1445 kv.key = m_key.as_u64;
1446 if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1447 m = pool_elt_at_index (sm->static_mappings, value.value);
1448
1449 if (!m)
1450 return VNET_API_ERROR_NO_SUCH_ENTRY;
1451
1452 if (!is_lb_static_mapping (m))
1453 return VNET_API_ERROR_INVALID_VALUE;
1454
1455 /* *INDENT-OFF* */
1456 pool_foreach (local, m->locals,
1457 ({
1458 if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1459 (local->vrf_id == vrf_id))
1460 {
1461 match_local = local;
1462 break;
1463 }
1464 }));
1465 /* *INDENT-ON* */
1466
1467 if (is_add)
1468 {
1469 if (match_local)
1470 return VNET_API_ERROR_VALUE_EXIST;
1471
1472 pool_get (m->locals, local);
1473 clib_memset (local, 0, sizeof (*local));
1474 local->addr.as_u32 = l_addr.as_u32;
1475 local->port = l_port;
1476 local->probability = probability;
1477 local->vrf_id = vrf_id;
1478 local->fib_index =
1479 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1480 FIB_SOURCE_PLUGIN_LOW);
1481
1482 if (!is_out2in_only_static_mapping (m))
1483 {
1484 m_key.addr = l_addr;
1485 m_key.port = l_port;
1486 m_key.fib_index = local->fib_index;
1487 kv.key = m_key.as_u64;
1488 kv.value = m - sm->static_mappings;
1489 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1490 nat_log_err ("static_mapping_by_local key add failed");
1491 }
1492 }
1493 else
1494 {
1495 if (!match_local)
1496 return VNET_API_ERROR_NO_SUCH_ENTRY;
1497
1498 if (pool_elts (m->locals) < 3)
1499 return VNET_API_ERROR_UNSPECIFIED;
1500
1501 fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1502 FIB_SOURCE_PLUGIN_LOW);
1503
1504 if (!is_out2in_only_static_mapping (m))
1505 {
1506 m_key.addr = l_addr;
1507 m_key.port = l_port;
1508 m_key.fib_index = match_local->fib_index;
1509 kv.key = m_key.as_u64;
1510 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1511 nat_log_err ("static_mapping_by_local key del failed");
1512 }
1513
1514 if (sm->num_workers > 1)
1515 {
1516 ip4_header_t ip = {
1517 .src_address = local->addr,
1518 };
1519 tsm = vec_elt_at_index (sm->per_thread_data,
1520 sm->worker_in2out_cb (&ip, m->fib_index));
1521 }
1522 else
1523 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1524
1525 /* Delete sessions */
1526 u_key.addr = match_local->addr;
1527 u_key.fib_index = match_local->fib_index;
1528 kv.key = u_key.as_u64;
1529 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1530 {
1531 u = pool_elt_at_index (tsm->users, value.value);
1532 if (u->nstaticsessions)
1533 {
1534 head_index = u->sessions_per_user_list_head_index;
1535 head = pool_elt_at_index (tsm->list_pool, head_index);
1536 elt_index = head->next;
1537 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1538 ses_index = elt->value;
1539 while (ses_index != ~0)
1540 {
1541 s = pool_elt_at_index (tsm->sessions, ses_index);
1542 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1543 ses_index = elt->value;
1544
1545 if (!(is_lb_session (s)))
1546 continue;
1547
1548 if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1549 (clib_net_to_host_u16 (s->in2out.port) !=
1550 match_local->port))
1551 continue;
1552
1553 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1554 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1555 }
1556 }
1557 }
1558
1559 pool_put (m->locals, match_local);
1560 }
1561
1562 vec_free (m->workers);
1563
1564 /* *INDENT-OFF* */
1565 pool_foreach (local, m->locals,
1566 ({
1567 vec_add1 (locals, local - m->locals);
1568 if (sm->num_workers > 1)
1569 {
1570 ip4_header_t ip;
1571 ip.src_address.as_u32 = local->addr.as_u32,
1572 bitmap = clib_bitmap_set (bitmap,
1573 sm->worker_in2out_cb (&ip, local->fib_index),
1574 1);
1575 }
1576 }));
1577 /* *INDENT-ON* */
1578
Matus Fabiand2bad812018-12-21 04:01:00 -08001579 ASSERT (vec_len (locals) > 1);
1580
Matus Fabianb6865082018-12-06 03:11:09 -08001581 local = pool_elt_at_index (m->locals, locals[0]);
1582 local->prefix = local->probability;
1583 for (i = 1; i < vec_len (locals); i++)
1584 {
1585 local = pool_elt_at_index (m->locals, locals[i]);
1586 prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1587 local->prefix = local->probability + prev_local->prefix;
1588 }
1589
1590 /* Assign workers */
1591 if (sm->num_workers > 1)
1592 {
1593 /* *INDENT-OFF* */
1594 clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1595 /* *INDENT-ON* */
1596 }
1597
1598 return 0;
1599}
1600
1601int
Matus Fabianab395ec2018-09-20 23:18:41 -07001602snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1603 u8 twice_nat)
Matus Fabian36532bd2017-01-23 23:42:28 -08001604{
1605 snat_address_t *a = 0;
1606 snat_session_t *ses;
1607 u32 *ses_to_be_removed = 0, *ses_index;
Matus Fabian36532bd2017-01-23 23:42:28 -08001608 snat_main_per_thread_data_t *tsm;
1609 snat_static_mapping_t *m;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001610 snat_interface_t *interface;
Matus Fabian36532bd2017-01-23 23:42:28 -08001611 int i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001612 snat_address_t *addresses =
1613 twice_nat ? sm->twice_nat_addresses : sm->addresses;
Matus Fabian36532bd2017-01-23 23:42:28 -08001614
1615 /* Find SNAT address */
Matus Fabianab395ec2018-09-20 23:18:41 -07001616 for (i = 0; i < vec_len (addresses); i++)
Matus Fabian36532bd2017-01-23 23:42:28 -08001617 {
Matus Fabianb932d262017-12-18 05:38:24 -08001618 if (addresses[i].addr.as_u32 == addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07001619 {
1620 a = addresses + i;
1621 break;
1622 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001623 }
1624 if (!a)
1625 return VNET_API_ERROR_NO_SUCH_ENTRY;
1626
1627 if (delete_sm)
1628 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001629 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001630 pool_foreach (m, sm->static_mappings,
1631 ({
1632 if (m->external_addr.as_u32 == addr.as_u32)
1633 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1634 m->local_port, m->external_port,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001635 m->vrf_id, is_addr_only_static_mapping(m), ~0,
Matus Fabiane82488f2018-01-18 03:38:45 -08001636 m->proto, 0, m->twice_nat,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001637 is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
Matus Fabian36532bd2017-01-23 23:42:28 -08001638 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001639 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001640 }
1641 else
1642 {
1643 /* Check if address is used in some static mapping */
Matus Fabianab395ec2018-09-20 23:18:41 -07001644 if (is_snat_address_used_in_static_mapping (sm, addr))
1645 {
1646 nat_log_notice ("address used in static mapping");
1647 return VNET_API_ERROR_UNSPECIFIED;
1648 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001649 }
1650
Matus Fabianf8d84902017-07-23 23:41:03 -07001651 if (a->fib_index != ~0)
Matus Fabianab395ec2018-09-20 23:18:41 -07001652 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
Matus Fabianf8d84902017-07-23 23:41:03 -07001653
Matus Fabian36532bd2017-01-23 23:42:28 -08001654 /* Delete sessions using address */
Matus Fabian09d96f42017-02-02 01:43:00 -08001655 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
Matus Fabian36532bd2017-01-23 23:42:28 -08001656 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001657 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001658 vec_foreach (tsm, sm->per_thread_data)
1659 {
1660 pool_foreach (ses, tsm->sessions, ({
1661 if (ses->out2in.addr.as_u32 == addr.as_u32)
1662 {
Matus Fabianb932d262017-12-18 05:38:24 -08001663 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
Matus Fabianb932d262017-12-18 05:38:24 -08001664 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
Matus Fabian36532bd2017-01-23 23:42:28 -08001665 }
1666 }));
1667
1668 vec_foreach (ses_index, ses_to_be_removed)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001669 {
1670 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1671 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1672 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001673
1674 vec_free (ses_to_be_removed);
Matus Fabianab395ec2018-09-20 23:18:41 -07001675 }
1676 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001677 }
1678
dongjuandf865202018-09-11 11:20:30 +00001679#define _(N, i, n, s) \
1680 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1681 vec_free (a->busy_##n##_ports_per_thread);
1682 foreach_snat_protocol
1683#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001684 if (twice_nat)
Matus Fabianb932d262017-12-18 05:38:24 -08001685 {
1686 vec_del1 (sm->twice_nat_addresses, i);
1687 return 0;
1688 }
1689 else
1690 vec_del1 (sm->addresses, i);
Matus Fabian36532bd2017-01-23 23:42:28 -08001691
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001692 /* Delete external address from FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001693 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001694 pool_foreach (interface, sm->interfaces,
1695 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001696 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001697 continue;
1698
Matus Fabian066f0342017-02-10 03:48:01 -08001699 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
Matus Fabiandccbee32017-01-31 22:20:30 -08001700 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001701 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001702 pool_foreach (interface, sm->output_feature_interfaces,
1703 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001704 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001705 continue;
1706
1707 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1708 break;
1709 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001710 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001711
Matus Fabian36532bd2017-01-23 23:42:28 -08001712 return 0;
1713}
1714
Matus Fabianab395ec2018-09-20 23:18:41 -07001715int
1716snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
Matus Fabian588144a2016-10-24 03:30:00 -07001717{
1718 snat_main_t *sm = &snat_main;
1719 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001720 const char *feature_name, *del_feature_name;
1721 snat_address_t *ap;
1722 snat_static_mapping_t *m;
1723 snat_det_map_t *dm;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001724 nat_outside_fib_t *outside_fib;
1725 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07001726 sw_if_index);
Matus Fabian588144a2016-10-24 03:30:00 -07001727
Juraj Slobodacba69362017-12-19 02:09:32 +01001728 if (sm->out2in_dpo && !is_inside)
1729 return VNET_API_ERROR_UNSUPPORTED;
1730
Matus Fabianab395ec2018-09-20 23:18:41 -07001731 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001732 pool_foreach (i, sm->output_feature_interfaces,
1733 ({
1734 if (i->sw_if_index == sw_if_index)
1735 return VNET_API_ERROR_VALUE_EXIST;
1736 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001737 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001738
Matus Fabian588144a2016-10-24 03:30:00 -07001739 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
Matus Fabianab395ec2018-09-20 23:18:41 -07001740 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
Matus Fabian588144a2016-10-24 03:30:00 -07001741 else
Matus Fabian475f0552016-10-19 06:17:52 -07001742 {
Matus Fabian066f0342017-02-10 03:48:01 -08001743 if (sm->num_workers > 1 && !sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001744 feature_name =
1745 is_inside ? "nat44-in2out-worker-handoff" :
1746 "nat44-out2in-worker-handoff";
Matus Fabian066f0342017-02-10 03:48:01 -08001747 else if (sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001748 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
Matus Fabiana6110b62018-06-13 05:39:07 -07001749 else if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001750 feature_name = is_inside ? "nat44-ed-in2out" : "nat44-ed-out2in";
Matus Fabian475f0552016-10-19 06:17:52 -07001751 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001752 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
Matus Fabian475f0552016-10-19 06:17:52 -07001753 }
Matus Fabian588144a2016-10-24 03:30:00 -07001754
Matus Fabian066f0342017-02-10 03:48:01 -08001755 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001756 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07001757 NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001758
Matus Fabian066f0342017-02-10 03:48:01 -08001759 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001760 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07001761 NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001762
Matus Fabian8008d7c2018-07-09 01:34:20 -07001763 if (!is_inside)
1764 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001765 /* *INDENT-OFF* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001766 vec_foreach (outside_fib, sm->outside_fibs)
1767 {
1768 if (outside_fib->fib_index == fib_index)
1769 {
1770 if (is_del)
1771 {
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05001772 outside_fib->refcount--;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001773 if (!outside_fib->refcount)
1774 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1775 }
1776 else
1777 outside_fib->refcount++;
1778 goto feature_set;
1779 }
1780 }
Matus Fabianab395ec2018-09-20 23:18:41 -07001781 /* *INDENT-ON* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001782 if (!is_del)
Matus Fabianab395ec2018-09-20 23:18:41 -07001783 {
1784 vec_add2 (sm->outside_fibs, outside_fib, 1);
1785 outside_fib->refcount = 1;
1786 outside_fib->fib_index = fib_index;
1787 }
Matus Fabian8008d7c2018-07-09 01:34:20 -07001788 }
1789feature_set:
Matus Fabianab395ec2018-09-20 23:18:41 -07001790 /* *INDENT-OFF* */
Matus Fabian588144a2016-10-24 03:30:00 -07001791 pool_foreach (i, sm->interfaces,
1792 ({
1793 if (i->sw_if_index == sw_if_index)
1794 {
1795 if (is_del)
Matus Fabian36ea2d62017-10-24 04:13:49 -07001796 {
1797 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1798 {
1799 if (is_inside)
1800 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1801 else
1802 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1803
1804 if (sm->num_workers > 1 && !sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001805 {
1806 del_feature_name = "nat44-handoff-classify";
1807 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1808 "nat44-out2in-worker-handoff";
1809 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001810 else if (sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001811 {
1812 del_feature_name = "nat44-det-classify";
1813 feature_name = !is_inside ? "nat44-det-in2out" :
1814 "nat44-det-out2in";
1815 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001816 else if (sm->endpoint_dependent)
1817 {
1818 del_feature_name = "nat44-ed-classify";
1819 feature_name = !is_inside ? "nat44-ed-in2out" :
1820 "nat44-ed-out2in";
1821 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001822 else
Milan Lenco2aa22902018-01-22 14:05:14 +01001823 {
1824 del_feature_name = "nat44-classify";
1825 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1826 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001827
1828 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1829 sw_if_index, 0, 0, 0);
1830 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1831 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001832 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001833 {
1834 if (sm->endpoint_dependent)
1835 vnet_feature_enable_disable ("ip4-local",
1836 "nat44-ed-hairpinning",
1837 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001838 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001839 vnet_feature_enable_disable ("ip4-local",
1840 "nat44-hairpinning",
1841 sw_if_index, 1, 0, 0);
1842 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001843 }
1844 else
1845 {
1846 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1847 sw_if_index, 0, 0, 0);
1848 pool_put (sm->interfaces, i);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001849 if (is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001850 {
1851 if (sm->endpoint_dependent)
1852 vnet_feature_enable_disable ("ip4-local",
1853 "nat44-ed-hairpinning",
1854 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001855 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001856 vnet_feature_enable_disable ("ip4-local",
1857 "nat44-hairpinning",
1858 sw_if_index, 0, 0, 0);
1859 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001860 }
1861 }
Matus Fabian588144a2016-10-24 03:30:00 -07001862 else
Matus Fabian36ea2d62017-10-24 04:13:49 -07001863 {
1864 if ((nat_interface_is_inside(i) && is_inside) ||
1865 (nat_interface_is_outside(i) && !is_inside))
1866 return 0;
1867
1868 if (sm->num_workers > 1 && !sm->deterministic)
1869 {
1870 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1871 "nat44-out2in-worker-handoff";
1872 feature_name = "nat44-handoff-classify";
1873 }
1874 else if (sm->deterministic)
1875 {
1876 del_feature_name = !is_inside ? "nat44-det-in2out" :
1877 "nat44-det-out2in";
1878 feature_name = "nat44-det-classify";
1879 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001880 else if (sm->endpoint_dependent)
1881 {
1882 del_feature_name = !is_inside ? "nat44-ed-in2out" :
1883 "nat44-ed-out2in";
1884 feature_name = "nat44-ed-classify";
1885 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001886 else
1887 {
1888 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1889 feature_name = "nat44-classify";
1890 }
1891
1892 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1893 sw_if_index, 0, 0, 0);
1894 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1895 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001896 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001897 {
1898 if (sm->endpoint_dependent)
1899 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1900 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001901 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001902 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1903 sw_if_index, 0, 0, 0);
1904 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001905 goto set_flags;
1906 }
Matus Fabian588144a2016-10-24 03:30:00 -07001907
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001908 goto fib;
Matus Fabian588144a2016-10-24 03:30:00 -07001909 }
1910 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001911 /* *INDENT-ON* */
Matus Fabian588144a2016-10-24 03:30:00 -07001912
1913 if (is_del)
1914 return VNET_API_ERROR_NO_SUCH_ENTRY;
1915
1916 pool_get (sm->interfaces, i);
1917 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001918 i->flags = 0;
Matus Fabianab395ec2018-09-20 23:18:41 -07001919 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1920 0);
Matus Fabian36ea2d62017-10-24 04:13:49 -07001921
Matus Fabian35dfedc2018-04-26 02:12:20 -07001922 if (is_inside && !sm->out2in_dpo)
Matus Fabiana6110b62018-06-13 05:39:07 -07001923 {
1924 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001925 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1926 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001927 else if (!sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001928 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1929 sw_if_index, 1, 0, 0);
Matus Fabiana6110b62018-06-13 05:39:07 -07001930 }
Matus Fabian35dfedc2018-04-26 02:12:20 -07001931
Matus Fabian36ea2d62017-10-24 04:13:49 -07001932set_flags:
1933 if (is_inside)
Matus Fabian35dfedc2018-04-26 02:12:20 -07001934 {
1935 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1936 return 0;
1937 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001938 else
1939 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian588144a2016-10-24 03:30:00 -07001940
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001941 /* Add/delete external addresses to FIB */
1942fib:
Matus Fabianab395ec2018-09-20 23:18:41 -07001943 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001944 vec_foreach (ap, sm->addresses)
Matus Fabian066f0342017-02-10 03:48:01 -08001945 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001946
1947 pool_foreach (m, sm->static_mappings,
1948 ({
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07001949 if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001950 continue;
1951
Matus Fabian066f0342017-02-10 03:48:01 -08001952 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1953 }));
1954
1955 pool_foreach (dm, sm->det_maps,
1956 ({
1957 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001958 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001959 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001960
Matus Fabian588144a2016-10-24 03:30:00 -07001961 return 0;
1962}
1963
Matus Fabianab395ec2018-09-20 23:18:41 -07001964int
1965snat_interface_add_del_output_feature (u32 sw_if_index,
1966 u8 is_inside, int is_del)
Matus Fabian93d84c92017-07-19 08:06:01 -07001967{
1968 snat_main_t *sm = &snat_main;
1969 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001970 snat_address_t *ap;
1971 snat_static_mapping_t *m;
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05001972 nat_outside_fib_t *outside_fib;
1973 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1974 sw_if_index);
1975
Matus Fabian93d84c92017-07-19 08:06:01 -07001976
1977 if (sm->deterministic ||
1978 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1979 return VNET_API_ERROR_UNSUPPORTED;
1980
Matus Fabianab395ec2018-09-20 23:18:41 -07001981 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001982 pool_foreach (i, sm->interfaces,
1983 ({
1984 if (i->sw_if_index == sw_if_index)
1985 return VNET_API_ERROR_VALUE_EXIST;
1986 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001987 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001988
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05001989 if (!is_inside)
1990 {
1991 /* *INDENT-OFF* */
1992 vec_foreach (outside_fib, sm->outside_fibs)
1993 {
1994 if (outside_fib->fib_index == fib_index)
1995 {
1996 if (is_del)
1997 {
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05001998 outside_fib->refcount--;
Dmitry Vakhrushevf5641392019-01-16 09:44:03 -05001999 if (!outside_fib->refcount)
2000 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2001 }
2002 else
2003 outside_fib->refcount++;
2004 goto feature_set;
2005 }
2006 }
2007 /* *INDENT-ON* */
2008 if (!is_del)
2009 {
2010 vec_add2 (sm->outside_fibs, outside_fib, 1);
2011 outside_fib->refcount = 1;
2012 outside_fib->fib_index = fib_index;
2013 }
2014 }
2015
2016feature_set:
Matus Fabian93d84c92017-07-19 08:06:01 -07002017 if (is_inside)
Matus Fabian161c59c2017-07-21 03:46:03 -07002018 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002019 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002020 {
2021 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2022 sw_if_index, !is_del, 0, 0);
2023 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2024 sw_if_index, !is_del, 0, 0);
2025 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002026 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002027 {
2028 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2029 sw_if_index, !is_del, 0, 0);
2030 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2031 sw_if_index, !is_del, 0, 0);
2032 }
Matus Fabian161c59c2017-07-21 03:46:03 -07002033 goto fq;
2034 }
Matus Fabian93d84c92017-07-19 08:06:01 -07002035
2036 if (sm->num_workers > 1)
2037 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002038 vnet_feature_enable_disable ("ip4-unicast",
Matus Fabianab395ec2018-09-20 23:18:41 -07002039 "nat44-out2in-worker-handoff",
2040 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002041 vnet_feature_enable_disable ("ip4-output",
Matus Fabianab395ec2018-09-20 23:18:41 -07002042 "nat44-in2out-output-worker-handoff",
2043 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002044 }
2045 else
2046 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002047 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002048 {
2049 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
2050 sw_if_index, !is_del, 0, 0);
2051 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2052 sw_if_index, !is_del, 0, 0);
2053 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002054 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002055 {
2056 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2057 sw_if_index, !is_del, 0, 0);
2058 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2059 sw_if_index, !is_del, 0, 0);
2060 }
Matus Fabian93d84c92017-07-19 08:06:01 -07002061 }
2062
Matus Fabian161c59c2017-07-21 03:46:03 -07002063fq:
Matus Fabian93d84c92017-07-19 08:06:01 -07002064 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2065 sm->fq_in2out_output_index =
2066 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
2067
2068 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07002069 sm->fq_out2in_index =
2070 vlib_frame_queue_main_init (sm->out2in_node_index, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07002071
Matus Fabianab395ec2018-09-20 23:18:41 -07002072 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002073 pool_foreach (i, sm->output_feature_interfaces,
2074 ({
2075 if (i->sw_if_index == sw_if_index)
2076 {
2077 if (is_del)
2078 pool_put (sm->output_feature_interfaces, i);
2079 else
2080 return VNET_API_ERROR_VALUE_EXIST;
2081
2082 goto fib;
2083 }
2084 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002085 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002086
2087 if (is_del)
2088 return VNET_API_ERROR_NO_SUCH_ENTRY;
2089
2090 pool_get (sm->output_feature_interfaces, i);
2091 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07002092 i->flags = 0;
2093 if (is_inside)
2094 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2095 else
2096 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian93d84c92017-07-19 08:06:01 -07002097
2098 /* Add/delete external addresses to FIB */
2099fib:
2100 if (is_inside)
2101 return 0;
2102
Matus Fabianab395ec2018-09-20 23:18:41 -07002103 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002104 vec_foreach (ap, sm->addresses)
2105 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2106
2107 pool_foreach (m, sm->static_mappings,
2108 ({
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002109 if (!((is_addr_only_static_mapping(m))) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabian93d84c92017-07-19 08:06:01 -07002110 continue;
2111
2112 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2113 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002114 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07002115
2116 return 0;
2117}
2118
Matus Fabianab395ec2018-09-20 23:18:41 -07002119int
2120snat_set_workers (uword * bitmap)
Matus Fabian475f0552016-10-19 06:17:52 -07002121{
2122 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07002123 int i, j = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002124
2125 if (sm->num_workers < 2)
2126 return VNET_API_ERROR_FEATURE_DISABLED;
2127
2128 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2129 return VNET_API_ERROR_INVALID_WORKER;
2130
2131 vec_free (sm->workers);
Matus Fabianab395ec2018-09-20 23:18:41 -07002132 /* *INDENT-OFF* */
Matus Fabian475f0552016-10-19 06:17:52 -07002133 clib_bitmap_foreach (i, bitmap,
2134 ({
2135 vec_add1(sm->workers, i);
Matus Fabian10491392018-01-05 05:03:35 -08002136 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
Matus Fabian7801ca22017-08-03 00:58:05 -07002137 j++;
Matus Fabian475f0552016-10-19 06:17:52 -07002138 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07002139 /* *INDENT-ON* */
Matus Fabian475f0552016-10-19 06:17:52 -07002140
Matus Fabian7801ca22017-08-03 00:58:05 -07002141 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2142 sm->num_snat_thread = _vec_len (sm->workers);
2143
Matus Fabian475f0552016-10-19 06:17:52 -07002144 return 0;
2145}
2146
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002147static void
2148snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2149 u32 old_fib_index)
2150{
2151 snat_main_t *sm = &snat_main;
2152 nat_outside_fib_t *outside_fib;
2153 snat_interface_t *i;
2154 u8 is_add = 1;
2155
2156 if (new_fib_index == old_fib_index)
2157 return;
2158
2159 if (!vec_len (sm->outside_fibs))
2160 return;
2161
2162 pool_foreach (i, sm->interfaces, (
2163 {
2164 if (i->sw_if_index == sw_if_index)
2165 {
2166 if (!(nat_interface_is_outside (i)))
2167 return;}
2168 }
2169 ));
2170 vec_foreach (outside_fib, sm->outside_fibs)
2171 {
2172 if (outside_fib->fib_index == old_fib_index)
2173 {
2174 outside_fib->refcount--;
2175 if (!outside_fib->refcount)
2176 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2177 break;
2178 }
2179 }
2180
2181 vec_foreach (outside_fib, sm->outside_fibs)
2182 {
2183 if (outside_fib->fib_index == new_fib_index)
2184 {
2185 outside_fib->refcount++;
2186 is_add = 0;
2187 break;
2188 }
2189 }
2190
2191 if (is_add)
2192 {
2193 vec_add2 (sm->outside_fibs, outside_fib, 1);
2194 outside_fib->refcount = 1;
2195 outside_fib->fib_index = new_fib_index;
2196 }
2197}
2198
2199static void
2200snat_ip4_table_bind (ip4_main_t * im,
2201 uword opaque,
2202 u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2203{
2204 snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2205}
Dave Barach8b275372017-01-16 10:54:02 -05002206
Dave Barachcab65ec2017-01-11 13:01:14 -05002207static void
2208snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002209 uword opaque,
2210 u32 sw_if_index,
2211 ip4_address_t * address,
2212 u32 address_length,
2213 u32 if_address_index, u32 is_delete);
Dave Barachcab65ec2017-01-11 13:01:14 -05002214
Matus Fabian4772e7a2018-04-04 00:38:02 -07002215static void
2216nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002217 uword opaque,
2218 u32 sw_if_index,
2219 ip4_address_t * address,
2220 u32 address_length,
2221 u32 if_address_index, u32 is_delete);
Matus Fabian4772e7a2018-04-04 00:38:02 -07002222
Matus Fabian27697102017-11-09 01:43:47 -08002223static int
2224nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002225 u32 fib_index,
2226 u32 thread_index,
2227 snat_session_key_t * k,
2228 u16 port_per_thread, u32 snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08002229
Matus Fabianab395ec2018-09-20 23:18:41 -07002230static clib_error_t *
2231snat_init (vlib_main_t * vm)
Dave Barach20c02cb2016-06-26 10:42:08 -04002232{
Matus Fabianab395ec2018-09-20 23:18:41 -07002233 snat_main_t *sm = &snat_main;
2234 clib_error_t *error = 0;
2235 ip4_main_t *im = &ip4_main;
2236 ip_lookup_main_t *lm = &im->lookup_main;
Matus Fabian475f0552016-10-19 06:17:52 -07002237 uword *p;
2238 vlib_thread_registration_t *tr;
2239 vlib_thread_main_t *tm = vlib_get_thread_main ();
2240 uword *bitmap = 0;
2241 u32 i;
Dave Barachcab65ec2017-01-11 13:01:14 -05002242 ip4_add_del_interface_address_callback_t cb4;
Matus Fabianab395ec2018-09-20 23:18:41 -07002243 vlib_node_t *error_drop_node;
Dave Barach20c02cb2016-06-26 10:42:08 -04002244
Dave Barach20c02cb2016-06-26 10:42:08 -04002245 sm->vlib_main = vm;
Matus Fabianab395ec2018-09-20 23:18:41 -07002246 sm->vnet_main = vnet_get_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -04002247 sm->ip4_main = im;
2248 sm->ip4_lookup_main = lm;
2249 sm->api_main = &api_main;
Matus Fabian475f0552016-10-19 06:17:52 -07002250 sm->first_worker_index = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002251 sm->num_workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07002252 sm->num_snat_thread = 1;
Matus Fabian475f0552016-10-19 06:17:52 -07002253 sm->workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07002254 sm->port_per_thread = 0xffff - 1024;
Matus Fabian475f0552016-10-19 06:17:52 -07002255 sm->fq_in2out_index = ~0;
2256 sm->fq_out2in_index = ~0;
Matus Fabian6a0946f2017-04-12 03:36:13 -07002257 sm->udp_timeout = SNAT_UDP_TIMEOUT;
2258 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
2259 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
2260 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
Matus Fabian27697102017-11-09 01:43:47 -08002261 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002262 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Juraj Sloboda7b929792017-11-23 13:20:48 +01002263 sm->forwarding_enabled = 0;
Matus Fabian229c1aa2018-05-28 04:09:52 -07002264 sm->log_class = vlib_log_register_class ("nat", 0);
2265 error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2266 sm->error_node_index = error_drop_node->index;
Matus Fabianbb4e0222018-09-13 02:36:25 -07002267 sm->mss_clamping = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07002268
2269 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2270 if (p)
2271 {
2272 tr = (vlib_thread_registration_t *) p[0];
2273 if (tr)
Matus Fabianab395ec2018-09-20 23:18:41 -07002274 {
2275 sm->num_workers = tr->count;
2276 sm->first_worker_index = tr->first_index;
2277 }
Matus Fabian475f0552016-10-19 06:17:52 -07002278 }
2279
Matus Fabian7801ca22017-08-03 00:58:05 -07002280 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2281
Matus Fabian475f0552016-10-19 06:17:52 -07002282 /* Use all available workers by default */
2283 if (sm->num_workers > 1)
2284 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002285 for (i = 0; i < sm->num_workers; i++)
2286 bitmap = clib_bitmap_set (bitmap, i, 1);
2287 snat_set_workers (bitmap);
Matus Fabian475f0552016-10-19 06:17:52 -07002288 clib_bitmap_free (bitmap);
2289 }
Matus Fabian7801ca22017-08-03 00:58:05 -07002290 else
2291 {
2292 sm->per_thread_data[0].snat_thread_index = 0;
2293 }
Dave Barach20c02cb2016-06-26 10:42:08 -04002294
Matus Fabianab395ec2018-09-20 23:18:41 -07002295 error = snat_api_init (vm, sm);
Matus Fabian08ce4322017-06-19 05:28:27 -07002296 if (error)
2297 return error;
Dave Barach20c02cb2016-06-26 10:42:08 -04002298
Dave Barachcab65ec2017-01-11 13:01:14 -05002299 /* Set up the interface address add/del callback */
2300 cb4.function = snat_ip4_add_del_interface_address_cb;
2301 cb4.function_opaque = 0;
2302
2303 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2304
Matus Fabian4772e7a2018-04-04 00:38:02 -07002305 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2306 cb4.function_opaque = 0;
2307
2308 vec_add1 (im->add_del_interface_address_callbacks, cb4);
2309
Juraj Slobodacba69362017-12-19 02:09:32 +01002310 nat_dpo_module_init ();
2311
Matus Fabianfd0d5082018-12-18 01:08:51 -08002312 /* Init counters */
2313 sm->total_users.name = "total-users";
2314 sm->total_users.stat_segment_name = "/nat44/total-users";
2315 vlib_validate_simple_counter (&sm->total_users, 0);
2316 vlib_zero_simple_counter (&sm->total_users, 0);
2317 sm->total_sessions.name = "total-sessions";
2318 sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2319 vlib_validate_simple_counter (&sm->total_sessions, 0);
2320 vlib_zero_simple_counter (&sm->total_sessions, 0);
2321
Matus Fabianeea28d72017-01-13 04:15:54 -08002322 /* Init IPFIX logging */
Matus Fabianab395ec2018-09-20 23:18:41 -07002323 snat_ipfix_logging_init (vm);
Matus Fabianeea28d72017-01-13 04:15:54 -08002324
Matus Fabianefcd1e92017-08-15 06:59:19 -07002325 /* Init NAT64 */
Matus Fabianab395ec2018-09-20 23:18:41 -07002326 error = nat64_init (vm);
Matus Fabianefcd1e92017-08-15 06:59:19 -07002327 if (error)
2328 return error;
Matus Fabian06596c52017-06-06 04:53:28 -07002329
Matus Fabianab395ec2018-09-20 23:18:41 -07002330 dslite_init (vm);
Matus Fabian8ebe6252017-11-06 05:04:53 -08002331
Matus Fabianab395ec2018-09-20 23:18:41 -07002332 nat66_init ();
Matus Fabianf2a23cc2018-01-22 03:41:53 -08002333
Dmitry Vakhrushevee3fb622019-01-22 05:28:53 -05002334 ip4_table_bind_callback_t cbt4 = {
2335 .function = snat_ip4_table_bind,
2336 };
2337 vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2338
Matus Fabianefcd1e92017-08-15 06:59:19 -07002339 /* Init virtual fragmenentation reassembly */
Matus Fabianab395ec2018-09-20 23:18:41 -07002340 return nat_reass_init (vm);
Dave Barach20c02cb2016-06-26 10:42:08 -04002341}
2342
2343VLIB_INIT_FUNCTION (snat_init);
2344
Matus Fabianab395ec2018-09-20 23:18:41 -07002345void
2346snat_free_outside_address_and_port (snat_address_t * addresses,
2347 u32 thread_index, snat_session_key_t * k)
Dave Barach20c02cb2016-06-26 10:42:08 -04002348{
2349 snat_address_t *a;
shubing guo762a4932018-08-13 17:16:46 +08002350 u32 address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04002351 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
Matus Fabian2ba92e32017-08-21 07:05:03 -07002352
Matus Fabianab395ec2018-09-20 23:18:41 -07002353 for (address_index = 0; address_index < vec_len (addresses);
2354 address_index++)
shubing guo762a4932018-08-13 17:16:46 +08002355 {
2356 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07002357 break;
shubing guo762a4932018-08-13 17:16:46 +08002358 }
2359
Matus Fabian8ebe6252017-11-06 05:04:53 -08002360 ASSERT (address_index < vec_len (addresses));
Dave Barach20c02cb2016-06-26 10:42:08 -04002361
Matus Fabian8ebe6252017-11-06 05:04:53 -08002362 a = addresses + address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04002363
Matus Fabian09d96f42017-02-02 01:43:00 -08002364 switch (k->protocol)
2365 {
2366#define _(N, i, n, s) \
2367 case SNAT_PROTOCOL_##N: \
2368 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2369 port_host_byte_order) == 1); \
2370 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2371 port_host_byte_order, 0); \
2372 a->busy_##n##_ports--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07002373 a->busy_##n##_ports_per_thread[thread_index]--; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002374 break;
2375 foreach_snat_protocol
2376#undef _
2377 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002378 nat_log_info ("unknown protocol");
Matus Fabian09d96f42017-02-02 01:43:00 -08002379 return;
2380 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07002381}
Dave Barach20c02cb2016-06-26 10:42:08 -04002382
Matus Fabianab395ec2018-09-20 23:18:41 -07002383int
2384snat_static_mapping_match (snat_main_t * sm,
2385 snat_session_key_t match,
2386 snat_session_key_t * mapping,
2387 u8 by_external,
2388 u8 * is_addr_only,
2389 twice_nat_type_t * twice_nat,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002390 lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2391 u8 * is_identity_nat)
Matus Fabiandb649882016-08-26 05:45:27 -07002392{
2393 clib_bihash_kv_8_8_t kv, value;
2394 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -08002395 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -07002396 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
Matus Fabianb6865082018-12-06 03:11:09 -08002397 u32 rand, lo = 0, hi, mid, *tmp = 0, i;
Matus Fabianea5b5be2018-09-03 05:02:23 -07002398 u8 backend_index;
Matus Fabianb6865082018-12-06 03:11:09 -08002399 nat44_lb_addr_port_t *local;
Matus Fabiandb649882016-08-26 05:45:27 -07002400
Matus Fabian8008d7c2018-07-09 01:34:20 -07002401 m_key.fib_index = match.fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -07002402 if (by_external)
Matus Fabian8008d7c2018-07-09 01:34:20 -07002403 {
2404 mapping_hash = &sm->static_mapping_by_external;
2405 m_key.fib_index = 0;
2406 }
Matus Fabiandb649882016-08-26 05:45:27 -07002407
2408 m_key.addr = match.addr;
2409 m_key.port = clib_net_to_host_u16 (match.port);
Matus Fabian09d96f42017-02-02 01:43:00 -08002410 m_key.protocol = match.protocol;
Matus Fabiandb649882016-08-26 05:45:27 -07002411
2412 kv.key = m_key.as_u64;
2413
2414 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2415 {
2416 /* Try address only mapping */
2417 m_key.port = 0;
Matus Fabian09d96f42017-02-02 01:43:00 -08002418 m_key.protocol = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07002419 kv.key = m_key.as_u64;
2420 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
Matus Fabianab395ec2018-09-20 23:18:41 -07002421 return 1;
Matus Fabiandb649882016-08-26 05:45:27 -07002422 }
2423
2424 m = pool_elt_at_index (sm->static_mappings, value.value);
2425
2426 if (by_external)
2427 {
Matus Fabian82b4ceb2018-10-11 04:28:48 -07002428 if (is_lb_static_mapping (m))
Matus Fabianab395ec2018-09-20 23:18:41 -07002429 {
2430 if (PREDICT_FALSE (lb != 0))
2431 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2432 if (m->affinity)
2433 {
2434 if (nat_affinity_find_and_lock (ext_host_addr[0], match.addr,
2435 match.protocol, match.port,
2436 &backend_index))
2437 goto get_local;
Matus Fabianea5b5be2018-09-03 05:02:23 -07002438
Matus Fabianb6865082018-12-06 03:11:09 -08002439 local = pool_elt_at_index (m->locals, backend_index);
2440 mapping->addr = local->addr;
2441 mapping->port = clib_host_to_net_u16 (local->port);
2442 mapping->fib_index = local->fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07002443 goto end;
2444 }
2445 get_local:
Matus Fabianb6865082018-12-06 03:11:09 -08002446 /* *INDENT-OFF* */
2447 pool_foreach_index (i, m->locals,
2448 ({
2449 vec_add1 (tmp, i);
2450 }));
2451 /* *INDENT-ON* */
2452 hi = vec_len (tmp) - 1;
2453 local = pool_elt_at_index (m->locals, tmp[hi]);
2454 rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
Matus Fabianab395ec2018-09-20 23:18:41 -07002455 while (lo < hi)
2456 {
2457 mid = ((hi - lo) >> 1) + lo;
Matus Fabianb6865082018-12-06 03:11:09 -08002458 local = pool_elt_at_index (m->locals, tmp[mid]);
2459 (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
Matus Fabianab395ec2018-09-20 23:18:41 -07002460 }
Matus Fabianb6865082018-12-06 03:11:09 -08002461 local = pool_elt_at_index (m->locals, tmp[lo]);
2462 if (!(local->prefix >= rand))
Matus Fabianab395ec2018-09-20 23:18:41 -07002463 return 1;
2464 if (PREDICT_FALSE (sm->num_workers > 1))
2465 {
2466 ip4_header_t ip = {
Matus Fabianb6865082018-12-06 03:11:09 -08002467 .src_address = local->addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07002468 };
2469 if (sm->worker_in2out_cb (&ip, m->fib_index) !=
2470 vlib_get_thread_index ())
2471 goto get_local;
2472 }
Matus Fabianb6865082018-12-06 03:11:09 -08002473 mapping->addr = local->addr;
2474 mapping->port = clib_host_to_net_u16 (local->port);
2475 mapping->fib_index = local->fib_index;
Matus Fabianab395ec2018-09-20 23:18:41 -07002476 if (m->affinity)
2477 {
2478 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2479 match.protocol, match.port,
Matus Fabianb6865082018-12-06 03:11:09 -08002480 tmp[lo], m->affinity,
Matus Fabianab395ec2018-09-20 23:18:41 -07002481 m->affinity_per_service_list_head_index))
2482 nat_log_info ("create affinity record failed");
2483 }
Matus Fabianb6865082018-12-06 03:11:09 -08002484 vec_free (tmp);
Matus Fabianab395ec2018-09-20 23:18:41 -07002485 }
Matus Fabian704018c2017-09-04 02:17:18 -07002486 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002487 {
2488 if (PREDICT_FALSE (lb != 0))
2489 *lb = NO_LB_NAT;
2490 mapping->fib_index = m->fib_index;
2491 mapping->addr = m->local_addr;
2492 /* Address only mapping doesn't change port */
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002493 mapping->port = is_addr_only_static_mapping (m) ? match.port
Matus Fabianab395ec2018-09-20 23:18:41 -07002494 : clib_host_to_net_u16 (m->local_port);
2495 }
Matus Fabian704018c2017-09-04 02:17:18 -07002496 mapping->protocol = m->proto;
Matus Fabiandb649882016-08-26 05:45:27 -07002497 }
2498 else
2499 {
2500 mapping->addr = m->external_addr;
2501 /* Address only mapping doesn't change port */
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002502 mapping->port = is_addr_only_static_mapping (m) ? match.port
Matus Fabianab395ec2018-09-20 23:18:41 -07002503 : clib_host_to_net_u16 (m->external_port);
Matus Fabiandb649882016-08-26 05:45:27 -07002504 mapping->fib_index = sm->outside_fib_index;
2505 }
2506
Matus Fabianea5b5be2018-09-03 05:02:23 -07002507end:
Matus Fabianab395ec2018-09-20 23:18:41 -07002508 if (PREDICT_FALSE (is_addr_only != 0))
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002509 *is_addr_only = is_addr_only_static_mapping (m);
Juraj Slobodad3677682017-04-14 03:24:45 +02002510
Matus Fabianab395ec2018-09-20 23:18:41 -07002511 if (PREDICT_FALSE (twice_nat != 0))
Matus Fabianb932d262017-12-18 05:38:24 -08002512 *twice_nat = m->twice_nat;
2513
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07002514 if (PREDICT_FALSE (is_identity_nat != 0))
2515 *is_identity_nat = is_identity_static_mapping (m);
2516
Matus Fabiandb649882016-08-26 05:45:27 -07002517 return 0;
2518}
2519
Matus Fabian7801ca22017-08-03 00:58:05 -07002520static_always_inline u16
Matus Fabian8ebe6252017-11-06 05:04:53 -08002521snat_random_port (u16 min, u16 max)
Matus Fabian7801ca22017-08-03 00:58:05 -07002522{
Matus Fabian8ebe6252017-11-06 05:04:53 -08002523 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07002524 return min + random_u32 (&sm->random_seed) /
Matus Fabianab395ec2018-09-20 23:18:41 -07002525 (random_u32_max () / (max - min + 1) + 1);
Matus Fabian7801ca22017-08-03 00:58:05 -07002526}
2527
Matus Fabian27697102017-11-09 01:43:47 -08002528int
2529snat_alloc_outside_address_and_port (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002530 u32 fib_index,
2531 u32 thread_index,
2532 snat_session_key_t * k,
2533 u16 port_per_thread,
2534 u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002535{
2536 snat_main_t *sm = &snat_main;
2537
Matus Fabianab395ec2018-09-20 23:18:41 -07002538 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2539 port_per_thread, snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08002540}
2541
2542static int
2543nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002544 u32 fib_index,
2545 u32 thread_index,
2546 snat_session_key_t * k,
2547 u16 port_per_thread, u32 snat_thread_index)
Dave Barach20c02cb2016-06-26 10:42:08 -04002548{
Matus Fabianab395ec2018-09-20 23:18:41 -07002549 int i;
Matus Fabian51e759f2017-12-07 23:22:51 -08002550 snat_address_t *a, *ga = 0;
Dave Barach20c02cb2016-06-26 10:42:08 -04002551 u32 portnum;
2552
Matus Fabian8ebe6252017-11-06 05:04:53 -08002553 for (i = 0; i < vec_len (addresses); i++)
Dave Barach20c02cb2016-06-26 10:42:08 -04002554 {
Matus Fabian8ebe6252017-11-06 05:04:53 -08002555 a = addresses + i;
Matus Fabian09d96f42017-02-02 01:43:00 -08002556 switch (k->protocol)
Matus Fabianab395ec2018-09-20 23:18:41 -07002557 {
Matus Fabian09d96f42017-02-02 01:43:00 -08002558#define _(N, j, n, s) \
2559 case SNAT_PROTOCOL_##N: \
Matus Fabian8ebe6252017-11-06 05:04:53 -08002560 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002561 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002562 if (a->fib_index == fib_index) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002563 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002564 while (1) \
2565 { \
2566 portnum = (port_per_thread * \
2567 snat_thread_index) + \
2568 snat_random_port(1, port_per_thread) + 1024; \
2569 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2570 continue; \
2571 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2572 a->busy_##n##_ports_per_thread[thread_index]++; \
2573 a->busy_##n##_ports++; \
2574 k->addr = a->addr; \
2575 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002576 return 0; \
2577 } \
2578 } \
2579 else if (a->fib_index == ~0) \
2580 { \
2581 ga = a; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002582 } \
2583 } \
2584 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07002585 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -08002586#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07002587 default:
2588 nat_log_info ("unknown protocol");
2589 return 1;
2590 }
Matus Fabian09d96f42017-02-02 01:43:00 -08002591
Dave Barach20c02cb2016-06-26 10:42:08 -04002592 }
Matus Fabian51e759f2017-12-07 23:22:51 -08002593
2594 if (ga)
2595 {
2596 a = ga;
2597 switch (k->protocol)
2598 {
2599#define _(N, j, n, s) \
2600 case SNAT_PROTOCOL_##N: \
2601 while (1) \
2602 { \
2603 portnum = (port_per_thread * \
2604 snat_thread_index) + \
2605 snat_random_port(1, port_per_thread) + 1024; \
2606 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2607 continue; \
2608 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2609 a->busy_##n##_ports_per_thread[thread_index]++; \
2610 a->busy_##n##_ports++; \
2611 k->addr = a->addr; \
2612 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002613 return 0; \
2614 }
2615 break;
2616 foreach_snat_protocol
2617#undef _
2618 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002619 nat_log_info ("unknown protocol");
Matus Fabian51e759f2017-12-07 23:22:51 -08002620 return 1;
2621 }
2622 }
2623
Dave Barach20c02cb2016-06-26 10:42:08 -04002624 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002625 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Dave Barach20c02cb2016-06-26 10:42:08 -04002626 return 1;
2627}
2628
Matus Fabian27697102017-11-09 01:43:47 -08002629static int
2630nat_alloc_addr_and_port_mape (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002631 u32 fib_index,
2632 u32 thread_index,
2633 snat_session_key_t * k,
2634 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002635{
2636 snat_main_t *sm = &snat_main;
2637 snat_address_t *a = addresses;
2638 u16 m, ports, portnum, A, j;
2639 m = 16 - (sm->psid_offset + sm->psid_length);
2640 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2641
2642 if (!vec_len (addresses))
2643 goto exhausted;
2644
2645 switch (k->protocol)
2646 {
2647#define _(N, i, n, s) \
2648 case SNAT_PROTOCOL_##N: \
2649 if (a->busy_##n##_ports < ports) \
2650 { \
2651 while (1) \
2652 { \
2653 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2654 j = snat_random_port(0, pow2_mask(m)); \
2655 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2656 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2657 continue; \
2658 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2659 a->busy_##n##_ports++; \
2660 k->addr = a->addr; \
2661 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian27697102017-11-09 01:43:47 -08002662 return 0; \
2663 } \
2664 } \
2665 break;
2666 foreach_snat_protocol
2667#undef _
2668 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002669 nat_log_info ("unknown protocol");
Matus Fabian27697102017-11-09 01:43:47 -08002670 return 1;
2671 }
2672
2673exhausted:
2674 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002675 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Matus Fabian27697102017-11-09 01:43:47 -08002676 return 1;
2677}
Dave Barach20c02cb2016-06-26 10:42:08 -04002678
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002679static int
2680nat_alloc_addr_and_port_range (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002681 u32 fib_index,
2682 u32 thread_index,
2683 snat_session_key_t * k,
2684 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002685{
2686 snat_main_t *sm = &snat_main;
2687 snat_address_t *a = addresses;
2688 u16 portnum, ports;
2689
2690 ports = sm->end_port - sm->start_port + 1;
2691
2692 if (!vec_len (addresses))
2693 goto exhausted;
2694
2695 switch (k->protocol)
2696 {
2697#define _(N, i, n, s) \
2698 case SNAT_PROTOCOL_##N: \
2699 if (a->busy_##n##_ports < ports) \
2700 { \
2701 while (1) \
2702 { \
2703 portnum = snat_random_port(sm->start_port, sm->end_port); \
2704 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2705 continue; \
2706 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2707 a->busy_##n##_ports++; \
2708 k->addr = a->addr; \
2709 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002710 return 0; \
2711 } \
2712 } \
2713 break;
2714 foreach_snat_protocol
2715#undef _
2716 default:
2717 nat_log_info ("unknown protocol");
2718 return 1;
2719 }
2720
2721exhausted:
2722 /* Totally out of translations to use... */
Filip Varga8254ab82019-01-21 00:05:03 -08002723 snat_ipfix_logging_addresses_exhausted (thread_index, 0);
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002724 return 1;
2725}
2726
Juraj Slobodacba69362017-12-19 02:09:32 +01002727void
2728nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2729{
2730 dpo_id_t dpo_v4 = DPO_INVALID;
2731 fib_prefix_t pfx = {
2732 .fp_proto = FIB_PROTOCOL_IP4,
2733 .fp_len = 32,
2734 .fp_addr.ip4.as_u32 = addr.as_u32,
2735 };
2736
2737 if (is_add)
2738 {
2739 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2740 fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
Matus Fabianab395ec2018-09-20 23:18:41 -07002741 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
Juraj Slobodacba69362017-12-19 02:09:32 +01002742 dpo_reset (&dpo_v4);
2743 }
2744 else
2745 {
2746 fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2747 }
2748}
2749
Matus Fabian229c1aa2018-05-28 04:09:52 -07002750u8 *
2751format_session_kvp (u8 * s, va_list * args)
2752{
2753 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2754 snat_session_key_t k;
2755
2756 k.as_u64 = v->key;
2757
2758 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2759
2760 return s;
2761}
2762
2763u8 *
2764format_static_mapping_kvp (u8 * s, va_list * args)
2765{
2766 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2767 snat_session_key_t k;
2768
2769 k.as_u64 = v->key;
2770
Matus Fabian878c6462018-08-23 00:33:35 -07002771 s = format (s, "%U static-mapping-index %llu",
Matus Fabianab395ec2018-09-20 23:18:41 -07002772 format_static_mapping_key, &k, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002773
2774 return s;
2775}
2776
2777u8 *
2778format_user_kvp (u8 * s, va_list * args)
2779{
2780 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2781 snat_user_key_t k;
2782
2783 k.as_u64 = v->key;
2784
2785 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07002786 k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002787
2788 return s;
2789}
2790
2791u8 *
2792format_ed_session_kvp (u8 * s, va_list * args)
2793{
2794 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2795 nat_ed_ses_key_t k;
2796
2797 k.as_u64[0] = v->key[0];
2798 k.as_u64[1] = v->key[1];
2799
Matus Fabianab395ec2018-09-20 23:18:41 -07002800 s =
2801 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2802 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2803 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2804 format_ip_protocol, k.proto, k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002805
2806 return s;
2807}
2808
Matus Fabian066f0342017-02-10 03:48:01 -08002809static u32
2810snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2811{
2812 snat_main_t *sm = &snat_main;
Matus Fabian066f0342017-02-10 03:48:01 -08002813 u32 next_worker_index = 0;
Matus Fabian7865b5c2017-09-26 01:23:01 -07002814 u32 hash;
Matus Fabian066f0342017-02-10 03:48:01 -08002815
Matus Fabian7865b5c2017-09-26 01:23:01 -07002816 next_worker_index = sm->first_worker_index;
2817 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
Matus Fabianab395ec2018-09-20 23:18:41 -07002818 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
Matus Fabian066f0342017-02-10 03:48:01 -08002819
Matus Fabian7865b5c2017-09-26 01:23:01 -07002820 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2821 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
Matus Fabian066f0342017-02-10 03:48:01 -08002822 else
Matus Fabian7865b5c2017-09-26 01:23:01 -07002823 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
Matus Fabian066f0342017-02-10 03:48:01 -08002824
2825 return next_worker_index;
2826}
2827
2828static u32
2829snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2830{
2831 snat_main_t *sm = &snat_main;
Matus Fabianed3c1602017-09-21 05:07:12 -07002832 udp_header_t *udp;
2833 u16 port;
2834 snat_session_key_t m_key;
2835 clib_bihash_kv_8_8_t kv, value;
2836 snat_static_mapping_t *m;
Matus Fabianed3c1602017-09-21 05:07:12 -07002837 u32 proto;
Matus Fabian10491392018-01-05 05:03:35 -08002838 u32 next_worker_index = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08002839
Matus Fabianed3c1602017-09-21 05:07:12 -07002840 /* first try static mappings without port */
2841 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
Matus Fabian066f0342017-02-10 03:48:01 -08002842 {
Matus Fabianed3c1602017-09-21 05:07:12 -07002843 m_key.addr = ip0->dst_address;
2844 m_key.port = 0;
2845 m_key.protocol = 0;
2846 m_key.fib_index = rx_fib_index0;
2847 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07002848 if (!clib_bihash_search_8_8
2849 (&sm->static_mapping_by_external, &kv, &value))
2850 {
2851 m = pool_elt_at_index (sm->static_mappings, value.value);
2852 return m->workers[0];
2853 }
Matus Fabian066f0342017-02-10 03:48:01 -08002854 }
2855
Matus Fabianed3c1602017-09-21 05:07:12 -07002856 proto = ip_proto_to_snat_proto (ip0->protocol);
2857 udp = ip4_next_header (ip0);
2858 port = udp->dst_port;
Matus Fabian066f0342017-02-10 03:48:01 -08002859
Matus Fabian51e759f2017-12-07 23:22:51 -08002860 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2861 {
2862 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2863 return vlib_get_thread_index ();
2864
Matus Fabian68458672019-02-18 01:54:16 -08002865 nat_reass_ip4_t *reass;
2866 reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2867 ip0->fragment_id, ip0->protocol);
2868
2869 if (reass && (reass->thread_index != (u32) ~ 0))
2870 return reass->thread_index;
2871
2872 if (ip4_is_first_fragment (ip0))
Matus Fabian51e759f2017-12-07 23:22:51 -08002873 {
Matus Fabian68458672019-02-18 01:54:16 -08002874 reass =
2875 nat_ip4_reass_create (ip0->src_address, ip0->dst_address,
2876 ip0->fragment_id, ip0->protocol);
2877 if (!reass)
2878 goto no_reass;
Matus Fabian51e759f2017-12-07 23:22:51 -08002879
Matus Fabian68458672019-02-18 01:54:16 -08002880 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2881 {
2882 m_key.addr = ip0->dst_address;
2883 m_key.port = clib_net_to_host_u16 (port);
2884 m_key.protocol = proto;
2885 m_key.fib_index = rx_fib_index0;
2886 kv.key = m_key.as_u64;
2887 if (!clib_bihash_search_8_8
2888 (&sm->static_mapping_by_external, &kv, &value))
2889 {
2890 m = pool_elt_at_index (sm->static_mappings, value.value);
2891 reass->thread_index = m->workers[0];
2892 return reass->thread_index;
2893 }
2894 }
2895 reass->thread_index = sm->first_worker_index;
2896 reass->thread_index +=
2897 sm->workers[(clib_net_to_host_u16 (port) - 1024) /
2898 sm->port_per_thread];
2899 return reass->thread_index;
Matus Fabian51e759f2017-12-07 23:22:51 -08002900 }
Matus Fabian68458672019-02-18 01:54:16 -08002901 else
2902 return vlib_get_thread_index ();
Matus Fabian51e759f2017-12-07 23:22:51 -08002903 }
2904
Matus Fabian68458672019-02-18 01:54:16 -08002905no_reass:
Matus Fabianed3c1602017-09-21 05:07:12 -07002906 /* unknown protocol */
2907 if (PREDICT_FALSE (proto == ~0))
Matus Fabian066f0342017-02-10 03:48:01 -08002908 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002909 /* use current thread */
Matus Fabianed3c1602017-09-21 05:07:12 -07002910 return vlib_get_thread_index ();
2911 }
2912
2913 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2914 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002915 icmp46_header_t *icmp = (icmp46_header_t *) udp;
2916 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Matus Fabianed3c1602017-09-21 05:07:12 -07002917 if (!icmp_is_error_message (icmp))
Matus Fabianab395ec2018-09-20 23:18:41 -07002918 port = echo->identifier;
Matus Fabian066f0342017-02-10 03:48:01 -08002919 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002920 {
2921 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2922 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2923 void *l4_header = ip4_next_header (inner_ip);
2924 switch (proto)
2925 {
2926 case SNAT_PROTOCOL_ICMP:
2927 icmp = (icmp46_header_t *) l4_header;
2928 echo = (icmp_echo_header_t *) (icmp + 1);
2929 port = echo->identifier;
2930 break;
2931 case SNAT_PROTOCOL_UDP:
2932 case SNAT_PROTOCOL_TCP:
2933 port = ((tcp_udp_header_t *) l4_header)->src_port;
2934 break;
2935 default:
2936 return vlib_get_thread_index ();
2937 }
2938 }
Matus Fabian066f0342017-02-10 03:48:01 -08002939 }
Matus Fabian066f0342017-02-10 03:48:01 -08002940
Matus Fabianed3c1602017-09-21 05:07:12 -07002941 /* try static mappings with port */
2942 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2943 {
2944 m_key.addr = ip0->dst_address;
2945 m_key.port = clib_net_to_host_u16 (port);
2946 m_key.protocol = proto;
2947 m_key.fib_index = rx_fib_index0;
2948 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07002949 if (!clib_bihash_search_8_8
2950 (&sm->static_mapping_by_external, &kv, &value))
2951 {
2952 m = pool_elt_at_index (sm->static_mappings, value.value);
2953 return m->workers[0];
2954 }
Matus Fabianed3c1602017-09-21 05:07:12 -07002955 }
2956
2957 /* worker by outside port */
Matus Fabian10491392018-01-05 05:03:35 -08002958 next_worker_index = sm->first_worker_index;
2959 next_worker_index +=
2960 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2961 return next_worker_index;
Matus Fabian066f0342017-02-10 03:48:01 -08002962}
2963
Matus Fabiana6110b62018-06-13 05:39:07 -07002964static u32
2965nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2966{
2967 snat_main_t *sm = &snat_main;
2968 clib_bihash_kv_8_8_t kv, value;
2969 u32 proto, next_worker_index = 0;
2970 udp_header_t *udp;
2971 u16 port;
2972 snat_static_mapping_t *m;
2973 u32 hash;
2974
2975 /* first try static mappings without port */
2976 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2977 {
2978 make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -07002979 if (!clib_bihash_search_8_8
2980 (&sm->static_mapping_by_external, &kv, &value))
2981 {
2982 m = pool_elt_at_index (sm->static_mappings, value.value);
2983 return m->workers[0];
2984 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002985 }
2986
2987 proto = ip_proto_to_snat_proto (ip->protocol);
2988
2989 /* unknown protocol */
2990 if (PREDICT_FALSE (proto == ~0))
2991 {
2992 /* use current thread */
2993 return vlib_get_thread_index ();
2994 }
2995
2996 udp = ip4_next_header (ip);
2997 port = udp->dst_port;
2998
2999 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3000 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003001 icmp46_header_t *icmp = (icmp46_header_t *) udp;
3002 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Matus Fabiana6110b62018-06-13 05:39:07 -07003003 if (!icmp_is_error_message (icmp))
Matus Fabianab395ec2018-09-20 23:18:41 -07003004 port = echo->identifier;
Matus Fabiana6110b62018-06-13 05:39:07 -07003005 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003006 {
3007 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3008 proto = ip_proto_to_snat_proto (inner_ip->protocol);
3009 void *l4_header = ip4_next_header (inner_ip);
3010 switch (proto)
3011 {
3012 case SNAT_PROTOCOL_ICMP:
3013 icmp = (icmp46_header_t *) l4_header;
3014 echo = (icmp_echo_header_t *) (icmp + 1);
3015 port = echo->identifier;
3016 break;
3017 case SNAT_PROTOCOL_UDP:
3018 case SNAT_PROTOCOL_TCP:
3019 port = ((tcp_udp_header_t *) l4_header)->src_port;
3020 break;
3021 default:
3022 return vlib_get_thread_index ();
3023 }
3024 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003025 }
3026
3027 /* try static mappings with port */
3028 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3029 {
3030 make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07003031 clib_net_to_host_u16 (port));
3032 if (!clib_bihash_search_8_8
3033 (&sm->static_mapping_by_external, &kv, &value))
3034 {
3035 m = pool_elt_at_index (sm->static_mappings, value.value);
Matus Fabian82b4ceb2018-10-11 04:28:48 -07003036 if (!is_lb_static_mapping (m))
Matus Fabianab395ec2018-09-20 23:18:41 -07003037 return m->workers[0];
Matus Fabiana6110b62018-06-13 05:39:07 -07003038
Matus Fabianab395ec2018-09-20 23:18:41 -07003039 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3040 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
Matus Fabiana6110b62018-06-13 05:39:07 -07003041
Matus Fabianab395ec2018-09-20 23:18:41 -07003042 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3043 return m->workers[hash & (_vec_len (m->workers) - 1)];
3044 else
3045 return m->workers[hash % _vec_len (m->workers)];
3046 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003047 }
3048
3049 /* worker by outside port */
3050 next_worker_index = sm->first_worker_index;
3051 next_worker_index +=
3052 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3053
3054 return next_worker_index;
3055}
3056
Matus Fabianeea28d72017-01-13 04:15:54 -08003057static clib_error_t *
Dave Barach20c02cb2016-06-26 10:42:08 -04003058snat_config (vlib_main_t * vm, unformat_input_t * input)
3059{
Matus Fabianab395ec2018-09-20 23:18:41 -07003060 snat_main_t *sm = &snat_main;
3061 nat66_main_t *nm = &nat66_main;
Dave Barach20c02cb2016-06-26 10:42:08 -04003062 u32 translation_buckets = 1024;
Matus Fabianab395ec2018-09-20 23:18:41 -07003063 u32 translation_memory_size = 128 << 20;
Dave Barach20c02cb2016-06-26 10:42:08 -04003064 u32 user_buckets = 128;
Matus Fabianab395ec2018-09-20 23:18:41 -07003065 u32 user_memory_size = 64 << 20;
Dave Barach20c02cb2016-06-26 10:42:08 -04003066 u32 max_translations_per_user = 100;
3067 u32 outside_vrf_id = 0;
Juraj Sloboda9341e342018-04-13 12:00:46 +02003068 u32 outside_ip6_vrf_id = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07003069 u32 inside_vrf_id = 0;
3070 u32 static_mapping_buckets = 1024;
Matus Fabianab395ec2018-09-20 23:18:41 -07003071 u32 static_mapping_memory_size = 64 << 20;
Matus Fabian51e759f2017-12-07 23:22:51 -08003072 u32 nat64_bib_buckets = 1024;
3073 u32 nat64_bib_memory_size = 128 << 20;
3074 u32 nat64_st_buckets = 2048;
3075 u32 nat64_st_memory_size = 256 << 20;
Matus Fabiandb649882016-08-26 05:45:27 -07003076 u8 static_mapping_only = 0;
3077 u8 static_mapping_connection_tracking = 0;
Matus Fabian092b3cd2017-09-19 05:42:38 -07003078 snat_main_per_thread_data_t *tsm;
Matus Fabianab395ec2018-09-20 23:18:41 -07003079 dslite_main_t *dm = &dslite_main;
Dave Barach20c02cb2016-06-26 10:42:08 -04003080
Matus Fabian066f0342017-02-10 03:48:01 -08003081 sm->deterministic = 0;
Juraj Slobodacba69362017-12-19 02:09:32 +01003082 sm->out2in_dpo = 0;
Matus Fabiana6110b62018-06-13 05:39:07 -07003083 sm->endpoint_dependent = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08003084
Dave Barach20c02cb2016-06-26 10:42:08 -04003085 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3086 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003087 if (unformat
3088 (input, "translation hash buckets %d", &translation_buckets))
3089 ;
Dave Barach20c02cb2016-06-26 10:42:08 -04003090 else if (unformat (input, "translation hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003091 &translation_memory_size));
Dave Barach20c02cb2016-06-26 10:42:08 -04003092 else if (unformat (input, "user hash buckets %d", &user_buckets))
Matus Fabianab395ec2018-09-20 23:18:41 -07003093 ;
3094 else if (unformat (input, "user hash memory %d", &user_memory_size))
3095 ;
Dave Barach20c02cb2016-06-26 10:42:08 -04003096 else if (unformat (input, "max translations per user %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003097 &max_translations_per_user))
3098 ;
3099 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
3100 ;
3101 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
3102 ;
3103 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
3104 ;
Matus Fabiandb649882016-08-26 05:45:27 -07003105 else if (unformat (input, "static mapping only"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003106 {
3107 static_mapping_only = 1;
3108 if (unformat (input, "connection tracking"))
3109 static_mapping_connection_tracking = 1;
3110 }
Matus Fabian066f0342017-02-10 03:48:01 -08003111 else if (unformat (input, "deterministic"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003112 sm->deterministic = 1;
Matus Fabian51e759f2017-12-07 23:22:51 -08003113 else if (unformat (input, "nat64 bib hash buckets %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003114 &nat64_bib_buckets))
3115 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08003116 else if (unformat (input, "nat64 bib hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003117 &nat64_bib_memory_size))
3118 ;
3119 else
3120 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
3121 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08003122 else if (unformat (input, "nat64 st hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07003123 &nat64_st_memory_size))
3124 ;
Juraj Slobodacba69362017-12-19 02:09:32 +01003125 else if (unformat (input, "out2in dpo"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003126 sm->out2in_dpo = 1;
Juraj Slobodac5c6a332018-01-09 16:08:32 +01003127 else if (unformat (input, "dslite ce"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003128 dslite_set_ce (dm, 1);
Matus Fabiana6110b62018-06-13 05:39:07 -07003129 else if (unformat (input, "endpoint-dependent"))
Matus Fabianab395ec2018-09-20 23:18:41 -07003130 sm->endpoint_dependent = 1;
Matus Fabian066f0342017-02-10 03:48:01 -08003131 else
Matus Fabiandb649882016-08-26 05:45:27 -07003132 return clib_error_return (0, "unknown input '%U'",
Dave Barach20c02cb2016-06-26 10:42:08 -04003133 format_unformat_error, input);
3134 }
3135
Matus Fabian69ce30d2018-08-22 01:27:10 -07003136 if (sm->deterministic && sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07003137 return clib_error_return (0,
3138 "deterministic and endpoint-dependent modes are mutually exclusive");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003139
3140 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07003141 return clib_error_return (0,
3142 "static mapping only mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003143
3144 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07003145 return clib_error_return (0,
3146 "out2in dpo mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07003147
Dave Barach20c02cb2016-06-26 10:42:08 -04003148 /* for show commands, etc. */
3149 sm->translation_buckets = translation_buckets;
3150 sm->translation_memory_size = translation_memory_size;
Matus Fabian41fef502017-09-22 02:43:05 -07003151 /* do not exceed load factor 10 */
3152 sm->max_translations = 10 * translation_buckets;
Dave Barach20c02cb2016-06-26 10:42:08 -04003153 sm->user_buckets = user_buckets;
3154 sm->user_memory_size = user_memory_size;
3155 sm->max_translations_per_user = max_translations_per_user;
3156 sm->outside_vrf_id = outside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08003157 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07003158 outside_vrf_id,
3159 FIB_SOURCE_PLUGIN_HI);
Juraj Sloboda9341e342018-04-13 12:00:46 +02003160 nm->outside_vrf_id = outside_ip6_vrf_id;
3161 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
Matus Fabianab395ec2018-09-20 23:18:41 -07003162 outside_ip6_vrf_id,
3163 FIB_SOURCE_PLUGIN_HI);
Matus Fabiandb649882016-08-26 05:45:27 -07003164 sm->inside_vrf_id = inside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08003165 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07003166 inside_vrf_id,
3167 FIB_SOURCE_PLUGIN_HI);
Matus Fabiandb649882016-08-26 05:45:27 -07003168 sm->static_mapping_only = static_mapping_only;
3169 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
Dave Barach20c02cb2016-06-26 10:42:08 -04003170
Matus Fabianab395ec2018-09-20 23:18:41 -07003171 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
3172 nat64_st_memory_size);
Matus Fabian51e759f2017-12-07 23:22:51 -08003173
Matus Fabian066f0342017-02-10 03:48:01 -08003174 if (sm->deterministic)
Matus Fabiandb649882016-08-26 05:45:27 -07003175 {
Matus Fabian066f0342017-02-10 03:48:01 -08003176 sm->in2out_node_index = snat_det_in2out_node.index;
Matus Fabian93d84c92017-07-19 08:06:01 -07003177 sm->in2out_output_node_index = ~0;
Matus Fabian066f0342017-02-10 03:48:01 -08003178 sm->out2in_node_index = snat_det_out2in_node.index;
Juraj Sloboda7a1bde02017-04-03 08:43:58 +02003179 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
3180 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
Matus Fabiandb649882016-08-26 05:45:27 -07003181 }
Matus Fabian066f0342017-02-10 03:48:01 -08003182 else
3183 {
Matus Fabiana6110b62018-06-13 05:39:07 -07003184 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07003185 {
3186 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
3187 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
3188 sm->in2out_node_index = nat44_ed_in2out_node.index;
3189 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
3190 sm->out2in_node_index = nat44_ed_out2in_node.index;
3191 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
3192 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
3193 nat_affinity_init (vm);
3194 }
Matus Fabiana6110b62018-06-13 05:39:07 -07003195 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003196 {
3197 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
3198 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
3199 sm->in2out_node_index = snat_in2out_node.index;
3200 sm->in2out_output_node_index = snat_in2out_output_node.index;
3201 sm->out2in_node_index = snat_out2in_node.index;
3202 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
3203 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
3204 }
Matus Fabian066f0342017-02-10 03:48:01 -08003205 if (!static_mapping_only ||
Matus Fabianab395ec2018-09-20 23:18:41 -07003206 (static_mapping_only && static_mapping_connection_tracking))
3207 {
3208 /* *INDENT-OFF* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07003209 vec_foreach (tsm, sm->per_thread_data)
3210 {
Matus Fabiana6110b62018-06-13 05:39:07 -07003211 if (sm->endpoint_dependent)
3212 {
3213 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3214 translation_buckets,
3215 translation_memory_size);
3216 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3217 format_ed_session_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07003218
Matus Fabiana6110b62018-06-13 05:39:07 -07003219 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3220 translation_buckets,
3221 translation_memory_size);
3222 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3223 format_ed_session_kvp);
3224 }
3225 else
3226 {
3227 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3228 translation_buckets,
3229 translation_memory_size);
3230 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
3231 format_session_kvp);
3232
3233 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3234 translation_buckets,
3235 translation_memory_size);
3236 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
3237 format_session_kvp);
3238 }
Matus Fabian092b3cd2017-09-19 05:42:38 -07003239
3240 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3241 user_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003242 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
3243 format_user_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07003244 }
Matus Fabianab395ec2018-09-20 23:18:41 -07003245 /* *INDENT-ON* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07003246
Matus Fabianab395ec2018-09-20 23:18:41 -07003247 }
Juraj Sloboda557a71c2017-02-22 05:16:06 -08003248 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003249 {
3250 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
3251 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
3252 }
Matus Fabian066f0342017-02-10 03:48:01 -08003253 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07003254 "static_mapping_by_local", static_mapping_buckets,
3255 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003256 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07003257 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08003258
3259 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07003260 "static_mapping_by_external",
3261 static_mapping_buckets,
3262 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003263 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07003264 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08003265 }
3266
Dave Barach20c02cb2016-06-26 10:42:08 -04003267 return 0;
3268}
3269
Matus Fabian2ba92e32017-08-21 07:05:03 -07003270VLIB_CONFIG_FUNCTION (snat_config, "nat");
Dave Barach20c02cb2016-06-26 10:42:08 -04003271
Dave Barachcab65ec2017-01-11 13:01:14 -05003272static void
Matus Fabian4772e7a2018-04-04 00:38:02 -07003273nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07003274 uword opaque,
3275 u32 sw_if_index,
3276 ip4_address_t * address,
3277 u32 address_length,
3278 u32 if_address_index, u32 is_delete)
Matus Fabian4772e7a2018-04-04 00:38:02 -07003279{
3280 snat_main_t *sm = &snat_main;
3281 snat_static_map_resolve_t *rp;
3282 snat_static_mapping_t *m;
3283 snat_session_key_t m_key;
3284 clib_bihash_kv_8_8_t kv, value;
3285 int i, rv;
3286 ip4_address_t l_addr;
3287
3288 for (i = 0; i < vec_len (sm->to_resolve); i++)
3289 {
3290 rp = sm->to_resolve + i;
3291 if (rp->addr_only == 0)
Matus Fabianab395ec2018-09-20 23:18:41 -07003292 continue;
Matus Fabian4772e7a2018-04-04 00:38:02 -07003293 if (rp->sw_if_index == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07003294 goto match;
Matus Fabian4772e7a2018-04-04 00:38:02 -07003295 }
3296
3297 return;
3298
3299match:
3300 m_key.addr.as_u32 = address->as_u32;
3301 m_key.port = rp->addr_only ? 0 : rp->e_port;
3302 m_key.protocol = rp->addr_only ? 0 : rp->proto;
3303 m_key.fib_index = sm->outside_fib_index;
3304 kv.key = m_key.as_u64;
3305 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
3306 m = 0;
3307 else
3308 m = pool_elt_at_index (sm->static_mappings, value.value);
3309
3310 if (!is_delete)
3311 {
3312 /* Don't trip over lease renewal, static config */
3313 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07003314 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07003315 }
3316 else
3317 {
3318 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07003319 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07003320 }
3321
3322 /* Indetity mapping? */
3323 if (rp->l_addr.as_u32 == 0)
3324 l_addr.as_u32 = address[0].as_u32;
3325 else
3326 l_addr.as_u32 = rp->l_addr.as_u32;
3327 /* Add the static mapping */
3328 rv = snat_add_static_mapping (l_addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07003329 address[0],
3330 rp->l_port,
3331 rp->e_port,
3332 rp->vrf_id,
3333 rp->addr_only, ~0 /* sw_if_index */ ,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07003334 rp->proto, !is_delete, rp->twice_nat,
3335 rp->out2in_only, rp->tag, rp->identity_nat);
Matus Fabian4772e7a2018-04-04 00:38:02 -07003336 if (rv)
Matus Fabian229c1aa2018-05-28 04:09:52 -07003337 nat_log_notice ("snat_add_static_mapping returned %d", rv);
Matus Fabian4772e7a2018-04-04 00:38:02 -07003338}
3339
3340static void
Dave Barachcab65ec2017-01-11 13:01:14 -05003341snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07003342 uword opaque,
3343 u32 sw_if_index,
3344 ip4_address_t * address,
3345 u32 address_length,
3346 u32 if_address_index, u32 is_delete)
Dave Barachcab65ec2017-01-11 13:01:14 -05003347{
3348 snat_main_t *sm = &snat_main;
Dave Barach8b275372017-01-16 10:54:02 -05003349 snat_static_map_resolve_t *rp;
Matus Fabianab7a8052017-11-28 04:29:41 -08003350 ip4_address_t l_addr;
Dave Barachcab65ec2017-01-11 13:01:14 -05003351 int i, j;
Dave Barach8b275372017-01-16 10:54:02 -05003352 int rv;
Matus Fabianb932d262017-12-18 05:38:24 -08003353 u8 twice_nat = 0;
3354 snat_address_t *addresses = sm->addresses;
Dave Barachcab65ec2017-01-11 13:01:14 -05003355
Matus Fabianab395ec2018-09-20 23:18:41 -07003356 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05003357 {
3358 if (sw_if_index == sm->auto_add_sw_if_indices[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07003359 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08003360 }
Dave Barachcab65ec2017-01-11 13:01:14 -05003361
Matus Fabianab395ec2018-09-20 23:18:41 -07003362 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
Matus Fabianb932d262017-12-18 05:38:24 -08003363 {
3364 twice_nat = 1;
3365 addresses = sm->twice_nat_addresses;
3366 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07003367 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08003368 }
3369
3370 return;
3371
3372match:
3373 if (!is_delete)
3374 {
3375 /* Don't trip over lease renewal, static config */
Matus Fabianab395ec2018-09-20 23:18:41 -07003376 for (j = 0; j < vec_len (addresses); j++)
3377 if (addresses[j].addr.as_u32 == address->as_u32)
3378 return;
Matus Fabianb932d262017-12-18 05:38:24 -08003379
Matus Fabiana6110b62018-06-13 05:39:07 -07003380 (void) snat_add_address (sm, address, ~0, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08003381 /* Scan static map resolution vector */
3382 for (j = 0; j < vec_len (sm->to_resolve); j++)
Matus Fabianab395ec2018-09-20 23:18:41 -07003383 {
3384 rp = sm->to_resolve + j;
3385 if (rp->addr_only)
3386 continue;
3387 /* On this interface? */
3388 if (rp->sw_if_index == sw_if_index)
3389 {
3390 /* Indetity mapping? */
3391 if (rp->l_addr.as_u32 == 0)
3392 l_addr.as_u32 = address[0].as_u32;
3393 else
3394 l_addr.as_u32 = rp->l_addr.as_u32;
3395 /* Add the static mapping */
3396 rv = snat_add_static_mapping (l_addr,
3397 address[0],
3398 rp->l_port,
3399 rp->e_port,
3400 rp->vrf_id,
3401 rp->addr_only,
3402 ~0 /* sw_if_index */ ,
3403 rp->proto,
Matus Fabiane2f4e2f2018-10-07 21:28:23 -07003404 rp->is_add, rp->twice_nat,
3405 rp->out2in_only, rp->tag,
3406 rp->identity_nat);
Matus Fabianab395ec2018-09-20 23:18:41 -07003407 if (rv)
3408 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3409 }
3410 }
Matus Fabianb932d262017-12-18 05:38:24 -08003411 return;
3412 }
3413 else
3414 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003415 (void) snat_del_address (sm, address[0], 1, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08003416 return;
Dave Barachcab65ec2017-01-11 13:01:14 -05003417 }
3418}
3419
3420
Matus Fabianab395ec2018-09-20 23:18:41 -07003421int
3422snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
3423 u8 twice_nat)
Dave Barachcab65ec2017-01-11 13:01:14 -05003424{
Matus Fabianab395ec2018-09-20 23:18:41 -07003425 ip4_main_t *ip4_main = sm->ip4_main;
3426 ip4_address_t *first_int_addr;
Matus Fabian36532bd2017-01-23 23:42:28 -08003427 snat_static_map_resolve_t *rp;
3428 u32 *indices_to_delete = 0;
3429 int i, j;
Matus Fabianb932d262017-12-18 05:38:24 -08003430 u32 *auto_add_sw_if_indices =
Matus Fabianab395ec2018-09-20 23:18:41 -07003431 twice_nat ? sm->
3432 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
Dave Barachcab65ec2017-01-11 13:01:14 -05003433
Matus Fabianab395ec2018-09-20 23:18:41 -07003434 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
3435 );
Dave Barachcab65ec2017-01-11 13:01:14 -05003436
Matus Fabianab395ec2018-09-20 23:18:41 -07003437 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05003438 {
Matus Fabianb932d262017-12-18 05:38:24 -08003439 if (auto_add_sw_if_indices[i] == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07003440 {
3441 if (is_del)
3442 {
3443 /* if have address remove it */
3444 if (first_int_addr)
3445 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3446 else
3447 {
3448 for (j = 0; j < vec_len (sm->to_resolve); j++)
3449 {
3450 rp = sm->to_resolve + j;
3451 if (rp->sw_if_index == sw_if_index)
3452 vec_add1 (indices_to_delete, j);
3453 }
3454 if (vec_len (indices_to_delete))
3455 {
3456 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3457 vec_del1 (sm->to_resolve, j);
3458 vec_free (indices_to_delete);
3459 }
3460 }
3461 if (twice_nat)
3462 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3463 else
3464 vec_del1 (sm->auto_add_sw_if_indices, i);
3465 }
3466 else
3467 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian8bf68e82017-01-12 04:24:35 -08003468
Matus Fabianab395ec2018-09-20 23:18:41 -07003469 return 0;
3470 }
Dave Barachcab65ec2017-01-11 13:01:14 -05003471 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07003472
Matus Fabian8bf68e82017-01-12 04:24:35 -08003473 if (is_del)
3474 return VNET_API_ERROR_NO_SUCH_ENTRY;
3475
Dave Barachcab65ec2017-01-11 13:01:14 -05003476 /* add to the auto-address list */
Matus Fabianb932d262017-12-18 05:38:24 -08003477 if (twice_nat)
Matus Fabianab395ec2018-09-20 23:18:41 -07003478 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
Matus Fabianb932d262017-12-18 05:38:24 -08003479 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003480 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
Dave Barachcab65ec2017-01-11 13:01:14 -05003481
3482 /* If the address is already bound - or static - add it now */
3483 if (first_int_addr)
Matus Fabianab395ec2018-09-20 23:18:41 -07003484 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
Dave Barachcab65ec2017-01-11 13:01:14 -05003485
3486 return 0;
3487}
3488
Matus Fabian5ba86f72017-10-26 03:37:38 -07003489int
Matus Fabianab395ec2018-09-20 23:18:41 -07003490nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3491 snat_protocol_t proto, u32 vrf_id, int is_in)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003492{
3493 snat_main_per_thread_data_t *tsm;
3494 clib_bihash_kv_8_8_t kv, value;
3495 ip4_header_t ip;
3496 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3497 snat_session_key_t key;
3498 snat_session_t *s;
3499 clib_bihash_8_8_t *t;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003500
Matus Fabiana6110b62018-06-13 05:39:07 -07003501 if (sm->endpoint_dependent)
3502 return VNET_API_ERROR_UNSUPPORTED;
3503
Matus Fabian5ba86f72017-10-26 03:37:38 -07003504 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
Matus Fabian4888b502018-03-27 01:07:25 -07003505 if (sm->num_workers > 1)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003506 tsm =
3507 vec_elt_at_index (sm->per_thread_data,
3508 sm->worker_in2out_cb (&ip, fib_index));
3509 else
3510 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3511
3512 key.addr.as_u32 = addr->as_u32;
3513 key.port = clib_host_to_net_u16 (port);
3514 key.protocol = proto;
3515 key.fib_index = fib_index;
3516 kv.key = key.as_u64;
3517 t = is_in ? &tsm->in2out : &tsm->out2in;
3518 if (!clib_bihash_search_8_8 (t, &kv, &value))
3519 {
Matus Fabian70a26ac2018-05-14 06:20:28 -07003520 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabianab395ec2018-09-20 23:18:41 -07003521 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003522
Matus Fabian5ba86f72017-10-26 03:37:38 -07003523 s = pool_elt_at_index (tsm->sessions, value.value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003524 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3525 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian5ba86f72017-10-26 03:37:38 -07003526 return 0;
3527 }
3528
3529 return VNET_API_ERROR_NO_SUCH_ENTRY;
3530}
3531
Matus Fabian70a26ac2018-05-14 06:20:28 -07003532int
Matus Fabianab395ec2018-09-20 23:18:41 -07003533nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3534 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3535 u32 vrf_id, int is_in)
Matus Fabian70a26ac2018-05-14 06:20:28 -07003536{
3537 ip4_header_t ip;
3538 clib_bihash_16_8_t *t;
3539 nat_ed_ses_key_t key;
3540 clib_bihash_kv_16_8_t kv, value;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003541 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3542 snat_session_t *s;
Matus Fabiana6110b62018-06-13 05:39:07 -07003543 snat_main_per_thread_data_t *tsm;
3544
3545 if (!sm->endpoint_dependent)
3546 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003547
3548 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3549 if (sm->num_workers > 1)
Matus Fabiana6110b62018-06-13 05:39:07 -07003550 tsm =
3551 vec_elt_at_index (sm->per_thread_data,
3552 sm->worker_in2out_cb (&ip, fib_index));
Matus Fabian70a26ac2018-05-14 06:20:28 -07003553 else
Matus Fabiana6110b62018-06-13 05:39:07 -07003554 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabian70a26ac2018-05-14 06:20:28 -07003555
Matus Fabiana6110b62018-06-13 05:39:07 -07003556 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003557 key.l_addr.as_u32 = addr->as_u32;
3558 key.r_addr.as_u32 = eh_addr->as_u32;
3559 key.l_port = clib_host_to_net_u16 (port);
3560 key.r_port = clib_host_to_net_u16 (eh_port);
3561 key.proto = proto;
Matus Fabianab395ec2018-09-20 23:18:41 -07003562 key.fib_index = fib_index;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003563 kv.key[0] = key.as_u64[0];
3564 kv.key[1] = key.as_u64[1];
3565 if (clib_bihash_search_16_8 (t, &kv, &value))
3566 return VNET_API_ERROR_NO_SUCH_ENTRY;
3567
Matus Fabiana6110b62018-06-13 05:39:07 -07003568 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabian70a26ac2018-05-14 06:20:28 -07003569 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabiana6110b62018-06-13 05:39:07 -07003570 s = pool_elt_at_index (tsm->sessions, value.value);
3571 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3572 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian70a26ac2018-05-14 06:20:28 -07003573 return 0;
3574}
3575
Matus Fabian82119542018-01-25 01:13:22 -08003576void
3577nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003578{
3579 snat_main_t *sm = &snat_main;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003580
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003581 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
Matus Fabian82119542018-01-25 01:13:22 -08003582 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3583 sm->psid = psid;
3584 sm->psid_offset = psid_offset;
3585 sm->psid_length = psid_length;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003586}
3587
Matus Fabian82119542018-01-25 01:13:22 -08003588void
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003589nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
3590{
3591 snat_main_t *sm = &snat_main;
3592
3593 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
3594 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
3595 sm->start_port = start_port;
3596 sm->end_port = end_port;
3597}
3598
3599void
Matus Fabian82119542018-01-25 01:13:22 -08003600nat_set_alloc_addr_and_port_default (void)
Matus Fabian27697102017-11-09 01:43:47 -08003601{
3602 snat_main_t *sm = &snat_main;
Matus Fabian27697102017-11-09 01:43:47 -08003603
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003604 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Matus Fabian82119542018-01-25 01:13:22 -08003605 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian066f0342017-02-10 03:48:01 -08003606}
3607
Matus Fabianab395ec2018-09-20 23:18:41 -07003608/*
3609 * fd.io coding-style-patch-verification: ON
3610 *
3611 * Local Variables:
3612 * eval: (c-set-style "gnu")
3613 * End:
3614 */