blob: 0818332eeb30cbd91b5e35784659c8ff5004a9b9 [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 Fabiane1ae29a2017-01-27 00:47:58 -080032#include <vnet/fib/fib_table.h>
33#include <vnet/fib/ip4_fib.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040034
Damjan Marion3b46cba2017-01-23 21:13:45 +010035#include <vpp/app/version.h>
Dave Barach20c02cb2016-06-26 10:42:08 -040036
37snat_main_t snat_main;
38
Matus Fabianab395ec2018-09-20 23:18:41 -070039/* *INDENT-OFF* */
Dave Barach20c02cb2016-06-26 10:42:08 -040040
Dave Barach20c02cb2016-06-26 10:42:08 -040041/* Hook up input features */
Damjan Marion8b3191e2016-11-09 19:54:20 +010042VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
43 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070044 .node_name = "nat44-in2out",
Matus Fabian16f05462018-02-08 05:28:28 -080045 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Dave Barach20c02cb2016-06-26 10:42:08 -040046};
Damjan Marion8b3191e2016-11-09 19:54:20 +010047VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
48 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070049 .node_name = "nat44-out2in",
Matus Fabiana6110b62018-06-13 05:39:07 -070050 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
Dave Barach525c9d02018-05-26 10:48:55 -040051 "ip4-dhcp-client-detect"),
Dave Barach20c02cb2016-06-26 10:42:08 -040052};
Matus Fabian36ea2d62017-10-24 04:13:49 -070053VNET_FEATURE_INIT (ip4_nat_classify, static) = {
54 .arc_name = "ip4-unicast",
55 .node_name = "nat44-classify",
Matus Fabian16f05462018-02-08 05:28:28 -080056 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -070057};
Matus Fabian066f0342017-02-10 03:48:01 -080058VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
59 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070060 .node_name = "nat44-det-in2out",
Matus Fabian16f05462018-02-08 05:28:28 -080061 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian066f0342017-02-10 03:48:01 -080062};
63VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
64 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070065 .node_name = "nat44-det-out2in",
Matus Fabiana6110b62018-06-13 05:39:07 -070066 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
67 "ip4-dhcp-client-detect"),
Matus Fabian066f0342017-02-10 03:48:01 -080068};
Matus Fabian36ea2d62017-10-24 04:13:49 -070069VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
70 .arc_name = "ip4-unicast",
71 .node_name = "nat44-det-classify",
Matus Fabian16f05462018-02-08 05:28:28 -080072 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -070073};
Matus Fabiana6110b62018-06-13 05:39:07 -070074VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
75 .arc_name = "ip4-unicast",
76 .node_name = "nat44-ed-in2out",
77 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
78};
79VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
80 .arc_name = "ip4-unicast",
81 .node_name = "nat44-ed-out2in",
82 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
83 "ip4-dhcp-client-detect"),
84};
85VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
86 .arc_name = "ip4-unicast",
87 .node_name = "nat44-ed-classify",
88 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
89};
Matus Fabian475f0552016-10-19 06:17:52 -070090VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
91 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070092 .node_name = "nat44-in2out-worker-handoff",
Matus Fabian16f05462018-02-08 05:28:28 -080093 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian475f0552016-10-19 06:17:52 -070094};
95VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
96 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -070097 .node_name = "nat44-out2in-worker-handoff",
Matus Fabiana6110b62018-06-13 05:39:07 -070098 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
99 "ip4-dhcp-client-detect"),
Matus Fabian475f0552016-10-19 06:17:52 -0700100};
Matus Fabian36ea2d62017-10-24 04:13:49 -0700101VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
102 .arc_name = "ip4-unicast",
103 .node_name = "nat44-handoff-classify",
Matus Fabian16f05462018-02-08 05:28:28 -0800104 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian36ea2d62017-10-24 04:13:49 -0700105};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100106VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
107 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700108 .node_name = "nat44-in2out-fast",
Matus Fabian16f05462018-02-08 05:28:28 -0800109 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabiandb649882016-08-26 05:45:27 -0700110};
Damjan Marion8b3191e2016-11-09 19:54:20 +0100111VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
112 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700113 .node_name = "nat44-out2in-fast",
Matus Fabiana6110b62018-06-13 05:39:07 -0700114 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
115 "ip4-dhcp-client-detect"),
Matus Fabiandb649882016-08-26 05:45:27 -0700116};
Matus Fabian161c59c2017-07-21 03:46:03 -0700117VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
118 .arc_name = "ip4-unicast",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700119 .node_name = "nat44-hairpin-dst",
Matus Fabian16f05462018-02-08 05:28:28 -0800120 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700121};
Matus Fabiana6110b62018-06-13 05:39:07 -0700122VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
123 .arc_name = "ip4-unicast",
124 .node_name = "nat44-ed-hairpin-dst",
125 .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
126};
Matus Fabiandb649882016-08-26 05:45:27 -0700127
Matus Fabian93d84c92017-07-19 08:06:01 -0700128/* Hook up output features */
129VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
130 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700131 .node_name = "nat44-in2out-output",
Matus Fabian16f05462018-02-08 05:28:28 -0800132 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700133};
Matus Fabian93d84c92017-07-19 08:06:01 -0700134VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
135 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700136 .node_name = "nat44-in2out-output-worker-handoff",
Matus Fabian16f05462018-02-08 05:28:28 -0800137 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian93d84c92017-07-19 08:06:01 -0700138};
Matus Fabian161c59c2017-07-21 03:46:03 -0700139VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
140 .arc_name = "ip4-output",
Matus Fabian2ba92e32017-08-21 07:05:03 -0700141 .node_name = "nat44-hairpin-src",
Matus Fabian16f05462018-02-08 05:28:28 -0800142 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
Matus Fabian161c59c2017-07-21 03:46:03 -0700143};
Matus Fabiana6110b62018-06-13 05:39:07 -0700144VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
145 .arc_name = "ip4-output",
146 .node_name = "nat44-ed-in2out-output",
147 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
148};
149VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
150 .arc_name = "ip4-output",
151 .node_name = "nat44-ed-hairpin-src",
152 .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
153};
Matus Fabian93d84c92017-07-19 08:06:01 -0700154
Matus Fabian87da4762017-10-04 08:03:56 -0700155/* Hook up ip4-local features */
156VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
157{
158 .arc_name = "ip4-local",
159 .node_name = "nat44-hairpinning",
160 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
161};
Matus Fabiana6110b62018-06-13 05:39:07 -0700162VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
163{
164 .arc_name = "ip4-local",
165 .node_name = "nat44-ed-hairpinning",
166 .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
167};
Matus Fabian87da4762017-10-04 08:03:56 -0700168
Matus Fabian93d84c92017-07-19 08:06:01 -0700169
Damjan Marion3b46cba2017-01-23 21:13:45 +0100170VLIB_PLUGIN_REGISTER () = {
171 .version = VPP_BUILD_VER,
Damjan Marion1bfb0dd2017-03-22 11:08:39 +0100172 .description = "Network Address Translation",
Damjan Marion3b46cba2017-01-23 21:13:45 +0100173};
174/* *INDENT-ON* */
Dave Barach20c02cb2016-06-26 10:42:08 -0400175
Matus Fabianb932d262017-12-18 05:38:24 -0800176void
177nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
178{
179 snat_session_key_t key;
180 clib_bihash_kv_8_8_t kv;
181 nat_ed_ses_key_t ed_key;
182 clib_bihash_kv_16_8_t ed_kv;
Matus Fabianb932d262017-12-18 05:38:24 -0800183 snat_main_per_thread_data_t *tsm =
184 vec_elt_at_index (sm->per_thread_data, thread_index);
185
Matus Fabian36ed73a2018-04-18 01:39:17 -0700186 if (is_fwd_bypass_session (s))
187 {
188 ed_key.l_addr = s->in2out.addr;
189 ed_key.r_addr = s->ext_host_addr;
190 ed_key.l_port = s->in2out.port;
191 ed_key.r_port = s->ext_host_port;
192 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
193 ed_key.fib_index = 0;
194 ed_kv.key[0] = ed_key.as_u64[0];
195 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700196 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700197 nat_log_warn ("in2out_ed key del failed");
Matus Fabian36ed73a2018-04-18 01:39:17 -0700198 return;
199 }
200
Matus Fabiana6110b62018-06-13 05:39:07 -0700201 /* session lookup tables */
Matus Fabianb932d262017-12-18 05:38:24 -0800202 if (is_ed_session (s))
203 {
Matus Fabianea5b5be2018-09-03 05:02:23 -0700204 if (is_affinity_sessions (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700205 nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
206 s->in2out.protocol, s->out2in.port);
Matus Fabianb932d262017-12-18 05:38:24 -0800207 ed_key.l_addr = s->out2in.addr;
208 ed_key.r_addr = s->ext_host_addr;
209 ed_key.fib_index = s->out2in.fib_index;
210 if (snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700211 {
212 ed_key.proto = s->in2out.port;
213 ed_key.r_port = 0;
214 ed_key.l_port = 0;
215 }
Matus Fabianb932d262017-12-18 05:38:24 -0800216 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700217 {
218 ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
219 ed_key.l_port = s->out2in.port;
220 ed_key.r_port = s->ext_host_port;
221 }
Matus Fabianb932d262017-12-18 05:38:24 -0800222 ed_kv.key[0] = ed_key.as_u64[0];
223 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700224 if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700225 nat_log_warn ("out2in_ed key del failed");
Matus Fabianb932d262017-12-18 05:38:24 -0800226 ed_key.l_addr = s->in2out.addr;
227 ed_key.fib_index = s->in2out.fib_index;
228 if (!snat_is_unk_proto_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700229 ed_key.l_port = s->in2out.port;
Matus Fabianb932d262017-12-18 05:38:24 -0800230 if (is_twice_nat_session (s))
Matus Fabianab395ec2018-09-20 23:18:41 -0700231 {
232 ed_key.r_addr = s->ext_host_nat_addr;
233 ed_key.r_port = s->ext_host_nat_port;
234 }
Matus Fabianb932d262017-12-18 05:38:24 -0800235 ed_kv.key[0] = ed_key.as_u64[0];
236 ed_kv.key[1] = ed_key.as_u64[1];
Matus Fabiana6110b62018-06-13 05:39:07 -0700237 if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700238 nat_log_warn ("in2out_ed key del failed");
Matus Fabianb932d262017-12-18 05:38:24 -0800239 }
Matus Fabiana6110b62018-06-13 05:39:07 -0700240 else
241 {
242 kv.key = s->in2out.as_u64;
243 if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700244 nat_log_warn ("in2out key del failed");
Matus Fabiana6110b62018-06-13 05:39:07 -0700245 kv.key = s->out2in.as_u64;
246 if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
Matus Fabianab395ec2018-09-20 23:18:41 -0700247 nat_log_warn ("out2in key del failed");
Matus Fabiana6110b62018-06-13 05:39:07 -0700248 }
Matus Fabianb932d262017-12-18 05:38:24 -0800249
250 if (snat_is_unk_proto_session (s))
251 return;
252
253 /* log NAT event */
Matus Fabianab395ec2018-09-20 23:18:41 -0700254 snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
255 s->out2in.addr.as_u32,
256 s->in2out.protocol,
257 s->in2out.port,
258 s->out2in.port, s->in2out.fib_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800259
260 /* Twice NAT address and port for external host */
Matus Fabian70a26ac2018-05-14 06:20:28 -0700261 if (is_twice_nat_session (s))
Matus Fabianb932d262017-12-18 05:38:24 -0800262 {
shubing guo762a4932018-08-13 17:16:46 +0800263 key.protocol = s->in2out.protocol;
264 key.port = s->ext_host_nat_port;
265 key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
266 snat_free_outside_address_and_port (sm->twice_nat_addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -0700267 thread_index, &key);
Matus Fabianb932d262017-12-18 05:38:24 -0800268 }
269
Matus Fabianb932d262017-12-18 05:38:24 -0800270 if (snat_is_session_static (s))
271 return;
272
Matus Fabianab395ec2018-09-20 23:18:41 -0700273 snat_free_outside_address_and_port (sm->addresses, thread_index,
274 &s->out2in);
Matus Fabianb932d262017-12-18 05:38:24 -0800275}
276
277snat_user_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700278nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
279 u32 thread_index)
Matus Fabianb932d262017-12-18 05:38:24 -0800280{
281 snat_user_t *u = 0;
282 snat_user_key_t user_key;
283 clib_bihash_kv_8_8_t kv, value;
284 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabianab395ec2018-09-20 23:18:41 -0700285 dlist_elt_t *per_user_list_head_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800286
287 user_key.addr.as_u32 = addr->as_u32;
288 user_key.fib_index = fib_index;
289 kv.key = user_key.as_u64;
290
291 /* Ever heard of the "user" = src ip4 address before? */
292 if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
293 {
294 /* no, make a new one */
295 pool_get (tsm->users, u);
296 memset (u, 0, sizeof (*u));
297 u->addr.as_u32 = addr->as_u32;
298 u->fib_index = fib_index;
299
300 pool_get (tsm->list_pool, per_user_list_head_elt);
301
302 u->sessions_per_user_list_head_index = per_user_list_head_elt -
Matus Fabianab395ec2018-09-20 23:18:41 -0700303 tsm->list_pool;
Matus Fabianb932d262017-12-18 05:38:24 -0800304
305 clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
306
307 kv.value = u - tsm->users;
308
309 /* add user */
310 if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
Matus Fabianab395ec2018-09-20 23:18:41 -0700311 nat_log_warn ("user_hash keay add failed");
Matus Fabianb932d262017-12-18 05:38:24 -0800312 }
313 else
314 {
315 u = pool_elt_at_index (tsm->users, value.value);
316 }
317
318 return u;
319}
320
321snat_session_t *
Matus Fabianab395ec2018-09-20 23:18:41 -0700322nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
323 u32 thread_index)
Matus Fabianb932d262017-12-18 05:38:24 -0800324{
325 snat_session_t *s;
326 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
327 u32 oldest_per_user_translation_list_index, session_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700328 dlist_elt_t *oldest_per_user_translation_list_elt;
329 dlist_elt_t *per_user_translation_list_elt;
Matus Fabianb932d262017-12-18 05:38:24 -0800330
331 /* Over quota? Recycle the least recently used translation */
332 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
333 {
334 oldest_per_user_translation_list_index =
Matus Fabianab395ec2018-09-20 23:18:41 -0700335 clib_dlist_remove_head (tsm->list_pool,
336 u->sessions_per_user_list_head_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800337
338 ASSERT (oldest_per_user_translation_list_index != ~0);
339
340 /* Add it back to the end of the LRU list */
341 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700342 u->sessions_per_user_list_head_index,
343 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800344 /* Get the list element */
345 oldest_per_user_translation_list_elt =
Matus Fabianab395ec2018-09-20 23:18:41 -0700346 pool_elt_at_index (tsm->list_pool,
347 oldest_per_user_translation_list_index);
Matus Fabianb932d262017-12-18 05:38:24 -0800348
349 /* Get the session index from the list element */
350 session_index = oldest_per_user_translation_list_elt->value;
351
352 /* Get the session */
353 s = pool_elt_at_index (tsm->sessions, session_index);
354 nat_free_session_data (sm, s, thread_index);
Matus Fabianab395ec2018-09-20 23:18:41 -0700355 if (snat_is_session_static (s))
356 u->nstaticsessions--;
Matus Fabian132dc492018-05-09 04:51:03 -0700357 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700358 u->nsessions--;
Matus Fabianb932d262017-12-18 05:38:24 -0800359 s->flags = 0;
360 s->total_bytes = 0;
361 s->total_pkts = 0;
Matus Fabianebdf1902018-05-04 03:57:42 -0700362 s->state = 0;
363 s->ext_host_addr.as_u32 = 0;
364 s->ext_host_port = 0;
365 s->ext_host_nat_addr.as_u32 = 0;
366 s->ext_host_nat_port = 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800367 }
368 else
369 {
370 pool_get (tsm->sessions, s);
371 memset (s, 0, sizeof (*s));
Matus Fabianb932d262017-12-18 05:38:24 -0800372
373 /* Create list elts */
374 pool_get (tsm->list_pool, per_user_translation_list_elt);
375 clib_dlist_init (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700376 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianb932d262017-12-18 05:38:24 -0800377
378 per_user_translation_list_elt->value = s - tsm->sessions;
379 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
380 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
381
382 clib_dlist_addtail (tsm->list_pool,
Matus Fabianab395ec2018-09-20 23:18:41 -0700383 s->per_user_list_head_index,
384 per_user_translation_list_elt - tsm->list_pool);
Matus Fabianb932d262017-12-18 05:38:24 -0800385 }
386
387 return s;
388}
389
Matus Fabian878c6462018-08-23 00:33:35 -0700390snat_session_t *
Matus Fabian8fdc0152018-09-24 04:41:28 -0700391nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
392 f64 now)
Matus Fabian878c6462018-08-23 00:33:35 -0700393{
394 snat_session_t *s;
395 snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
Matus Fabian8fdc0152018-09-24 04:41:28 -0700396 dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
397 u32 oldest_index;
398 u64 sess_timeout_time;
Matus Fabian878c6462018-08-23 00:33:35 -0700399
400 if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
401 {
Matus Fabian8fdc0152018-09-24 04:41:28 -0700402 oldest_index =
403 clib_dlist_remove_head (tsm->list_pool,
404 u->sessions_per_user_list_head_index);
405 oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
406 s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
407 sess_timeout_time =
408 s->last_heard + (f64) nat44_session_get_timeout (sm, s);
409 if (now >= sess_timeout_time)
410 {
411 clib_dlist_addtail (tsm->list_pool,
412 u->sessions_per_user_list_head_index,
413 oldest_index);
414 nat_free_session_data (sm, s, thread_index);
415 if (snat_is_session_static (s))
416 u->nstaticsessions--;
417 else
418 u->nsessions--;
419 s->flags = 0;
420 s->total_bytes = 0;
421 s->total_pkts = 0;
422 s->state = 0;
423 s->ext_host_addr.as_u32 = 0;
424 s->ext_host_port = 0;
425 s->ext_host_nat_addr.as_u32 = 0;
426 s->ext_host_nat_port = 0;
427 }
428 else
429 {
430 clib_dlist_addhead (tsm->list_pool,
431 u->sessions_per_user_list_head_index,
432 oldest_index);
433 nat_log_warn ("max translations per user %U", format_ip4_address,
434 &u->addr);
435 snat_ipfix_logging_max_entries_per_user
436 (sm->max_translations_per_user, u->addr.as_u32);
437 return 0;
438 }
Matus Fabian878c6462018-08-23 00:33:35 -0700439 }
Matus Fabian8fdc0152018-09-24 04:41:28 -0700440 else
441 {
442 pool_get (tsm->sessions, s);
443 memset (s, 0, sizeof (*s));
Matus Fabian878c6462018-08-23 00:33:35 -0700444
Matus Fabian8fdc0152018-09-24 04:41:28 -0700445 /* Create list elts */
446 pool_get (tsm->list_pool, per_user_translation_list_elt);
447 clib_dlist_init (tsm->list_pool,
448 per_user_translation_list_elt - tsm->list_pool);
Matus Fabian878c6462018-08-23 00:33:35 -0700449
Matus Fabian8fdc0152018-09-24 04:41:28 -0700450 per_user_translation_list_elt->value = s - tsm->sessions;
451 s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
452 s->per_user_list_head_index = u->sessions_per_user_list_head_index;
Matus Fabian878c6462018-08-23 00:33:35 -0700453
Matus Fabian8fdc0152018-09-24 04:41:28 -0700454 clib_dlist_addtail (tsm->list_pool,
455 s->per_user_list_head_index,
456 per_user_translation_list_elt - tsm->list_pool);
457 }
Matus Fabian878c6462018-08-23 00:33:35 -0700458 return s;
459}
460
Matus Fabian066f0342017-02-10 03:48:01 -0800461void
462snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
Matus Fabianab395ec2018-09-20 23:18:41 -0700463 int is_add)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800464{
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800465 fib_prefix_t prefix = {
Matus Fabian066f0342017-02-10 03:48:01 -0800466 .fp_len = p_len,
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800467 .fp_proto = FIB_PROTOCOL_IP4,
468 .fp_addr = {
Matus Fabianab395ec2018-09-20 23:18:41 -0700469 .ip4.as_u32 = addr->as_u32,
470 },
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800471 };
Matus Fabianab395ec2018-09-20 23:18:41 -0700472 u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800473
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800474 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700475 fib_table_entry_update_one_path (fib_index,
476 &prefix,
477 FIB_SOURCE_PLUGIN_LOW,
478 (FIB_ENTRY_FLAG_CONNECTED |
479 FIB_ENTRY_FLAG_LOCAL |
480 FIB_ENTRY_FLAG_EXCLUSIVE),
481 DPO_PROTO_IP4,
482 NULL,
483 sw_if_index,
484 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800485 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700486 fib_table_entry_delete (fib_index, &prefix, FIB_SOURCE_PLUGIN_LOW);
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800487}
488
Matus Fabianab395ec2018-09-20 23:18:41 -0700489int
490snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
491 u8 twice_nat)
Dave Barach20c02cb2016-06-26 10:42:08 -0400492{
Matus Fabianab395ec2018-09-20 23:18:41 -0700493 snat_address_t *ap;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800494 snat_interface_t *i;
Matus Fabian624b8d92017-09-12 04:15:30 -0700495 vlib_thread_main_t *tm = vlib_get_thread_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -0400496
Matus Fabiana6110b62018-06-13 05:39:07 -0700497 if (twice_nat && !sm->endpoint_dependent)
498 return VNET_API_ERROR_FEATURE_DISABLED;
499
Matus Fabian860dacc2016-10-25 04:19:26 -0700500 /* Check if address already exists */
Matus Fabianab395ec2018-09-20 23:18:41 -0700501 /* *INDENT-OFF* */
Matus Fabianb932d262017-12-18 05:38:24 -0800502 vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
Matus Fabian860dacc2016-10-25 04:19:26 -0700503 {
504 if (ap->addr.as_u32 == addr->as_u32)
Matus Fabiana6110b62018-06-13 05:39:07 -0700505 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian860dacc2016-10-25 04:19:26 -0700506 }
Matus Fabianab395ec2018-09-20 23:18:41 -0700507 /* *INDENT-ON* */
Matus Fabian860dacc2016-10-25 04:19:26 -0700508
Matus Fabianb932d262017-12-18 05:38:24 -0800509 if (twice_nat)
510 vec_add2 (sm->twice_nat_addresses, ap, 1);
511 else
512 vec_add2 (sm->addresses, ap, 1);
513
Dave Barach20c02cb2016-06-26 10:42:08 -0400514 ap->addr = *addr;
Matus Fabianf8d84902017-07-23 23:41:03 -0700515 if (vrf_id != ~0)
516 ap->fib_index =
Neale Ranns15002542017-09-10 04:39:11 -0700517 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
Matus Fabianab395ec2018-09-20 23:18:41 -0700518 FIB_SOURCE_PLUGIN_LOW);
Matus Fabianf8d84902017-07-23 23:41:03 -0700519 else
520 ap->fib_index = ~0;
Matus Fabian09d96f42017-02-02 01:43:00 -0800521#define _(N, i, n, s) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700522 clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
523 ap->busy_##n##_ports = 0; \
dongjuandf865202018-09-11 11:20:30 +0000524 ap->busy_##n##_ports_per_thread = 0;\
Matus Fabian624b8d92017-09-12 04:15:30 -0700525 vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
Matus Fabian09d96f42017-02-02 01:43:00 -0800526 foreach_snat_protocol
527#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700528 if (twice_nat)
Matus Fabiana6110b62018-06-13 05:39:07 -0700529 return 0;
Matus Fabianb932d262017-12-18 05:38:24 -0800530
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800531 /* Add external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -0700532 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800533 pool_foreach (i, sm->interfaces,
534 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100535 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800536 continue;
537
Matus Fabian066f0342017-02-10 03:48:01 -0800538 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
Matus Fabiandccbee32017-01-31 22:20:30 -0800539 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800540 }));
Matus Fabian93d84c92017-07-19 08:06:01 -0700541 pool_foreach (i, sm->output_feature_interfaces,
542 ({
Juraj Slobodacba69362017-12-19 02:09:32 +0100543 if (nat_interface_is_inside(i) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -0700544 continue;
545
546 snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
547 break;
548 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700549 /* *INDENT-ON* */
Matus Fabiana6110b62018-06-13 05:39:07 -0700550
551 return 0;
Dave Barach20c02cb2016-06-26 10:42:08 -0400552}
553
Matus Fabianab395ec2018-09-20 23:18:41 -0700554static int
555is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
Matus Fabian724b8152016-10-04 03:23:43 -0700556{
557 snat_static_mapping_t *m;
Matus Fabianab395ec2018-09-20 23:18:41 -0700558 /* *INDENT-OFF* */
Matus Fabian724b8152016-10-04 03:23:43 -0700559 pool_foreach (m, sm->static_mappings,
560 ({
561 if (m->external_addr.as_u32 == addr.as_u32)
562 return 1;
563 }));
Matus Fabianab395ec2018-09-20 23:18:41 -0700564 /* *INDENT-ON* */
Matus Fabian724b8152016-10-04 03:23:43 -0700565
566 return 0;
567}
568
Matus Fabianab395ec2018-09-20 23:18:41 -0700569void
570increment_v4_address (ip4_address_t * a)
Dave Barach20c02cb2016-06-26 10:42:08 -0400571{
572 u32 v;
Matus Fabian2ba92e32017-08-21 07:05:03 -0700573
Matus Fabianab395ec2018-09-20 23:18:41 -0700574 v = clib_net_to_host_u32 (a->as_u32) + 1;
575 a->as_u32 = clib_host_to_net_u32 (v);
Dave Barach20c02cb2016-06-26 10:42:08 -0400576}
577
Matus Fabian2ba92e32017-08-21 07:05:03 -0700578static void
579snat_add_static_mapping_when_resolved (snat_main_t * sm,
Matus Fabianab395ec2018-09-20 23:18:41 -0700580 ip4_address_t l_addr,
581 u16 l_port,
582 u32 sw_if_index,
583 u16 e_port,
584 u32 vrf_id,
585 snat_protocol_t proto,
586 int addr_only, int is_add, u8 * tag)
Dave Barach8b275372017-01-16 10:54:02 -0500587{
588 snat_static_map_resolve_t *rp;
589
590 vec_add2 (sm->to_resolve, rp, 1);
591 rp->l_addr.as_u32 = l_addr.as_u32;
592 rp->l_port = l_port;
593 rp->sw_if_index = sw_if_index;
594 rp->e_port = e_port;
595 rp->vrf_id = vrf_id;
Matus Fabian09d96f42017-02-02 01:43:00 -0800596 rp->proto = proto;
Dave Barach8b275372017-01-16 10:54:02 -0500597 rp->addr_only = addr_only;
598 rp->is_add = is_add;
Matus Fabian5f224992018-01-25 21:59:16 -0800599 rp->tag = vec_dup (tag);
Dave Barach8b275372017-01-16 10:54:02 -0500600}
Matus Fabianab395ec2018-09-20 23:18:41 -0700601
602static u32
603get_thread_idx_by_port (u16 e_port)
dongjuan58f50f12018-09-04 17:40:53 +0800604{
Matus Fabianab395ec2018-09-20 23:18:41 -0700605 snat_main_t *sm = &snat_main;
606 u32 thread_idx = sm->num_workers;
607 if (sm->num_workers > 1)
dongjuan58f50f12018-09-04 17:40:53 +0800608 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700609 thread_idx =
610 sm->first_worker_index +
611 sm->workers[(e_port - 1024) / sm->port_per_thread];
612 }
613 return thread_idx;
dongjuan58f50f12018-09-04 17:40:53 +0800614}
Dave Barach8b275372017-01-16 10:54:02 -0500615
Matus Fabiandb649882016-08-26 05:45:27 -0700616/**
617 * @brief Add static mapping.
618 *
619 * Create static mapping between local addr+port and external addr+port.
620 *
621 * @param l_addr Local IPv4 address.
622 * @param e_addr External IPv4 address.
623 * @param l_port Local port number.
624 * @param e_port External port number.
625 * @param vrf_id VRF ID.
626 * @param addr_only If 0 address port and pair mapping, otherwise address only.
Matus Fabian36532bd2017-01-23 23:42:28 -0800627 * @param sw_if_index External port instead of specific IP address.
Matus Fabiandb649882016-08-26 05:45:27 -0700628 * @param is_add If 0 delete static mapping, otherwise add.
Juraj Sloboda1e5c07d2018-04-10 13:51:54 +0200629 * @param twice_nat If value is TWICE_NAT then translate external host address
630 * and port.
631 * If value is TWICE_NAT_SELF then translate external host
632 * address and port whenever external host address equals
633 * local address of internal host.
Matus Fabiane82488f2018-01-18 03:38:45 -0800634 * @param out2in_only If 1 rule match only out2in direction
Matus Fabian5f224992018-01-25 21:59:16 -0800635 * @param tag - opaque string tag
Matus Fabiandb649882016-08-26 05:45:27 -0700636 *
637 * @returns
638 */
Matus Fabianab395ec2018-09-20 23:18:41 -0700639int
640snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
641 u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
642 u32 sw_if_index, snat_protocol_t proto, int is_add,
643 twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag)
Matus Fabiandb649882016-08-26 05:45:27 -0700644{
Matus Fabianab395ec2018-09-20 23:18:41 -0700645 snat_main_t *sm = &snat_main;
Matus Fabiandb649882016-08-26 05:45:27 -0700646 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -0800647 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -0700648 clib_bihash_kv_8_8_t kv, value;
649 snat_address_t *a = 0;
650 u32 fib_index = ~0;
Matus Fabianab395ec2018-09-20 23:18:41 -0700651 uword *p;
Matus Fabiane1ae29a2017-01-27 00:47:58 -0800652 snat_interface_t *interface;
Matus Fabiandb649882016-08-26 05:45:27 -0700653 int i;
Matus Fabianb932d262017-12-18 05:38:24 -0800654 snat_main_per_thread_data_t *tsm;
Matus Fabianb793d092018-01-31 05:50:21 -0800655 snat_user_key_t u_key;
656 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -0700657 dlist_elt_t *head, *elt;
Matus Fabianb793d092018-01-31 05:50:21 -0800658 u32 elt_index, head_index;
659 u32 ses_index;
660 u64 user_index;
Matus Fabianab395ec2018-09-20 23:18:41 -0700661 snat_session_t *s;
Matus Fabianf13a8782018-04-06 02:54:40 -0700662 snat_static_map_resolve_t *rp, *rp_match = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700663
Matus Fabiana6110b62018-06-13 05:39:07 -0700664 if (!sm->endpoint_dependent)
665 {
666 if (twice_nat || out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700667 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabiana6110b62018-06-13 05:39:07 -0700668 }
669
Dave Barach8b275372017-01-16 10:54:02 -0500670 /* If the external address is a specific interface address */
671 if (sw_if_index != ~0)
672 {
Matus Fabianab395ec2018-09-20 23:18:41 -0700673 ip4_address_t *first_int_addr;
Matus Fabianea2600a2018-03-28 04:06:26 -0700674
675 for (i = 0; i < vec_len (sm->to_resolve); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -0700676 {
677 rp = sm->to_resolve + i;
678 if (rp->sw_if_index != sw_if_index ||
679 rp->l_addr.as_u32 != l_addr.as_u32 ||
680 rp->vrf_id != vrf_id || rp->addr_only != addr_only)
681 continue;
Matus Fabianea2600a2018-03-28 04:06:26 -0700682
Matus Fabianab395ec2018-09-20 23:18:41 -0700683 if (!addr_only)
684 {
685 if (rp->l_port != l_port || rp->e_port != e_port
686 || rp->proto != proto)
687 continue;
688 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700689
Matus Fabianab395ec2018-09-20 23:18:41 -0700690 rp_match = rp;
691 break;
692 }
Dave Barach8b275372017-01-16 10:54:02 -0500693
694 /* Might be already set... */
Matus Fabian2ba92e32017-08-21 07:05:03 -0700695 first_int_addr = ip4_interface_first_address
Matus Fabianab395ec2018-09-20 23:18:41 -0700696 (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
Dave Barach8b275372017-01-16 10:54:02 -0500697
Matus Fabianea2600a2018-03-28 04:06:26 -0700698 if (is_add)
Matus Fabianab395ec2018-09-20 23:18:41 -0700699 {
700 if (rp_match)
701 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabianea2600a2018-03-28 04:06:26 -0700702
Matus Fabianab395ec2018-09-20 23:18:41 -0700703 snat_add_static_mapping_when_resolved
704 (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
705 addr_only, is_add, tag);
Matus Fabian4772e7a2018-04-04 00:38:02 -0700706
Matus Fabianab395ec2018-09-20 23:18:41 -0700707 /* DHCP resolution required? */
708 if (first_int_addr == 0)
709 {
710 return 0;
711 }
712 else
713 {
714 e_addr.as_u32 = first_int_addr->as_u32;
715 /* Identity mapping? */
716 if (l_addr.as_u32 == 0)
717 l_addr.as_u32 = e_addr.as_u32;
718 }
719 }
Matus Fabianea2600a2018-03-28 04:06:26 -0700720 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700721 {
722 if (!rp_match)
723 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabianea2600a2018-03-28 04:06:26 -0700724
Matus Fabianab395ec2018-09-20 23:18:41 -0700725 vec_del1 (sm->to_resolve, i);
Matus Fabianea2600a2018-03-28 04:06:26 -0700726
Matus Fabianab395ec2018-09-20 23:18:41 -0700727 if (first_int_addr)
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 else
735 return 0;
736 }
Dave Barach8b275372017-01-16 10:54:02 -0500737 }
738
Matus Fabiandb649882016-08-26 05:45:27 -0700739 m_key.addr = e_addr;
740 m_key.port = addr_only ? 0 : e_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800741 m_key.protocol = addr_only ? 0 : proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700742 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700743 kv.key = m_key.as_u64;
744 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
745 m = 0;
746 else
747 m = pool_elt_at_index (sm->static_mappings, value.value);
748
749 if (is_add)
750 {
751 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -0700752 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabiandb649882016-08-26 05:45:27 -0700753
Matus Fabianb932d262017-12-18 05:38:24 -0800754 if (twice_nat && addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700755 return VNET_API_ERROR_UNSUPPORTED;
Matus Fabianb932d262017-12-18 05:38:24 -0800756
Matus Fabiandb649882016-08-26 05:45:27 -0700757 /* Convert VRF id to FIB index */
758 if (vrf_id != ~0)
Matus Fabianab395ec2018-09-20 23:18:41 -0700759 {
760 p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
761 if (!p)
762 return VNET_API_ERROR_NO_SUCH_FIB;
763 fib_index = p[0];
764 }
Matus Fabiandb649882016-08-26 05:45:27 -0700765 /* If not specified use inside VRF id from SNAT plugin startup config */
766 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700767 {
768 fib_index = sm->inside_fib_index;
769 vrf_id = sm->inside_vrf_id;
770 }
Matus Fabiandb649882016-08-26 05:45:27 -0700771
Matus Fabian36a62702018-04-04 03:27:43 -0700772 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700773 {
774 m_key.addr = l_addr;
775 m_key.port = addr_only ? 0 : l_port;
776 m_key.protocol = addr_only ? 0 : proto;
777 m_key.fib_index = fib_index;
778 kv.key = m_key.as_u64;
779 if (!clib_bihash_search_8_8
780 (&sm->static_mapping_by_local, &kv, &value))
781 return VNET_API_ERROR_VALUE_EXIST;
782 }
Matus Fabian36a62702018-04-04 03:27:43 -0700783
Matus Fabiandb649882016-08-26 05:45:27 -0700784 /* Find external address in allocated addresses and reserve port for
785 address and port pair mapping when dynamic translations enabled */
Matus Fabiane82488f2018-01-18 03:38:45 -0800786 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700787 {
788 for (i = 0; i < vec_len (sm->addresses); i++)
789 {
790 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
791 {
792 a = sm->addresses + i;
793 /* External port must be unused */
794 switch (proto)
795 {
Matus Fabian09d96f42017-02-02 01:43:00 -0800796#define _(N, j, n, s) \
797 case SNAT_PROTOCOL_##N: \
798 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
799 return VNET_API_ERROR_INVALID_VALUE; \
800 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
801 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700802 { \
803 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +0800804 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -0700805 } \
Matus Fabian09d96f42017-02-02 01:43:00 -0800806 break;
Matus Fabianab395ec2018-09-20 23:18:41 -0700807 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -0800808#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700809 default:
810 nat_log_info ("unknown protocol");
811 return VNET_API_ERROR_INVALID_VALUE_2;
812 }
813 break;
814 }
815 }
816 /* External address must be allocated */
817 if (!a && (l_addr.as_u32 != e_addr.as_u32))
818 {
819 if (sw_if_index != ~0)
820 {
821 for (i = 0; i < vec_len (sm->to_resolve); i++)
822 {
823 rp = sm->to_resolve + i;
824 if (rp->addr_only)
825 continue;
826 if (rp->sw_if_index != sw_if_index &&
827 rp->l_addr.as_u32 != l_addr.as_u32 &&
828 rp->vrf_id != vrf_id && rp->l_port != l_port &&
829 rp->e_port != e_port && rp->proto != proto)
830 continue;
Matus Fabianf13a8782018-04-06 02:54:40 -0700831
Matus Fabianab395ec2018-09-20 23:18:41 -0700832 vec_del1 (sm->to_resolve, i);
833 break;
834 }
835 }
836 return VNET_API_ERROR_NO_SUCH_ENTRY;
837 }
838 }
Matus Fabiandb649882016-08-26 05:45:27 -0700839
840 pool_get (sm->static_mappings, m);
841 memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -0800842 m->tag = vec_dup (tag);
Matus Fabiandb649882016-08-26 05:45:27 -0700843 m->local_addr = l_addr;
844 m->external_addr = e_addr;
845 m->addr_only = addr_only;
846 m->vrf_id = vrf_id;
847 m->fib_index = fib_index;
Matus Fabianb932d262017-12-18 05:38:24 -0800848 m->twice_nat = twice_nat;
Matus Fabiane82488f2018-01-18 03:38:45 -0800849 m->out2in_only = out2in_only;
Matus Fabiandb649882016-08-26 05:45:27 -0700850 if (!addr_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700851 {
852 m->local_port = l_port;
853 m->external_port = e_port;
854 m->proto = proto;
855 }
Matus Fabiandb649882016-08-26 05:45:27 -0700856
Matus Fabiana6110b62018-06-13 05:39:07 -0700857 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -0700858 {
859 ip4_header_t ip = {
860 .src_address = m->local_addr,
861 };
862 vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index));
863 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
864 }
Matus Fabianb932d262017-12-18 05:38:24 -0800865 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700866 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -0800867
Matus Fabiandb649882016-08-26 05:45:27 -0700868 m_key.addr = m->local_addr;
869 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800870 m_key.protocol = m->proto;
Matus Fabian7e46a4d2016-10-06 04:28:29 -0700871 m_key.fib_index = m->fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -0700872 kv.key = m_key.as_u64;
873 kv.value = m - sm->static_mappings;
Matus Fabiane82488f2018-01-18 03:38:45 -0800874 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700875 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
Matus Fabiandb649882016-08-26 05:45:27 -0700876
877 m_key.addr = m->external_addr;
878 m_key.port = m->external_port;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700879 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700880 kv.key = m_key.as_u64;
881 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -0700882 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
Matus Fabianb932d262017-12-18 05:38:24 -0800883
Matus Fabianb793d092018-01-31 05:50:21 -0800884 /* Delete dynamic sessions matching local address (+ local port) */
885 if (!(sm->static_mapping_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700886 {
887 u_key.addr = m->local_addr;
888 u_key.fib_index = m->fib_index;
889 kv.key = u_key.as_u64;
890 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
891 {
892 user_index = value.value;
893 u = pool_elt_at_index (tsm->users, user_index);
894 if (u->nsessions)
895 {
896 head_index = u->sessions_per_user_list_head_index;
897 head = pool_elt_at_index (tsm->list_pool, head_index);
898 elt_index = head->next;
899 elt = pool_elt_at_index (tsm->list_pool, elt_index);
900 ses_index = elt->value;
901 while (ses_index != ~0)
902 {
903 s = pool_elt_at_index (tsm->sessions, ses_index);
904 elt = pool_elt_at_index (tsm->list_pool, elt->next);
905 ses_index = elt->value;
Matus Fabianb793d092018-01-31 05:50:21 -0800906
Matus Fabianab395ec2018-09-20 23:18:41 -0700907 if (snat_is_session_static (s))
908 continue;
Matus Fabianb793d092018-01-31 05:50:21 -0800909
Matus Fabianab395ec2018-09-20 23:18:41 -0700910 if (!addr_only
911 && (clib_net_to_host_u16 (s->in2out.port) !=
912 m->local_port))
913 continue;
Matus Fabianb793d092018-01-31 05:50:21 -0800914
Matus Fabianab395ec2018-09-20 23:18:41 -0700915 nat_free_session_data (sm, s,
916 tsm - sm->per_thread_data);
917 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb793d092018-01-31 05:50:21 -0800918
Matus Fabianab395ec2018-09-20 23:18:41 -0700919 if (!addr_only && !sm->endpoint_dependent)
920 break;
921 }
922 }
923 }
924 }
Matus Fabiandb649882016-08-26 05:45:27 -0700925 }
926 else
927 {
928 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -0700929 {
930 if (sw_if_index != ~0)
931 return 0;
932 else
933 return VNET_API_ERROR_NO_SUCH_ENTRY;
934 }
Matus Fabiandb649882016-08-26 05:45:27 -0700935
936 /* Free external address port */
Matus Fabiane82488f2018-01-18 03:38:45 -0800937 if (!(addr_only || sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -0700938 {
939 for (i = 0; i < vec_len (sm->addresses); i++)
940 {
941 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
942 {
943 a = sm->addresses + i;
944 switch (proto)
945 {
Matus Fabian09d96f42017-02-02 01:43:00 -0800946#define _(N, j, n, s) \
947 case SNAT_PROTOCOL_##N: \
948 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
949 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -0700950 { \
951 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +0800952 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -0700953 } \
Matus Fabian09d96f42017-02-02 01:43:00 -0800954 break;
Matus Fabianab395ec2018-09-20 23:18:41 -0700955 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -0800956#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -0700957 default:
958 nat_log_info ("unknown protocol");
959 return VNET_API_ERROR_INVALID_VALUE_2;
960 }
961 break;
962 }
963 }
964 }
Matus Fabiandb649882016-08-26 05:45:27 -0700965
Matus Fabianb932d262017-12-18 05:38:24 -0800966 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -0700967 tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
Matus Fabianb932d262017-12-18 05:38:24 -0800968 else
Matus Fabianab395ec2018-09-20 23:18:41 -0700969 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabianb932d262017-12-18 05:38:24 -0800970
Matus Fabiandb649882016-08-26 05:45:27 -0700971 m_key.addr = m->local_addr;
972 m_key.port = m->local_port;
Matus Fabian09d96f42017-02-02 01:43:00 -0800973 m_key.protocol = m->proto;
Matus Fabian7e46a4d2016-10-06 04:28:29 -0700974 m_key.fib_index = m->fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -0700975 kv.key = m_key.as_u64;
Matus Fabiane82488f2018-01-18 03:38:45 -0800976 if (!out2in_only)
Matus Fabianab395ec2018-09-20 23:18:41 -0700977 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
Matus Fabiandb649882016-08-26 05:45:27 -0700978
979 m_key.addr = m->external_addr;
980 m_key.port = m->external_port;
Matus Fabian8008d7c2018-07-09 01:34:20 -0700981 m_key.fib_index = 0;
Matus Fabiandb649882016-08-26 05:45:27 -0700982 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -0700983 clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
Matus Fabiandb649882016-08-26 05:45:27 -0700984
985 /* Delete session(s) for static mapping if exist */
986 if (!(sm->static_mapping_only) ||
Matus Fabianab395ec2018-09-20 23:18:41 -0700987 (sm->static_mapping_only && sm->static_mapping_connection_tracking))
988 {
989 u_key.addr = m->local_addr;
990 u_key.fib_index = m->fib_index;
991 kv.key = u_key.as_u64;
992 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
993 {
994 user_index = value.value;
995 u = pool_elt_at_index (tsm->users, user_index);
996 if (u->nstaticsessions)
997 {
998 head_index = u->sessions_per_user_list_head_index;
999 head = pool_elt_at_index (tsm->list_pool, head_index);
1000 elt_index = head->next;
1001 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1002 ses_index = elt->value;
1003 while (ses_index != ~0)
1004 {
1005 s = pool_elt_at_index (tsm->sessions, ses_index);
1006 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1007 ses_index = elt->value;
Matus Fabiandb649882016-08-26 05:45:27 -07001008
Matus Fabianab395ec2018-09-20 23:18:41 -07001009 if (!addr_only)
1010 {
1011 if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1012 (clib_net_to_host_u16 (s->out2in.port) !=
1013 e_port))
1014 continue;
1015 }
Matus Fabian13c08182018-04-11 00:36:57 -07001016
Matus Fabianab395ec2018-09-20 23:18:41 -07001017 if (is_lb_session (s))
1018 continue;
Matus Fabian475f0552016-10-19 06:17:52 -07001019
Matus Fabianab395ec2018-09-20 23:18:41 -07001020 if (!snat_is_session_static (s))
1021 continue;
Matus Fabian70a26ac2018-05-14 06:20:28 -07001022
Matus Fabianab395ec2018-09-20 23:18:41 -07001023 nat_free_session_data (sm, s,
1024 tsm - sm->per_thread_data);
1025 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabiandb649882016-08-26 05:45:27 -07001026
Matus Fabianab395ec2018-09-20 23:18:41 -07001027 if (!addr_only && !sm->endpoint_dependent)
1028 break;
1029 }
1030 }
1031 }
1032 }
Matus Fabiandb649882016-08-26 05:45:27 -07001033
Matus Fabian5f224992018-01-25 21:59:16 -08001034 vec_free (m->tag);
Matus Fabiana6110b62018-06-13 05:39:07 -07001035 vec_free (m->workers);
Matus Fabiandb649882016-08-26 05:45:27 -07001036 /* Delete static mapping from pool */
1037 pool_put (sm->static_mappings, m);
1038 }
1039
Matus Fabianab7a8052017-11-28 04:29:41 -08001040 if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001041 return 0;
1042
1043 /* Add/delete external address to FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001044 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001045 pool_foreach (interface, sm->interfaces,
1046 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001047 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001048 continue;
1049
Matus Fabian066f0342017-02-10 03:48:01 -08001050 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
Matus Fabiandccbee32017-01-31 22:20:30 -08001051 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001052 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001053 pool_foreach (interface, sm->output_feature_interfaces,
1054 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001055 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001056 continue;
1057
1058 snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1059 break;
1060 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001061 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001062
Matus Fabiandb649882016-08-26 05:45:27 -07001063 return 0;
1064}
1065
Matus Fabianab395ec2018-09-20 23:18:41 -07001066int
1067nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1068 snat_protocol_t proto,
1069 nat44_lb_addr_port_t * locals, u8 is_add,
1070 twice_nat_type_t twice_nat, u8 out2in_only,
1071 u8 * tag, u32 affinity)
Matus Fabian704018c2017-09-04 02:17:18 -07001072{
Matus Fabianab395ec2018-09-20 23:18:41 -07001073 snat_main_t *sm = &snat_main;
Matus Fabian704018c2017-09-04 02:17:18 -07001074 snat_static_mapping_t *m;
1075 snat_session_key_t m_key;
1076 clib_bihash_kv_8_8_t kv, value;
Matus Fabian704018c2017-09-04 02:17:18 -07001077 snat_address_t *a = 0;
1078 int i;
1079 nat44_lb_addr_port_t *local;
Matus Fabiana6110b62018-06-13 05:39:07 -07001080 u32 elt_index, head_index, ses_index;
Matus Fabian092b3cd2017-09-19 05:42:38 -07001081 snat_main_per_thread_data_t *tsm;
Matus Fabianb932d262017-12-18 05:38:24 -08001082 snat_user_key_t u_key;
1083 snat_user_t *u;
Matus Fabianab395ec2018-09-20 23:18:41 -07001084 snat_session_t *s;
1085 dlist_elt_t *head, *elt;
Matus Fabiana6110b62018-06-13 05:39:07 -07001086 uword *bitmap = 0;
1087
1088 if (!sm->endpoint_dependent)
1089 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian704018c2017-09-04 02:17:18 -07001090
1091 m_key.addr = e_addr;
1092 m_key.port = e_port;
1093 m_key.protocol = proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001094 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001095 kv.key = m_key.as_u64;
1096 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1097 m = 0;
1098 else
1099 m = pool_elt_at_index (sm->static_mappings, value.value);
1100
1101 if (is_add)
1102 {
1103 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001104 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian704018c2017-09-04 02:17:18 -07001105
1106 if (vec_len (locals) < 2)
Matus Fabianab395ec2018-09-20 23:18:41 -07001107 return VNET_API_ERROR_INVALID_VALUE;
Matus Fabian704018c2017-09-04 02:17:18 -07001108
Matus Fabian704018c2017-09-04 02:17:18 -07001109 /* Find external address in allocated addresses and reserve port for
1110 address and port pair mapping when dynamic translations enabled */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001111 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001112 {
1113 for (i = 0; i < vec_len (sm->addresses); i++)
1114 {
1115 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1116 {
1117 a = sm->addresses + i;
1118 /* External port must be unused */
1119 switch (proto)
1120 {
Matus Fabian704018c2017-09-04 02:17:18 -07001121#define _(N, j, n, s) \
1122 case SNAT_PROTOCOL_##N: \
1123 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1124 return VNET_API_ERROR_INVALID_VALUE; \
1125 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1126 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001127 { \
1128 a->busy_##n##_ports++; \
dongjuan58f50f12018-09-04 17:40:53 +08001129 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001130 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001131 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001132 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001133#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001134 default:
1135 nat_log_info ("unknown protocol");
1136 return VNET_API_ERROR_INVALID_VALUE_2;
1137 }
1138 break;
1139 }
1140 }
1141 /* External address must be allocated */
1142 if (!a)
1143 return VNET_API_ERROR_NO_SUCH_ENTRY;
1144 }
Matus Fabian704018c2017-09-04 02:17:18 -07001145
1146 pool_get (sm->static_mappings, m);
1147 memset (m, 0, sizeof (*m));
Matus Fabian5f224992018-01-25 21:59:16 -08001148 m->tag = vec_dup (tag);
Matus Fabian704018c2017-09-04 02:17:18 -07001149 m->external_addr = e_addr;
1150 m->addr_only = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001151 m->external_port = e_port;
1152 m->proto = proto;
Matus Fabianb932d262017-12-18 05:38:24 -08001153 m->twice_nat = twice_nat;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001154 m->out2in_only = out2in_only;
Matus Fabianea5b5be2018-09-03 05:02:23 -07001155 m->affinity = affinity;
1156
1157 if (affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001158 m->affinity_per_service_list_head_index =
1159 nat_affinity_get_per_service_list_head_index ();
Matus Fabianea5b5be2018-09-03 05:02:23 -07001160 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001161 m->affinity_per_service_list_head_index = ~0;
Matus Fabian704018c2017-09-04 02:17:18 -07001162
1163 m_key.addr = m->external_addr;
1164 m_key.port = m->external_port;
1165 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001166 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001167 kv.key = m_key.as_u64;
1168 kv.value = m - sm->static_mappings;
Matus Fabianab395ec2018-09-20 23:18:41 -07001169 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1170 {
1171 nat_log_err ("static_mapping_by_external key add failed");
1172 return VNET_API_ERROR_UNSPECIFIED;
1173 }
Matus Fabian704018c2017-09-04 02:17:18 -07001174
Matus Fabian092b3cd2017-09-19 05:42:38 -07001175 m_key.fib_index = m->fib_index;
Matus Fabian704018c2017-09-04 02:17:18 -07001176 for (i = 0; i < vec_len (locals); i++)
Matus Fabianab395ec2018-09-20 23:18:41 -07001177 {
1178 locals[i].fib_index =
1179 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1180 locals[i].vrf_id,
1181 FIB_SOURCE_PLUGIN_LOW);
1182 m_key.addr = locals[i].addr;
1183 m_key.fib_index = locals[i].fib_index;
1184 if (!out2in_only)
1185 {
1186 m_key.port = locals[i].port;
1187 kv.key = m_key.as_u64;
1188 kv.value = m - sm->static_mappings;
1189 clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1190 }
1191 locals[i].prefix = (i == 0) ? locals[i].probability :
1192 (locals[i - 1].prefix + locals[i].probability);
1193 vec_add1 (m->locals, locals[i]);
1194 if (sm->num_workers > 1)
1195 {
1196 ip4_header_t ip = {
1197 .src_address = locals[i].addr,
1198 };
1199 bitmap =
1200 clib_bitmap_set (bitmap,
1201 sm->worker_in2out_cb (&ip, m->fib_index), 1);
1202 }
1203 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001204
1205 /* Assign workers */
1206 if (sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001207 {
1208 /* *INDENT-OFF* */
Matus Fabiana6110b62018-06-13 05:39:07 -07001209 clib_bitmap_foreach (i, bitmap,
1210 ({
1211 vec_add1(m->workers, i);
1212 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001213 /* *INDENT-ON* */
1214 }
Matus Fabian704018c2017-09-04 02:17:18 -07001215 }
1216 else
1217 {
1218 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07001219 return VNET_API_ERROR_NO_SUCH_ENTRY;
Matus Fabian704018c2017-09-04 02:17:18 -07001220
Matus Fabian704018c2017-09-04 02:17:18 -07001221 /* Free external address port */
Matus Fabian240b5ef2018-01-11 04:09:17 -08001222 if (!(sm->static_mapping_only || out2in_only))
Matus Fabianab395ec2018-09-20 23:18:41 -07001223 {
1224 for (i = 0; i < vec_len (sm->addresses); i++)
1225 {
1226 if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1227 {
1228 a = sm->addresses + i;
1229 switch (proto)
1230 {
Matus Fabian704018c2017-09-04 02:17:18 -07001231#define _(N, j, n, s) \
1232 case SNAT_PROTOCOL_##N: \
1233 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1234 if (e_port > 1024) \
Matus Fabian624b8d92017-09-12 04:15:30 -07001235 { \
1236 a->busy_##n##_ports--; \
dongjuan58f50f12018-09-04 17:40:53 +08001237 a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07001238 } \
Matus Fabian704018c2017-09-04 02:17:18 -07001239 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07001240 foreach_snat_protocol
Matus Fabian704018c2017-09-04 02:17:18 -07001241#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001242 default:
1243 nat_log_info ("unknown protocol");
1244 return VNET_API_ERROR_INVALID_VALUE_2;
1245 }
1246 break;
1247 }
1248 }
1249 }
Matus Fabian704018c2017-09-04 02:17:18 -07001250
1251 m_key.addr = m->external_addr;
1252 m_key.port = m->external_port;
1253 m_key.protocol = m->proto;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001254 m_key.fib_index = 0;
Matus Fabian704018c2017-09-04 02:17:18 -07001255 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07001256 if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1257 {
1258 nat_log_err ("static_mapping_by_external key del failed");
1259 return VNET_API_ERROR_UNSPECIFIED;
1260 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001261
Matus Fabianab395ec2018-09-20 23:18:41 -07001262 /* *INDENT-OFF* */
Matus Fabian704018c2017-09-04 02:17:18 -07001263 vec_foreach (local, m->locals)
1264 {
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001265 fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1266 FIB_SOURCE_PLUGIN_LOW);
Matus Fabian704018c2017-09-04 02:17:18 -07001267 m_key.addr = local->addr;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001268 if (!out2in_only)
Matus Fabian704018c2017-09-04 02:17:18 -07001269 {
Matus Fabian240b5ef2018-01-11 04:09:17 -08001270 m_key.port = local->port;
Matus Fabianc6c0d2a2018-07-19 22:45:25 -07001271 m_key.fib_index = local->fib_index;
Matus Fabian240b5ef2018-01-11 04:09:17 -08001272 kv.key = m_key.as_u64;
1273 if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1274 {
Matus Fabian229c1aa2018-05-28 04:09:52 -07001275 nat_log_err ("static_mapping_by_local key del failed");
Matus Fabian240b5ef2018-01-11 04:09:17 -08001276 return VNET_API_ERROR_UNSPECIFIED;
1277 }
Matus Fabian704018c2017-09-04 02:17:18 -07001278 }
Matus Fabian7865b5c2017-09-26 01:23:01 -07001279
Matus Fabiana6110b62018-06-13 05:39:07 -07001280 if (sm->num_workers > 1)
Matus Fabian704018c2017-09-04 02:17:18 -07001281 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001282 ip4_header_t ip = {
1283 .src_address = local->addr,
1284 };
1285 tsm = vec_elt_at_index (sm->per_thread_data,
1286 sm->worker_in2out_cb (&ip, m->fib_index));
Matus Fabian704018c2017-09-04 02:17:18 -07001287 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001288 else
1289 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1290
Matus Fabianb932d262017-12-18 05:38:24 -08001291 /* Delete sessions */
1292 u_key.addr = local->addr;
1293 u_key.fib_index = m->fib_index;
1294 kv.key = u_key.as_u64;
1295 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1296 {
1297 u = pool_elt_at_index (tsm->users, value.value);
1298 if (u->nstaticsessions)
1299 {
1300 head_index = u->sessions_per_user_list_head_index;
1301 head = pool_elt_at_index (tsm->list_pool, head_index);
1302 elt_index = head->next;
1303 elt = pool_elt_at_index (tsm->list_pool, elt_index);
1304 ses_index = elt->value;
1305 while (ses_index != ~0)
1306 {
1307 s = pool_elt_at_index (tsm->sessions, ses_index);
1308 elt = pool_elt_at_index (tsm->list_pool, elt->next);
1309 ses_index = elt->value;
1310
Matus Fabian13c08182018-04-11 00:36:57 -07001311 if (!(is_lb_session (s)))
1312 continue;
1313
shubing guo060c3a72018-08-10 13:59:50 +08001314 if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
Matus Fabianb932d262017-12-18 05:38:24 -08001315 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1316 continue;
1317
1318 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
Matus Fabian229c1aa2018-05-28 04:09:52 -07001319 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabianb932d262017-12-18 05:38:24 -08001320 }
1321 }
1322 }
Matus Fabian704018c2017-09-04 02:17:18 -07001323 }
Matus Fabianab395ec2018-09-20 23:18:41 -07001324 /* *INDENT-ON* */
Matus Fabianea5b5be2018-09-03 05:02:23 -07001325 if (m->affinity)
Matus Fabianab395ec2018-09-20 23:18:41 -07001326 nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1327 vec_free (m->locals);
1328 vec_free (m->tag);
1329 vec_free (m->workers);
Matus Fabian704018c2017-09-04 02:17:18 -07001330
1331 pool_put (sm->static_mappings, m);
1332 }
1333
1334 return 0;
1335}
1336
Matus Fabianb932d262017-12-18 05:38:24 -08001337int
Matus Fabianab395ec2018-09-20 23:18:41 -07001338snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1339 u8 twice_nat)
Matus Fabian36532bd2017-01-23 23:42:28 -08001340{
1341 snat_address_t *a = 0;
1342 snat_session_t *ses;
1343 u32 *ses_to_be_removed = 0, *ses_index;
Matus Fabian36532bd2017-01-23 23:42:28 -08001344 snat_main_per_thread_data_t *tsm;
1345 snat_static_mapping_t *m;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001346 snat_interface_t *interface;
Matus Fabian36532bd2017-01-23 23:42:28 -08001347 int i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001348 snat_address_t *addresses =
1349 twice_nat ? sm->twice_nat_addresses : sm->addresses;
Matus Fabian36532bd2017-01-23 23:42:28 -08001350
1351 /* Find SNAT address */
Matus Fabianab395ec2018-09-20 23:18:41 -07001352 for (i = 0; i < vec_len (addresses); i++)
Matus Fabian36532bd2017-01-23 23:42:28 -08001353 {
Matus Fabianb932d262017-12-18 05:38:24 -08001354 if (addresses[i].addr.as_u32 == addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07001355 {
1356 a = addresses + i;
1357 break;
1358 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001359 }
1360 if (!a)
1361 return VNET_API_ERROR_NO_SUCH_ENTRY;
1362
1363 if (delete_sm)
1364 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001365 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001366 pool_foreach (m, sm->static_mappings,
1367 ({
1368 if (m->external_addr.as_u32 == addr.as_u32)
1369 (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1370 m->local_port, m->external_port,
Matus Fabian09d96f42017-02-02 01:43:00 -08001371 m->vrf_id, m->addr_only, ~0,
Matus Fabiane82488f2018-01-18 03:38:45 -08001372 m->proto, 0, m->twice_nat,
Matus Fabian5f224992018-01-25 21:59:16 -08001373 m->out2in_only, m->tag);
Matus Fabian36532bd2017-01-23 23:42:28 -08001374 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001375 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001376 }
1377 else
1378 {
1379 /* Check if address is used in some static mapping */
Matus Fabianab395ec2018-09-20 23:18:41 -07001380 if (is_snat_address_used_in_static_mapping (sm, addr))
1381 {
1382 nat_log_notice ("address used in static mapping");
1383 return VNET_API_ERROR_UNSPECIFIED;
1384 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001385 }
1386
Matus Fabianf8d84902017-07-23 23:41:03 -07001387 if (a->fib_index != ~0)
Matus Fabianab395ec2018-09-20 23:18:41 -07001388 fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
Matus Fabianf8d84902017-07-23 23:41:03 -07001389
Matus Fabian36532bd2017-01-23 23:42:28 -08001390 /* Delete sessions using address */
Matus Fabian09d96f42017-02-02 01:43:00 -08001391 if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
Matus Fabian36532bd2017-01-23 23:42:28 -08001392 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001393 /* *INDENT-OFF* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001394 vec_foreach (tsm, sm->per_thread_data)
1395 {
1396 pool_foreach (ses, tsm->sessions, ({
1397 if (ses->out2in.addr.as_u32 == addr.as_u32)
1398 {
Matus Fabianb932d262017-12-18 05:38:24 -08001399 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
Matus Fabianb932d262017-12-18 05:38:24 -08001400 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
Matus Fabian36532bd2017-01-23 23:42:28 -08001401 }
1402 }));
1403
1404 vec_foreach (ses_index, ses_to_be_removed)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001405 {
1406 ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1407 nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1408 }
Matus Fabian36532bd2017-01-23 23:42:28 -08001409
1410 vec_free (ses_to_be_removed);
Matus Fabianab395ec2018-09-20 23:18:41 -07001411 }
1412 /* *INDENT-ON* */
Matus Fabian36532bd2017-01-23 23:42:28 -08001413 }
1414
dongjuandf865202018-09-11 11:20:30 +00001415#define _(N, i, n, s) \
1416 clib_bitmap_free (a->busy_##n##_port_bitmap); \
1417 vec_free (a->busy_##n##_ports_per_thread);
1418 foreach_snat_protocol
1419#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07001420 if (twice_nat)
Matus Fabianb932d262017-12-18 05:38:24 -08001421 {
1422 vec_del1 (sm->twice_nat_addresses, i);
1423 return 0;
1424 }
1425 else
1426 vec_del1 (sm->addresses, i);
Matus Fabian36532bd2017-01-23 23:42:28 -08001427
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001428 /* Delete external address from FIB */
Matus Fabianab395ec2018-09-20 23:18:41 -07001429 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001430 pool_foreach (interface, sm->interfaces,
1431 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001432 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001433 continue;
1434
Matus Fabian066f0342017-02-10 03:48:01 -08001435 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
Matus Fabiandccbee32017-01-31 22:20:30 -08001436 break;
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001437 }));
Matus Fabian93d84c92017-07-19 08:06:01 -07001438 pool_foreach (interface, sm->output_feature_interfaces,
1439 ({
Juraj Slobodacba69362017-12-19 02:09:32 +01001440 if (nat_interface_is_inside(interface) || sm->out2in_dpo)
Matus Fabian93d84c92017-07-19 08:06:01 -07001441 continue;
1442
1443 snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1444 break;
1445 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001446 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001447
Matus Fabian36532bd2017-01-23 23:42:28 -08001448 return 0;
1449}
1450
Matus Fabianab395ec2018-09-20 23:18:41 -07001451int
1452snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
Matus Fabian588144a2016-10-24 03:30:00 -07001453{
1454 snat_main_t *sm = &snat_main;
1455 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001456 const char *feature_name, *del_feature_name;
1457 snat_address_t *ap;
1458 snat_static_mapping_t *m;
1459 snat_det_map_t *dm;
Matus Fabian8008d7c2018-07-09 01:34:20 -07001460 nat_outside_fib_t *outside_fib;
1461 u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07001462 sw_if_index);
Matus Fabian588144a2016-10-24 03:30:00 -07001463
Juraj Slobodacba69362017-12-19 02:09:32 +01001464 if (sm->out2in_dpo && !is_inside)
1465 return VNET_API_ERROR_UNSUPPORTED;
1466
Matus Fabianab395ec2018-09-20 23:18:41 -07001467 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001468 pool_foreach (i, sm->output_feature_interfaces,
1469 ({
1470 if (i->sw_if_index == sw_if_index)
1471 return VNET_API_ERROR_VALUE_EXIST;
1472 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001473 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001474
Matus Fabian588144a2016-10-24 03:30:00 -07001475 if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
Matus Fabianab395ec2018-09-20 23:18:41 -07001476 feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
Matus Fabian588144a2016-10-24 03:30:00 -07001477 else
Matus Fabian475f0552016-10-19 06:17:52 -07001478 {
Matus Fabian066f0342017-02-10 03:48:01 -08001479 if (sm->num_workers > 1 && !sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001480 feature_name =
1481 is_inside ? "nat44-in2out-worker-handoff" :
1482 "nat44-out2in-worker-handoff";
Matus Fabian066f0342017-02-10 03:48:01 -08001483 else if (sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001484 feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
Matus Fabiana6110b62018-06-13 05:39:07 -07001485 else if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001486 feature_name = is_inside ? "nat44-ed-in2out" : "nat44-ed-out2in";
Matus Fabian475f0552016-10-19 06:17:52 -07001487 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001488 feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
Matus Fabian475f0552016-10-19 06:17:52 -07001489 }
Matus Fabian588144a2016-10-24 03:30:00 -07001490
Matus Fabian066f0342017-02-10 03:48:01 -08001491 if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001492 sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07001493 NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001494
Matus Fabian066f0342017-02-10 03:48:01 -08001495 if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
Matus Fabian229c1aa2018-05-28 04:09:52 -07001496 sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07001497 NAT_FQ_NELTS);
Matus Fabian475f0552016-10-19 06:17:52 -07001498
Matus Fabian8008d7c2018-07-09 01:34:20 -07001499 if (!is_inside)
1500 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001501 /* *INDENT-OFF* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001502 vec_foreach (outside_fib, sm->outside_fibs)
1503 {
1504 if (outside_fib->fib_index == fib_index)
1505 {
1506 if (is_del)
1507 {
1508 outside_fib->refcount--;
1509 if (!outside_fib->refcount)
1510 vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1511 }
1512 else
1513 outside_fib->refcount++;
1514 goto feature_set;
1515 }
1516 }
Matus Fabianab395ec2018-09-20 23:18:41 -07001517 /* *INDENT-ON* */
Matus Fabian8008d7c2018-07-09 01:34:20 -07001518 if (!is_del)
Matus Fabianab395ec2018-09-20 23:18:41 -07001519 {
1520 vec_add2 (sm->outside_fibs, outside_fib, 1);
1521 outside_fib->refcount = 1;
1522 outside_fib->fib_index = fib_index;
1523 }
Matus Fabian8008d7c2018-07-09 01:34:20 -07001524 }
1525feature_set:
Matus Fabianab395ec2018-09-20 23:18:41 -07001526 /* *INDENT-OFF* */
Matus Fabian588144a2016-10-24 03:30:00 -07001527 pool_foreach (i, sm->interfaces,
1528 ({
1529 if (i->sw_if_index == sw_if_index)
1530 {
1531 if (is_del)
Matus Fabian36ea2d62017-10-24 04:13:49 -07001532 {
1533 if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1534 {
1535 if (is_inside)
1536 i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1537 else
1538 i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1539
1540 if (sm->num_workers > 1 && !sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001541 {
1542 del_feature_name = "nat44-handoff-classify";
1543 feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1544 "nat44-out2in-worker-handoff";
1545 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001546 else if (sm->deterministic)
Milan Lenco2aa22902018-01-22 14:05:14 +01001547 {
1548 del_feature_name = "nat44-det-classify";
1549 feature_name = !is_inside ? "nat44-det-in2out" :
1550 "nat44-det-out2in";
1551 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001552 else if (sm->endpoint_dependent)
1553 {
1554 del_feature_name = "nat44-ed-classify";
1555 feature_name = !is_inside ? "nat44-ed-in2out" :
1556 "nat44-ed-out2in";
1557 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001558 else
Milan Lenco2aa22902018-01-22 14:05:14 +01001559 {
1560 del_feature_name = "nat44-classify";
1561 feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1562 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001563
1564 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1565 sw_if_index, 0, 0, 0);
1566 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1567 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001568 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001569 {
1570 if (sm->endpoint_dependent)
1571 vnet_feature_enable_disable ("ip4-local",
1572 "nat44-ed-hairpinning",
1573 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001574 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001575 vnet_feature_enable_disable ("ip4-local",
1576 "nat44-hairpinning",
1577 sw_if_index, 1, 0, 0);
1578 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001579 }
1580 else
1581 {
1582 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1583 sw_if_index, 0, 0, 0);
1584 pool_put (sm->interfaces, i);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001585 if (is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001586 {
1587 if (sm->endpoint_dependent)
1588 vnet_feature_enable_disable ("ip4-local",
1589 "nat44-ed-hairpinning",
1590 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001591 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001592 vnet_feature_enable_disable ("ip4-local",
1593 "nat44-hairpinning",
1594 sw_if_index, 0, 0, 0);
1595 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001596 }
1597 }
Matus Fabian588144a2016-10-24 03:30:00 -07001598 else
Matus Fabian36ea2d62017-10-24 04:13:49 -07001599 {
1600 if ((nat_interface_is_inside(i) && is_inside) ||
1601 (nat_interface_is_outside(i) && !is_inside))
1602 return 0;
1603
1604 if (sm->num_workers > 1 && !sm->deterministic)
1605 {
1606 del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" :
1607 "nat44-out2in-worker-handoff";
1608 feature_name = "nat44-handoff-classify";
1609 }
1610 else if (sm->deterministic)
1611 {
1612 del_feature_name = !is_inside ? "nat44-det-in2out" :
1613 "nat44-det-out2in";
1614 feature_name = "nat44-det-classify";
1615 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001616 else if (sm->endpoint_dependent)
1617 {
1618 del_feature_name = !is_inside ? "nat44-ed-in2out" :
1619 "nat44-ed-out2in";
1620 feature_name = "nat44-ed-classify";
1621 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001622 else
1623 {
1624 del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in";
1625 feature_name = "nat44-classify";
1626 }
1627
1628 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1629 sw_if_index, 0, 0, 0);
1630 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1631 sw_if_index, 1, 0, 0);
Matus Fabian35dfedc2018-04-26 02:12:20 -07001632 if (!is_inside)
Matus Fabiana6110b62018-06-13 05:39:07 -07001633 {
1634 if (sm->endpoint_dependent)
1635 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1636 sw_if_index, 0, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001637 else if (!sm->deterministic)
Matus Fabiana6110b62018-06-13 05:39:07 -07001638 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1639 sw_if_index, 0, 0, 0);
1640 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001641 goto set_flags;
1642 }
Matus Fabian588144a2016-10-24 03:30:00 -07001643
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001644 goto fib;
Matus Fabian588144a2016-10-24 03:30:00 -07001645 }
1646 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001647 /* *INDENT-ON* */
Matus Fabian588144a2016-10-24 03:30:00 -07001648
1649 if (is_del)
1650 return VNET_API_ERROR_NO_SUCH_ENTRY;
1651
1652 pool_get (sm->interfaces, i);
1653 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001654 i->flags = 0;
Matus Fabianab395ec2018-09-20 23:18:41 -07001655 vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1656 0);
Matus Fabian36ea2d62017-10-24 04:13:49 -07001657
Matus Fabian35dfedc2018-04-26 02:12:20 -07001658 if (is_inside && !sm->out2in_dpo)
Matus Fabiana6110b62018-06-13 05:39:07 -07001659 {
1660 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001661 vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1662 sw_if_index, 1, 0, 0);
Matus Fabian38bc3082018-08-09 05:15:19 -07001663 else if (!sm->deterministic)
Matus Fabianab395ec2018-09-20 23:18:41 -07001664 vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1665 sw_if_index, 1, 0, 0);
Matus Fabiana6110b62018-06-13 05:39:07 -07001666 }
Matus Fabian35dfedc2018-04-26 02:12:20 -07001667
Matus Fabian36ea2d62017-10-24 04:13:49 -07001668set_flags:
1669 if (is_inside)
Matus Fabian35dfedc2018-04-26 02:12:20 -07001670 {
1671 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1672 return 0;
1673 }
Matus Fabian36ea2d62017-10-24 04:13:49 -07001674 else
1675 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian588144a2016-10-24 03:30:00 -07001676
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001677 /* Add/delete external addresses to FIB */
1678fib:
Matus Fabianab395ec2018-09-20 23:18:41 -07001679 /* *INDENT-OFF* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001680 vec_foreach (ap, sm->addresses)
Matus Fabian066f0342017-02-10 03:48:01 -08001681 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001682
1683 pool_foreach (m, sm->static_mappings,
1684 ({
Matus Fabianab7a8052017-11-28 04:29:41 -08001685 if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001686 continue;
1687
Matus Fabian066f0342017-02-10 03:48:01 -08001688 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1689 }));
1690
1691 pool_foreach (dm, sm->det_maps,
1692 ({
1693 snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001694 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001695 /* *INDENT-ON* */
Matus Fabiane1ae29a2017-01-27 00:47:58 -08001696
Matus Fabian588144a2016-10-24 03:30:00 -07001697 return 0;
1698}
1699
Matus Fabianab395ec2018-09-20 23:18:41 -07001700int
1701snat_interface_add_del_output_feature (u32 sw_if_index,
1702 u8 is_inside, int is_del)
Matus Fabian93d84c92017-07-19 08:06:01 -07001703{
1704 snat_main_t *sm = &snat_main;
1705 snat_interface_t *i;
Matus Fabianab395ec2018-09-20 23:18:41 -07001706 snat_address_t *ap;
1707 snat_static_mapping_t *m;
Matus Fabian93d84c92017-07-19 08:06:01 -07001708
1709 if (sm->deterministic ||
1710 (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1711 return VNET_API_ERROR_UNSUPPORTED;
1712
Matus Fabianab395ec2018-09-20 23:18:41 -07001713 /* *INDENT-OFF* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001714 pool_foreach (i, sm->interfaces,
1715 ({
1716 if (i->sw_if_index == sw_if_index)
1717 return VNET_API_ERROR_VALUE_EXIST;
1718 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001719 /* *INDENT-ON* */
Matus Fabiane4e34c22018-03-07 03:17:57 -08001720
Matus Fabian93d84c92017-07-19 08:06:01 -07001721 if (is_inside)
Matus Fabian161c59c2017-07-21 03:46:03 -07001722 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001723 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001724 {
1725 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
1726 sw_if_index, !is_del, 0, 0);
1727 vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
1728 sw_if_index, !is_del, 0, 0);
1729 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001730 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001731 {
1732 vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1733 sw_if_index, !is_del, 0, 0);
1734 vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1735 sw_if_index, !is_del, 0, 0);
1736 }
Matus Fabian161c59c2017-07-21 03:46:03 -07001737 goto fq;
1738 }
Matus Fabian93d84c92017-07-19 08:06:01 -07001739
1740 if (sm->num_workers > 1)
1741 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001742 vnet_feature_enable_disable ("ip4-unicast",
Matus Fabianab395ec2018-09-20 23:18:41 -07001743 "nat44-out2in-worker-handoff",
1744 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07001745 vnet_feature_enable_disable ("ip4-output",
Matus Fabianab395ec2018-09-20 23:18:41 -07001746 "nat44-in2out-output-worker-handoff",
1747 sw_if_index, !is_del, 0, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07001748 }
1749 else
1750 {
Matus Fabiana6110b62018-06-13 05:39:07 -07001751 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07001752 {
1753 vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
1754 sw_if_index, !is_del, 0, 0);
1755 vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
1756 sw_if_index, !is_del, 0, 0);
1757 }
Matus Fabiana6110b62018-06-13 05:39:07 -07001758 else
Matus Fabianab395ec2018-09-20 23:18:41 -07001759 {
1760 vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
1761 sw_if_index, !is_del, 0, 0);
1762 vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1763 sw_if_index, !is_del, 0, 0);
1764 }
Matus Fabian93d84c92017-07-19 08:06:01 -07001765 }
1766
Matus Fabian161c59c2017-07-21 03:46:03 -07001767fq:
Matus Fabian93d84c92017-07-19 08:06:01 -07001768 if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1769 sm->fq_in2out_output_index =
1770 vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1771
1772 if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
Matus Fabianab395ec2018-09-20 23:18:41 -07001773 sm->fq_out2in_index =
1774 vlib_frame_queue_main_init (sm->out2in_node_index, 0);
Matus Fabian93d84c92017-07-19 08:06:01 -07001775
Matus Fabianab395ec2018-09-20 23:18:41 -07001776 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07001777 pool_foreach (i, sm->output_feature_interfaces,
1778 ({
1779 if (i->sw_if_index == sw_if_index)
1780 {
1781 if (is_del)
1782 pool_put (sm->output_feature_interfaces, i);
1783 else
1784 return VNET_API_ERROR_VALUE_EXIST;
1785
1786 goto fib;
1787 }
1788 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001789 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07001790
1791 if (is_del)
1792 return VNET_API_ERROR_NO_SUCH_ENTRY;
1793
1794 pool_get (sm->output_feature_interfaces, i);
1795 i->sw_if_index = sw_if_index;
Matus Fabian36ea2d62017-10-24 04:13:49 -07001796 i->flags = 0;
1797 if (is_inside)
1798 i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1799 else
1800 i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
Matus Fabian93d84c92017-07-19 08:06:01 -07001801
1802 /* Add/delete external addresses to FIB */
1803fib:
1804 if (is_inside)
1805 return 0;
1806
Matus Fabianab395ec2018-09-20 23:18:41 -07001807 /* *INDENT-OFF* */
Matus Fabian93d84c92017-07-19 08:06:01 -07001808 vec_foreach (ap, sm->addresses)
1809 snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1810
1811 pool_foreach (m, sm->static_mappings,
1812 ({
Matus Fabiana15cd022018-04-24 05:23:56 -07001813 if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
Matus Fabian93d84c92017-07-19 08:06:01 -07001814 continue;
1815
1816 snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1817 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001818 /* *INDENT-ON* */
Matus Fabian93d84c92017-07-19 08:06:01 -07001819
1820 return 0;
1821}
1822
Matus Fabianab395ec2018-09-20 23:18:41 -07001823int
1824snat_set_workers (uword * bitmap)
Matus Fabian475f0552016-10-19 06:17:52 -07001825{
1826 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07001827 int i, j = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07001828
1829 if (sm->num_workers < 2)
1830 return VNET_API_ERROR_FEATURE_DISABLED;
1831
1832 if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1833 return VNET_API_ERROR_INVALID_WORKER;
1834
1835 vec_free (sm->workers);
Matus Fabianab395ec2018-09-20 23:18:41 -07001836 /* *INDENT-OFF* */
Matus Fabian475f0552016-10-19 06:17:52 -07001837 clib_bitmap_foreach (i, bitmap,
1838 ({
1839 vec_add1(sm->workers, i);
Matus Fabian10491392018-01-05 05:03:35 -08001840 sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
Matus Fabian7801ca22017-08-03 00:58:05 -07001841 j++;
Matus Fabian475f0552016-10-19 06:17:52 -07001842 }));
Matus Fabianab395ec2018-09-20 23:18:41 -07001843 /* *INDENT-ON* */
Matus Fabian475f0552016-10-19 06:17:52 -07001844
Matus Fabian7801ca22017-08-03 00:58:05 -07001845 sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1846 sm->num_snat_thread = _vec_len (sm->workers);
1847
Matus Fabian475f0552016-10-19 06:17:52 -07001848 return 0;
1849}
1850
Dave Barach8b275372017-01-16 10:54:02 -05001851
Dave Barachcab65ec2017-01-11 13:01:14 -05001852static void
1853snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07001854 uword opaque,
1855 u32 sw_if_index,
1856 ip4_address_t * address,
1857 u32 address_length,
1858 u32 if_address_index, u32 is_delete);
Dave Barachcab65ec2017-01-11 13:01:14 -05001859
Matus Fabian4772e7a2018-04-04 00:38:02 -07001860static void
1861nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07001862 uword opaque,
1863 u32 sw_if_index,
1864 ip4_address_t * address,
1865 u32 address_length,
1866 u32 if_address_index, u32 is_delete);
Matus Fabian4772e7a2018-04-04 00:38:02 -07001867
Matus Fabian27697102017-11-09 01:43:47 -08001868static int
1869nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07001870 u32 fib_index,
1871 u32 thread_index,
1872 snat_session_key_t * k,
1873 u16 port_per_thread, u32 snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08001874
Matus Fabianab395ec2018-09-20 23:18:41 -07001875static clib_error_t *
1876snat_init (vlib_main_t * vm)
Dave Barach20c02cb2016-06-26 10:42:08 -04001877{
Matus Fabianab395ec2018-09-20 23:18:41 -07001878 snat_main_t *sm = &snat_main;
1879 clib_error_t *error = 0;
1880 ip4_main_t *im = &ip4_main;
1881 ip_lookup_main_t *lm = &im->lookup_main;
Matus Fabian475f0552016-10-19 06:17:52 -07001882 uword *p;
1883 vlib_thread_registration_t *tr;
1884 vlib_thread_main_t *tm = vlib_get_thread_main ();
1885 uword *bitmap = 0;
1886 u32 i;
Dave Barachcab65ec2017-01-11 13:01:14 -05001887 ip4_add_del_interface_address_callback_t cb4;
Matus Fabianab395ec2018-09-20 23:18:41 -07001888 vlib_node_t *error_drop_node;
Dave Barach20c02cb2016-06-26 10:42:08 -04001889
Dave Barach20c02cb2016-06-26 10:42:08 -04001890 sm->vlib_main = vm;
Matus Fabianab395ec2018-09-20 23:18:41 -07001891 sm->vnet_main = vnet_get_main ();
Dave Barach20c02cb2016-06-26 10:42:08 -04001892 sm->ip4_main = im;
1893 sm->ip4_lookup_main = lm;
1894 sm->api_main = &api_main;
Matus Fabian475f0552016-10-19 06:17:52 -07001895 sm->first_worker_index = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07001896 sm->num_workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07001897 sm->num_snat_thread = 1;
Matus Fabian475f0552016-10-19 06:17:52 -07001898 sm->workers = 0;
Matus Fabian7801ca22017-08-03 00:58:05 -07001899 sm->port_per_thread = 0xffff - 1024;
Matus Fabian475f0552016-10-19 06:17:52 -07001900 sm->fq_in2out_index = ~0;
1901 sm->fq_out2in_index = ~0;
Matus Fabian6a0946f2017-04-12 03:36:13 -07001902 sm->udp_timeout = SNAT_UDP_TIMEOUT;
1903 sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1904 sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1905 sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
Matus Fabian27697102017-11-09 01:43:47 -08001906 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian5d28c7a2018-09-04 03:55:45 -07001907 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Juraj Sloboda7b929792017-11-23 13:20:48 +01001908 sm->forwarding_enabled = 0;
Matus Fabian229c1aa2018-05-28 04:09:52 -07001909 sm->log_class = vlib_log_register_class ("nat", 0);
1910 error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
1911 sm->error_node_index = error_drop_node->index;
Matus Fabianbb4e0222018-09-13 02:36:25 -07001912 sm->mss_clamping = 0;
Matus Fabian475f0552016-10-19 06:17:52 -07001913
1914 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1915 if (p)
1916 {
1917 tr = (vlib_thread_registration_t *) p[0];
1918 if (tr)
Matus Fabianab395ec2018-09-20 23:18:41 -07001919 {
1920 sm->num_workers = tr->count;
1921 sm->first_worker_index = tr->first_index;
1922 }
Matus Fabian475f0552016-10-19 06:17:52 -07001923 }
1924
Matus Fabian7801ca22017-08-03 00:58:05 -07001925 vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1926
Matus Fabian475f0552016-10-19 06:17:52 -07001927 /* Use all available workers by default */
1928 if (sm->num_workers > 1)
1929 {
Matus Fabianab395ec2018-09-20 23:18:41 -07001930 for (i = 0; i < sm->num_workers; i++)
1931 bitmap = clib_bitmap_set (bitmap, i, 1);
1932 snat_set_workers (bitmap);
Matus Fabian475f0552016-10-19 06:17:52 -07001933 clib_bitmap_free (bitmap);
1934 }
Matus Fabian7801ca22017-08-03 00:58:05 -07001935 else
1936 {
1937 sm->per_thread_data[0].snat_thread_index = 0;
1938 }
Dave Barach20c02cb2016-06-26 10:42:08 -04001939
Matus Fabianab395ec2018-09-20 23:18:41 -07001940 error = snat_api_init (vm, sm);
Matus Fabian08ce4322017-06-19 05:28:27 -07001941 if (error)
1942 return error;
Dave Barach20c02cb2016-06-26 10:42:08 -04001943
Dave Barachcab65ec2017-01-11 13:01:14 -05001944 /* Set up the interface address add/del callback */
1945 cb4.function = snat_ip4_add_del_interface_address_cb;
1946 cb4.function_opaque = 0;
1947
1948 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1949
Matus Fabian4772e7a2018-04-04 00:38:02 -07001950 cb4.function = nat_ip4_add_del_addr_only_sm_cb;
1951 cb4.function_opaque = 0;
1952
1953 vec_add1 (im->add_del_interface_address_callbacks, cb4);
1954
Juraj Slobodacba69362017-12-19 02:09:32 +01001955 nat_dpo_module_init ();
1956
Matus Fabianeea28d72017-01-13 04:15:54 -08001957 /* Init IPFIX logging */
Matus Fabianab395ec2018-09-20 23:18:41 -07001958 snat_ipfix_logging_init (vm);
Matus Fabianeea28d72017-01-13 04:15:54 -08001959
Matus Fabianefcd1e92017-08-15 06:59:19 -07001960 /* Init NAT64 */
Matus Fabianab395ec2018-09-20 23:18:41 -07001961 error = nat64_init (vm);
Matus Fabianefcd1e92017-08-15 06:59:19 -07001962 if (error)
1963 return error;
Matus Fabian06596c52017-06-06 04:53:28 -07001964
Matus Fabianab395ec2018-09-20 23:18:41 -07001965 dslite_init (vm);
Matus Fabian8ebe6252017-11-06 05:04:53 -08001966
Matus Fabianab395ec2018-09-20 23:18:41 -07001967 nat66_init ();
Matus Fabianf2a23cc2018-01-22 03:41:53 -08001968
Matus Fabianefcd1e92017-08-15 06:59:19 -07001969 /* Init virtual fragmenentation reassembly */
Matus Fabianab395ec2018-09-20 23:18:41 -07001970 return nat_reass_init (vm);
Dave Barach20c02cb2016-06-26 10:42:08 -04001971}
1972
1973VLIB_INIT_FUNCTION (snat_init);
1974
Matus Fabianab395ec2018-09-20 23:18:41 -07001975void
1976snat_free_outside_address_and_port (snat_address_t * addresses,
1977 u32 thread_index, snat_session_key_t * k)
Dave Barach20c02cb2016-06-26 10:42:08 -04001978{
1979 snat_address_t *a;
shubing guo762a4932018-08-13 17:16:46 +08001980 u32 address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04001981 u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
Matus Fabian2ba92e32017-08-21 07:05:03 -07001982
Matus Fabianab395ec2018-09-20 23:18:41 -07001983 for (address_index = 0; address_index < vec_len (addresses);
1984 address_index++)
shubing guo762a4932018-08-13 17:16:46 +08001985 {
1986 if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
Matus Fabianab395ec2018-09-20 23:18:41 -07001987 break;
shubing guo762a4932018-08-13 17:16:46 +08001988 }
1989
Matus Fabian8ebe6252017-11-06 05:04:53 -08001990 ASSERT (address_index < vec_len (addresses));
Dave Barach20c02cb2016-06-26 10:42:08 -04001991
Matus Fabian8ebe6252017-11-06 05:04:53 -08001992 a = addresses + address_index;
Dave Barach20c02cb2016-06-26 10:42:08 -04001993
Matus Fabian09d96f42017-02-02 01:43:00 -08001994 switch (k->protocol)
1995 {
1996#define _(N, i, n, s) \
1997 case SNAT_PROTOCOL_##N: \
1998 ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1999 port_host_byte_order) == 1); \
2000 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2001 port_host_byte_order, 0); \
2002 a->busy_##n##_ports--; \
Matus Fabian624b8d92017-09-12 04:15:30 -07002003 a->busy_##n##_ports_per_thread[thread_index]--; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002004 break;
2005 foreach_snat_protocol
2006#undef _
2007 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002008 nat_log_info ("unknown protocol");
Matus Fabian09d96f42017-02-02 01:43:00 -08002009 return;
2010 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07002011}
Dave Barach20c02cb2016-06-26 10:42:08 -04002012
Matus Fabianab395ec2018-09-20 23:18:41 -07002013int
2014snat_static_mapping_match (snat_main_t * sm,
2015 snat_session_key_t match,
2016 snat_session_key_t * mapping,
2017 u8 by_external,
2018 u8 * is_addr_only,
2019 twice_nat_type_t * twice_nat,
2020 lb_nat_type_t * lb, ip4_address_t * ext_host_addr)
Matus Fabiandb649882016-08-26 05:45:27 -07002021{
2022 clib_bihash_kv_8_8_t kv, value;
2023 snat_static_mapping_t *m;
Matus Fabian09d96f42017-02-02 01:43:00 -08002024 snat_session_key_t m_key;
Matus Fabiandb649882016-08-26 05:45:27 -07002025 clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
Matus Fabian704018c2017-09-04 02:17:18 -07002026 u32 rand, lo = 0, hi, mid;
Matus Fabianea5b5be2018-09-03 05:02:23 -07002027 u8 backend_index;
Matus Fabiandb649882016-08-26 05:45:27 -07002028
Matus Fabian8008d7c2018-07-09 01:34:20 -07002029 m_key.fib_index = match.fib_index;
Matus Fabiandb649882016-08-26 05:45:27 -07002030 if (by_external)
Matus Fabian8008d7c2018-07-09 01:34:20 -07002031 {
2032 mapping_hash = &sm->static_mapping_by_external;
2033 m_key.fib_index = 0;
2034 }
Matus Fabiandb649882016-08-26 05:45:27 -07002035
2036 m_key.addr = match.addr;
2037 m_key.port = clib_net_to_host_u16 (match.port);
Matus Fabian09d96f42017-02-02 01:43:00 -08002038 m_key.protocol = match.protocol;
Matus Fabiandb649882016-08-26 05:45:27 -07002039
2040 kv.key = m_key.as_u64;
2041
2042 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2043 {
2044 /* Try address only mapping */
2045 m_key.port = 0;
Matus Fabian09d96f42017-02-02 01:43:00 -08002046 m_key.protocol = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07002047 kv.key = m_key.as_u64;
2048 if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
Matus Fabianab395ec2018-09-20 23:18:41 -07002049 return 1;
Matus Fabiandb649882016-08-26 05:45:27 -07002050 }
2051
2052 m = pool_elt_at_index (sm->static_mappings, value.value);
2053
2054 if (by_external)
2055 {
Matus Fabian704018c2017-09-04 02:17:18 -07002056 if (vec_len (m->locals))
Matus Fabianab395ec2018-09-20 23:18:41 -07002057 {
2058 if (PREDICT_FALSE (lb != 0))
2059 *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2060 if (m->affinity)
2061 {
2062 if (nat_affinity_find_and_lock (ext_host_addr[0], match.addr,
2063 match.protocol, match.port,
2064 &backend_index))
2065 goto get_local;
Matus Fabianea5b5be2018-09-03 05:02:23 -07002066
Matus Fabianab395ec2018-09-20 23:18:41 -07002067 mapping->addr = m->locals[backend_index].addr;
2068 mapping->port =
2069 clib_host_to_net_u16 (m->locals[backend_index].port);
2070 mapping->fib_index = m->locals[backend_index].fib_index;
2071 goto end;
2072 }
2073 get_local:
2074 hi = vec_len (m->locals) - 1;
2075 rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2076 while (lo < hi)
2077 {
2078 mid = ((hi - lo) >> 1) + lo;
2079 (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2080 }
2081 if (!(m->locals[lo].prefix >= rand))
2082 return 1;
2083 if (PREDICT_FALSE (sm->num_workers > 1))
2084 {
2085 ip4_header_t ip = {
2086 .src_address = m->locals[lo].addr,
2087 };
2088 if (sm->worker_in2out_cb (&ip, m->fib_index) !=
2089 vlib_get_thread_index ())
2090 goto get_local;
2091 }
2092 mapping->addr = m->locals[lo].addr;
2093 mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2094 mapping->fib_index = m->locals[lo].fib_index;
2095 if (m->affinity)
2096 {
2097 if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2098 match.protocol, match.port,
2099 lo, m->affinity,
2100 m->affinity_per_service_list_head_index))
2101 nat_log_info ("create affinity record failed");
2102 }
2103 }
Matus Fabian704018c2017-09-04 02:17:18 -07002104 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002105 {
2106 if (PREDICT_FALSE (lb != 0))
2107 *lb = NO_LB_NAT;
2108 mapping->fib_index = m->fib_index;
2109 mapping->addr = m->local_addr;
2110 /* Address only mapping doesn't change port */
2111 mapping->port = m->addr_only ? match.port
2112 : clib_host_to_net_u16 (m->local_port);
2113 }
Matus Fabian704018c2017-09-04 02:17:18 -07002114 mapping->protocol = m->proto;
Matus Fabiandb649882016-08-26 05:45:27 -07002115 }
2116 else
2117 {
2118 mapping->addr = m->external_addr;
2119 /* Address only mapping doesn't change port */
2120 mapping->port = m->addr_only ? match.port
Matus Fabianab395ec2018-09-20 23:18:41 -07002121 : clib_host_to_net_u16 (m->external_port);
Matus Fabiandb649882016-08-26 05:45:27 -07002122 mapping->fib_index = sm->outside_fib_index;
2123 }
2124
Matus Fabianea5b5be2018-09-03 05:02:23 -07002125end:
Matus Fabianab395ec2018-09-20 23:18:41 -07002126 if (PREDICT_FALSE (is_addr_only != 0))
Juraj Slobodad3677682017-04-14 03:24:45 +02002127 *is_addr_only = m->addr_only;
2128
Matus Fabianab395ec2018-09-20 23:18:41 -07002129 if (PREDICT_FALSE (twice_nat != 0))
Matus Fabianb932d262017-12-18 05:38:24 -08002130 *twice_nat = m->twice_nat;
2131
Matus Fabiandb649882016-08-26 05:45:27 -07002132 return 0;
2133}
2134
Matus Fabian7801ca22017-08-03 00:58:05 -07002135static_always_inline u16
Matus Fabian8ebe6252017-11-06 05:04:53 -08002136snat_random_port (u16 min, u16 max)
Matus Fabian7801ca22017-08-03 00:58:05 -07002137{
Matus Fabian8ebe6252017-11-06 05:04:53 -08002138 snat_main_t *sm = &snat_main;
Matus Fabian7801ca22017-08-03 00:58:05 -07002139 return min + random_u32 (&sm->random_seed) /
Matus Fabianab395ec2018-09-20 23:18:41 -07002140 (random_u32_max () / (max - min + 1) + 1);
Matus Fabian7801ca22017-08-03 00:58:05 -07002141}
2142
Matus Fabian27697102017-11-09 01:43:47 -08002143int
2144snat_alloc_outside_address_and_port (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002145 u32 fib_index,
2146 u32 thread_index,
2147 snat_session_key_t * k,
2148 u16 port_per_thread,
2149 u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002150{
2151 snat_main_t *sm = &snat_main;
2152
Matus Fabianab395ec2018-09-20 23:18:41 -07002153 return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2154 port_per_thread, snat_thread_index);
Matus Fabian27697102017-11-09 01:43:47 -08002155}
2156
2157static int
2158nat_alloc_addr_and_port_default (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002159 u32 fib_index,
2160 u32 thread_index,
2161 snat_session_key_t * k,
2162 u16 port_per_thread, u32 snat_thread_index)
Dave Barach20c02cb2016-06-26 10:42:08 -04002163{
Matus Fabianab395ec2018-09-20 23:18:41 -07002164 int i;
Matus Fabian51e759f2017-12-07 23:22:51 -08002165 snat_address_t *a, *ga = 0;
Dave Barach20c02cb2016-06-26 10:42:08 -04002166 u32 portnum;
2167
Matus Fabian8ebe6252017-11-06 05:04:53 -08002168 for (i = 0; i < vec_len (addresses); i++)
Dave Barach20c02cb2016-06-26 10:42:08 -04002169 {
Matus Fabian8ebe6252017-11-06 05:04:53 -08002170 a = addresses + i;
Matus Fabian09d96f42017-02-02 01:43:00 -08002171 switch (k->protocol)
Matus Fabianab395ec2018-09-20 23:18:41 -07002172 {
Matus Fabian09d96f42017-02-02 01:43:00 -08002173#define _(N, j, n, s) \
2174 case SNAT_PROTOCOL_##N: \
Matus Fabian8ebe6252017-11-06 05:04:53 -08002175 if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002176 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002177 if (a->fib_index == fib_index) \
Matus Fabian09d96f42017-02-02 01:43:00 -08002178 { \
Matus Fabian51e759f2017-12-07 23:22:51 -08002179 while (1) \
2180 { \
2181 portnum = (port_per_thread * \
2182 snat_thread_index) + \
2183 snat_random_port(1, port_per_thread) + 1024; \
2184 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2185 continue; \
2186 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2187 a->busy_##n##_ports_per_thread[thread_index]++; \
2188 a->busy_##n##_ports++; \
2189 k->addr = a->addr; \
2190 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002191 return 0; \
2192 } \
2193 } \
2194 else if (a->fib_index == ~0) \
2195 { \
2196 ga = a; \
Matus Fabian09d96f42017-02-02 01:43:00 -08002197 } \
2198 } \
2199 break;
Matus Fabianab395ec2018-09-20 23:18:41 -07002200 foreach_snat_protocol
Matus Fabian09d96f42017-02-02 01:43:00 -08002201#undef _
Matus Fabianab395ec2018-09-20 23:18:41 -07002202 default:
2203 nat_log_info ("unknown protocol");
2204 return 1;
2205 }
Matus Fabian09d96f42017-02-02 01:43:00 -08002206
Dave Barach20c02cb2016-06-26 10:42:08 -04002207 }
Matus Fabian51e759f2017-12-07 23:22:51 -08002208
2209 if (ga)
2210 {
2211 a = ga;
2212 switch (k->protocol)
2213 {
2214#define _(N, j, n, s) \
2215 case SNAT_PROTOCOL_##N: \
2216 while (1) \
2217 { \
2218 portnum = (port_per_thread * \
2219 snat_thread_index) + \
2220 snat_random_port(1, port_per_thread) + 1024; \
2221 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2222 continue; \
2223 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2224 a->busy_##n##_ports_per_thread[thread_index]++; \
2225 a->busy_##n##_ports++; \
2226 k->addr = a->addr; \
2227 k->port = clib_host_to_net_u16(portnum); \
Matus Fabian51e759f2017-12-07 23:22:51 -08002228 return 0; \
2229 }
2230 break;
2231 foreach_snat_protocol
2232#undef _
2233 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002234 nat_log_info ("unknown protocol");
Matus Fabian51e759f2017-12-07 23:22:51 -08002235 return 1;
2236 }
2237 }
2238
Dave Barach20c02cb2016-06-26 10:42:08 -04002239 /* Totally out of translations to use... */
Matus Fabianab395ec2018-09-20 23:18:41 -07002240 snat_ipfix_logging_addresses_exhausted (0);
Dave Barach20c02cb2016-06-26 10:42:08 -04002241 return 1;
2242}
2243
Matus Fabian27697102017-11-09 01:43:47 -08002244static int
2245nat_alloc_addr_and_port_mape (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002246 u32 fib_index,
2247 u32 thread_index,
2248 snat_session_key_t * k,
2249 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian27697102017-11-09 01:43:47 -08002250{
2251 snat_main_t *sm = &snat_main;
2252 snat_address_t *a = addresses;
2253 u16 m, ports, portnum, A, j;
2254 m = 16 - (sm->psid_offset + sm->psid_length);
2255 ports = (1 << (16 - sm->psid_length)) - (1 << m);
2256
2257 if (!vec_len (addresses))
2258 goto exhausted;
2259
2260 switch (k->protocol)
2261 {
2262#define _(N, i, n, s) \
2263 case SNAT_PROTOCOL_##N: \
2264 if (a->busy_##n##_ports < ports) \
2265 { \
2266 while (1) \
2267 { \
2268 A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2269 j = snat_random_port(0, pow2_mask(m)); \
2270 portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2271 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2272 continue; \
2273 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2274 a->busy_##n##_ports++; \
2275 k->addr = a->addr; \
2276 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian27697102017-11-09 01:43:47 -08002277 return 0; \
2278 } \
2279 } \
2280 break;
2281 foreach_snat_protocol
2282#undef _
2283 default:
Matus Fabian229c1aa2018-05-28 04:09:52 -07002284 nat_log_info ("unknown protocol");
Matus Fabian27697102017-11-09 01:43:47 -08002285 return 1;
2286 }
2287
2288exhausted:
2289 /* Totally out of translations to use... */
Matus Fabianab395ec2018-09-20 23:18:41 -07002290 snat_ipfix_logging_addresses_exhausted (0);
Matus Fabian27697102017-11-09 01:43:47 -08002291 return 1;
2292}
Dave Barach20c02cb2016-06-26 10:42:08 -04002293
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002294static int
2295nat_alloc_addr_and_port_range (snat_address_t * addresses,
Matus Fabianab395ec2018-09-20 23:18:41 -07002296 u32 fib_index,
2297 u32 thread_index,
2298 snat_session_key_t * k,
2299 u16 port_per_thread, u32 snat_thread_index)
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002300{
2301 snat_main_t *sm = &snat_main;
2302 snat_address_t *a = addresses;
2303 u16 portnum, ports;
2304
2305 ports = sm->end_port - sm->start_port + 1;
2306
2307 if (!vec_len (addresses))
2308 goto exhausted;
2309
2310 switch (k->protocol)
2311 {
2312#define _(N, i, n, s) \
2313 case SNAT_PROTOCOL_##N: \
2314 if (a->busy_##n##_ports < ports) \
2315 { \
2316 while (1) \
2317 { \
2318 portnum = snat_random_port(sm->start_port, sm->end_port); \
2319 if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2320 continue; \
2321 clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2322 a->busy_##n##_ports++; \
2323 k->addr = a->addr; \
2324 k->port = clib_host_to_net_u16 (portnum); \
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002325 return 0; \
2326 } \
2327 } \
2328 break;
2329 foreach_snat_protocol
2330#undef _
2331 default:
2332 nat_log_info ("unknown protocol");
2333 return 1;
2334 }
2335
2336exhausted:
2337 /* Totally out of translations to use... */
Matus Fabianab395ec2018-09-20 23:18:41 -07002338 snat_ipfix_logging_addresses_exhausted (0);
Matus Fabian5d28c7a2018-09-04 03:55:45 -07002339 return 1;
2340}
2341
Juraj Slobodacba69362017-12-19 02:09:32 +01002342void
2343nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2344{
2345 dpo_id_t dpo_v4 = DPO_INVALID;
2346 fib_prefix_t pfx = {
2347 .fp_proto = FIB_PROTOCOL_IP4,
2348 .fp_len = 32,
2349 .fp_addr.ip4.as_u32 = addr.as_u32,
2350 };
2351
2352 if (is_add)
2353 {
2354 nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2355 fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
Matus Fabianab395ec2018-09-20 23:18:41 -07002356 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
Juraj Slobodacba69362017-12-19 02:09:32 +01002357 dpo_reset (&dpo_v4);
2358 }
2359 else
2360 {
2361 fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2362 }
2363}
2364
Matus Fabian229c1aa2018-05-28 04:09:52 -07002365u8 *
2366format_session_kvp (u8 * s, va_list * args)
2367{
2368 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2369 snat_session_key_t k;
2370
2371 k.as_u64 = v->key;
2372
2373 s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2374
2375 return s;
2376}
2377
2378u8 *
2379format_static_mapping_kvp (u8 * s, va_list * args)
2380{
2381 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2382 snat_session_key_t k;
2383
2384 k.as_u64 = v->key;
2385
Matus Fabian878c6462018-08-23 00:33:35 -07002386 s = format (s, "%U static-mapping-index %llu",
Matus Fabianab395ec2018-09-20 23:18:41 -07002387 format_static_mapping_key, &k, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002388
2389 return s;
2390}
2391
2392u8 *
2393format_user_kvp (u8 * s, va_list * args)
2394{
2395 clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2396 snat_user_key_t k;
2397
2398 k.as_u64 = v->key;
2399
2400 s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07002401 k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002402
2403 return s;
2404}
2405
2406u8 *
2407format_ed_session_kvp (u8 * s, va_list * args)
2408{
2409 clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2410 nat_ed_ses_key_t k;
2411
2412 k.as_u64[0] = v->key[0];
2413 k.as_u64[1] = v->key[1];
2414
Matus Fabianab395ec2018-09-20 23:18:41 -07002415 s =
2416 format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2417 format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2418 format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2419 format_ip_protocol, k.proto, k.fib_index, v->value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002420
2421 return s;
2422}
2423
Matus Fabian066f0342017-02-10 03:48:01 -08002424static u32
2425snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2426{
2427 snat_main_t *sm = &snat_main;
Matus Fabian066f0342017-02-10 03:48:01 -08002428 u32 next_worker_index = 0;
Matus Fabian7865b5c2017-09-26 01:23:01 -07002429 u32 hash;
Matus Fabian066f0342017-02-10 03:48:01 -08002430
Matus Fabian7865b5c2017-09-26 01:23:01 -07002431 next_worker_index = sm->first_worker_index;
2432 hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
Matus Fabianab395ec2018-09-20 23:18:41 -07002433 (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
Matus Fabian066f0342017-02-10 03:48:01 -08002434
Matus Fabian7865b5c2017-09-26 01:23:01 -07002435 if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2436 next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
Matus Fabian066f0342017-02-10 03:48:01 -08002437 else
Matus Fabian7865b5c2017-09-26 01:23:01 -07002438 next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
Matus Fabian066f0342017-02-10 03:48:01 -08002439
2440 return next_worker_index;
2441}
2442
2443static u32
2444snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2445{
2446 snat_main_t *sm = &snat_main;
Matus Fabianed3c1602017-09-21 05:07:12 -07002447 udp_header_t *udp;
2448 u16 port;
2449 snat_session_key_t m_key;
2450 clib_bihash_kv_8_8_t kv, value;
2451 snat_static_mapping_t *m;
Matus Fabianed3c1602017-09-21 05:07:12 -07002452 u32 proto;
Matus Fabian10491392018-01-05 05:03:35 -08002453 u32 next_worker_index = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08002454
Matus Fabianed3c1602017-09-21 05:07:12 -07002455 /* first try static mappings without port */
2456 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
Matus Fabian066f0342017-02-10 03:48:01 -08002457 {
Matus Fabianed3c1602017-09-21 05:07:12 -07002458 m_key.addr = ip0->dst_address;
2459 m_key.port = 0;
2460 m_key.protocol = 0;
2461 m_key.fib_index = rx_fib_index0;
2462 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07002463 if (!clib_bihash_search_8_8
2464 (&sm->static_mapping_by_external, &kv, &value))
2465 {
2466 m = pool_elt_at_index (sm->static_mappings, value.value);
2467 return m->workers[0];
2468 }
Matus Fabian066f0342017-02-10 03:48:01 -08002469 }
2470
Matus Fabianed3c1602017-09-21 05:07:12 -07002471 proto = ip_proto_to_snat_proto (ip0->protocol);
2472 udp = ip4_next_header (ip0);
2473 port = udp->dst_port;
Matus Fabian066f0342017-02-10 03:48:01 -08002474
Matus Fabian51e759f2017-12-07 23:22:51 -08002475 if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2476 {
2477 if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2478 return vlib_get_thread_index ();
2479
2480 if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2481 {
2482 nat_reass_ip4_t *reass;
2483
2484 reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2485 ip0->fragment_id, ip0->protocol);
2486
2487 if (reass && (reass->thread_index != (u32) ~ 0))
Matus Fabianab395ec2018-09-20 23:18:41 -07002488 return reass->thread_index;
Matus Fabian51e759f2017-12-07 23:22:51 -08002489 else
2490 return vlib_get_thread_index ();
2491 }
2492 }
2493
Matus Fabianed3c1602017-09-21 05:07:12 -07002494 /* unknown protocol */
2495 if (PREDICT_FALSE (proto == ~0))
Matus Fabian066f0342017-02-10 03:48:01 -08002496 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002497 /* use current thread */
Matus Fabianed3c1602017-09-21 05:07:12 -07002498 return vlib_get_thread_index ();
2499 }
2500
2501 if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2502 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002503 icmp46_header_t *icmp = (icmp46_header_t *) udp;
2504 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Matus Fabianed3c1602017-09-21 05:07:12 -07002505 if (!icmp_is_error_message (icmp))
Matus Fabianab395ec2018-09-20 23:18:41 -07002506 port = echo->identifier;
Matus Fabian066f0342017-02-10 03:48:01 -08002507 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002508 {
2509 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2510 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2511 void *l4_header = ip4_next_header (inner_ip);
2512 switch (proto)
2513 {
2514 case SNAT_PROTOCOL_ICMP:
2515 icmp = (icmp46_header_t *) l4_header;
2516 echo = (icmp_echo_header_t *) (icmp + 1);
2517 port = echo->identifier;
2518 break;
2519 case SNAT_PROTOCOL_UDP:
2520 case SNAT_PROTOCOL_TCP:
2521 port = ((tcp_udp_header_t *) l4_header)->src_port;
2522 break;
2523 default:
2524 return vlib_get_thread_index ();
2525 }
2526 }
Matus Fabian066f0342017-02-10 03:48:01 -08002527 }
Matus Fabian066f0342017-02-10 03:48:01 -08002528
Matus Fabianed3c1602017-09-21 05:07:12 -07002529 /* try static mappings with port */
2530 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2531 {
2532 m_key.addr = ip0->dst_address;
2533 m_key.port = clib_net_to_host_u16 (port);
2534 m_key.protocol = proto;
2535 m_key.fib_index = rx_fib_index0;
2536 kv.key = m_key.as_u64;
Matus Fabianab395ec2018-09-20 23:18:41 -07002537 if (!clib_bihash_search_8_8
2538 (&sm->static_mapping_by_external, &kv, &value))
2539 {
2540 m = pool_elt_at_index (sm->static_mappings, value.value);
2541 return m->workers[0];
2542 }
Matus Fabianed3c1602017-09-21 05:07:12 -07002543 }
2544
2545 /* worker by outside port */
Matus Fabian10491392018-01-05 05:03:35 -08002546 next_worker_index = sm->first_worker_index;
2547 next_worker_index +=
2548 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2549 return next_worker_index;
Matus Fabian066f0342017-02-10 03:48:01 -08002550}
2551
Matus Fabiana6110b62018-06-13 05:39:07 -07002552static u32
2553nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2554{
2555 snat_main_t *sm = &snat_main;
2556 clib_bihash_kv_8_8_t kv, value;
2557 u32 proto, next_worker_index = 0;
2558 udp_header_t *udp;
2559 u16 port;
2560 snat_static_mapping_t *m;
2561 u32 hash;
2562
2563 /* first try static mappings without port */
2564 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2565 {
2566 make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
Matus Fabianab395ec2018-09-20 23:18:41 -07002567 if (!clib_bihash_search_8_8
2568 (&sm->static_mapping_by_external, &kv, &value))
2569 {
2570 m = pool_elt_at_index (sm->static_mappings, value.value);
2571 return m->workers[0];
2572 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002573 }
2574
2575 proto = ip_proto_to_snat_proto (ip->protocol);
2576
2577 /* unknown protocol */
2578 if (PREDICT_FALSE (proto == ~0))
2579 {
2580 /* use current thread */
2581 return vlib_get_thread_index ();
2582 }
2583
2584 udp = ip4_next_header (ip);
2585 port = udp->dst_port;
2586
2587 if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2588 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002589 icmp46_header_t *icmp = (icmp46_header_t *) udp;
2590 icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
Matus Fabiana6110b62018-06-13 05:39:07 -07002591 if (!icmp_is_error_message (icmp))
Matus Fabianab395ec2018-09-20 23:18:41 -07002592 port = echo->identifier;
Matus Fabiana6110b62018-06-13 05:39:07 -07002593 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002594 {
2595 ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2596 proto = ip_proto_to_snat_proto (inner_ip->protocol);
2597 void *l4_header = ip4_next_header (inner_ip);
2598 switch (proto)
2599 {
2600 case SNAT_PROTOCOL_ICMP:
2601 icmp = (icmp46_header_t *) l4_header;
2602 echo = (icmp_echo_header_t *) (icmp + 1);
2603 port = echo->identifier;
2604 break;
2605 case SNAT_PROTOCOL_UDP:
2606 case SNAT_PROTOCOL_TCP:
2607 port = ((tcp_udp_header_t *) l4_header)->src_port;
2608 break;
2609 default:
2610 return vlib_get_thread_index ();
2611 }
2612 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002613 }
2614
2615 /* try static mappings with port */
2616 if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2617 {
2618 make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
Matus Fabianab395ec2018-09-20 23:18:41 -07002619 clib_net_to_host_u16 (port));
2620 if (!clib_bihash_search_8_8
2621 (&sm->static_mapping_by_external, &kv, &value))
2622 {
2623 m = pool_elt_at_index (sm->static_mappings, value.value);
2624 if (!vec_len (m->locals))
2625 return m->workers[0];
Matus Fabiana6110b62018-06-13 05:39:07 -07002626
Matus Fabianab395ec2018-09-20 23:18:41 -07002627 hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2628 (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
Matus Fabiana6110b62018-06-13 05:39:07 -07002629
Matus Fabianab395ec2018-09-20 23:18:41 -07002630 if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
2631 return m->workers[hash & (_vec_len (m->workers) - 1)];
2632 else
2633 return m->workers[hash % _vec_len (m->workers)];
2634 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002635 }
2636
2637 /* worker by outside port */
2638 next_worker_index = sm->first_worker_index;
2639 next_worker_index +=
2640 sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2641
2642 return next_worker_index;
2643}
2644
Matus Fabianeea28d72017-01-13 04:15:54 -08002645static clib_error_t *
Dave Barach20c02cb2016-06-26 10:42:08 -04002646snat_config (vlib_main_t * vm, unformat_input_t * input)
2647{
Matus Fabianab395ec2018-09-20 23:18:41 -07002648 snat_main_t *sm = &snat_main;
2649 nat66_main_t *nm = &nat66_main;
Dave Barach20c02cb2016-06-26 10:42:08 -04002650 u32 translation_buckets = 1024;
Matus Fabianab395ec2018-09-20 23:18:41 -07002651 u32 translation_memory_size = 128 << 20;
Dave Barach20c02cb2016-06-26 10:42:08 -04002652 u32 user_buckets = 128;
Matus Fabianab395ec2018-09-20 23:18:41 -07002653 u32 user_memory_size = 64 << 20;
Dave Barach20c02cb2016-06-26 10:42:08 -04002654 u32 max_translations_per_user = 100;
2655 u32 outside_vrf_id = 0;
Juraj Sloboda9341e342018-04-13 12:00:46 +02002656 u32 outside_ip6_vrf_id = 0;
Matus Fabiandb649882016-08-26 05:45:27 -07002657 u32 inside_vrf_id = 0;
2658 u32 static_mapping_buckets = 1024;
Matus Fabianab395ec2018-09-20 23:18:41 -07002659 u32 static_mapping_memory_size = 64 << 20;
Matus Fabian51e759f2017-12-07 23:22:51 -08002660 u32 nat64_bib_buckets = 1024;
2661 u32 nat64_bib_memory_size = 128 << 20;
2662 u32 nat64_st_buckets = 2048;
2663 u32 nat64_st_memory_size = 256 << 20;
Matus Fabiandb649882016-08-26 05:45:27 -07002664 u8 static_mapping_only = 0;
2665 u8 static_mapping_connection_tracking = 0;
Matus Fabian092b3cd2017-09-19 05:42:38 -07002666 snat_main_per_thread_data_t *tsm;
Matus Fabianab395ec2018-09-20 23:18:41 -07002667 dslite_main_t *dm = &dslite_main;
Dave Barach20c02cb2016-06-26 10:42:08 -04002668
Matus Fabian066f0342017-02-10 03:48:01 -08002669 sm->deterministic = 0;
Juraj Slobodacba69362017-12-19 02:09:32 +01002670 sm->out2in_dpo = 0;
Matus Fabiana6110b62018-06-13 05:39:07 -07002671 sm->endpoint_dependent = 0;
Matus Fabian066f0342017-02-10 03:48:01 -08002672
Dave Barach20c02cb2016-06-26 10:42:08 -04002673 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2674 {
Matus Fabianab395ec2018-09-20 23:18:41 -07002675 if (unformat
2676 (input, "translation hash buckets %d", &translation_buckets))
2677 ;
Dave Barach20c02cb2016-06-26 10:42:08 -04002678 else if (unformat (input, "translation hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07002679 &translation_memory_size));
Dave Barach20c02cb2016-06-26 10:42:08 -04002680 else if (unformat (input, "user hash buckets %d", &user_buckets))
Matus Fabianab395ec2018-09-20 23:18:41 -07002681 ;
2682 else if (unformat (input, "user hash memory %d", &user_memory_size))
2683 ;
Dave Barach20c02cb2016-06-26 10:42:08 -04002684 else if (unformat (input, "max translations per user %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07002685 &max_translations_per_user))
2686 ;
2687 else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
2688 ;
2689 else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
2690 ;
2691 else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
2692 ;
Matus Fabiandb649882016-08-26 05:45:27 -07002693 else if (unformat (input, "static mapping only"))
Matus Fabianab395ec2018-09-20 23:18:41 -07002694 {
2695 static_mapping_only = 1;
2696 if (unformat (input, "connection tracking"))
2697 static_mapping_connection_tracking = 1;
2698 }
Matus Fabian066f0342017-02-10 03:48:01 -08002699 else if (unformat (input, "deterministic"))
Matus Fabianab395ec2018-09-20 23:18:41 -07002700 sm->deterministic = 1;
Matus Fabian51e759f2017-12-07 23:22:51 -08002701 else if (unformat (input, "nat64 bib hash buckets %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07002702 &nat64_bib_buckets))
2703 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08002704 else if (unformat (input, "nat64 bib hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07002705 &nat64_bib_memory_size))
2706 ;
2707 else
2708 if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2709 ;
Matus Fabian51e759f2017-12-07 23:22:51 -08002710 else if (unformat (input, "nat64 st hash memory %d",
Matus Fabianab395ec2018-09-20 23:18:41 -07002711 &nat64_st_memory_size))
2712 ;
Juraj Slobodacba69362017-12-19 02:09:32 +01002713 else if (unformat (input, "out2in dpo"))
Matus Fabianab395ec2018-09-20 23:18:41 -07002714 sm->out2in_dpo = 1;
Juraj Slobodac5c6a332018-01-09 16:08:32 +01002715 else if (unformat (input, "dslite ce"))
Matus Fabianab395ec2018-09-20 23:18:41 -07002716 dslite_set_ce (dm, 1);
Matus Fabiana6110b62018-06-13 05:39:07 -07002717 else if (unformat (input, "endpoint-dependent"))
Matus Fabianab395ec2018-09-20 23:18:41 -07002718 sm->endpoint_dependent = 1;
Matus Fabian066f0342017-02-10 03:48:01 -08002719 else
Matus Fabiandb649882016-08-26 05:45:27 -07002720 return clib_error_return (0, "unknown input '%U'",
Dave Barach20c02cb2016-06-26 10:42:08 -04002721 format_unformat_error, input);
2722 }
2723
Matus Fabian69ce30d2018-08-22 01:27:10 -07002724 if (sm->deterministic && sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002725 return clib_error_return (0,
2726 "deterministic and endpoint-dependent modes are mutually exclusive");
Matus Fabian69ce30d2018-08-22 01:27:10 -07002727
2728 if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07002729 return clib_error_return (0,
2730 "static mapping only mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07002731
2732 if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
Matus Fabianab395ec2018-09-20 23:18:41 -07002733 return clib_error_return (0,
2734 "out2in dpo mode available only for simple nat");
Matus Fabian69ce30d2018-08-22 01:27:10 -07002735
Dave Barach20c02cb2016-06-26 10:42:08 -04002736 /* for show commands, etc. */
2737 sm->translation_buckets = translation_buckets;
2738 sm->translation_memory_size = translation_memory_size;
Matus Fabian41fef502017-09-22 02:43:05 -07002739 /* do not exceed load factor 10 */
2740 sm->max_translations = 10 * translation_buckets;
Dave Barach20c02cb2016-06-26 10:42:08 -04002741 sm->user_buckets = user_buckets;
2742 sm->user_memory_size = user_memory_size;
2743 sm->max_translations_per_user = max_translations_per_user;
2744 sm->outside_vrf_id = outside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08002745 sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07002746 outside_vrf_id,
2747 FIB_SOURCE_PLUGIN_HI);
Juraj Sloboda9341e342018-04-13 12:00:46 +02002748 nm->outside_vrf_id = outside_ip6_vrf_id;
2749 nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
Matus Fabianab395ec2018-09-20 23:18:41 -07002750 outside_ip6_vrf_id,
2751 FIB_SOURCE_PLUGIN_HI);
Matus Fabiandb649882016-08-26 05:45:27 -07002752 sm->inside_vrf_id = inside_vrf_id;
Matus Fabian31c31aa2017-02-05 22:45:57 -08002753 sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
Matus Fabianab395ec2018-09-20 23:18:41 -07002754 inside_vrf_id,
2755 FIB_SOURCE_PLUGIN_HI);
Matus Fabiandb649882016-08-26 05:45:27 -07002756 sm->static_mapping_only = static_mapping_only;
2757 sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
Dave Barach20c02cb2016-06-26 10:42:08 -04002758
Matus Fabianab395ec2018-09-20 23:18:41 -07002759 nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2760 nat64_st_memory_size);
Matus Fabian51e759f2017-12-07 23:22:51 -08002761
Matus Fabian066f0342017-02-10 03:48:01 -08002762 if (sm->deterministic)
Matus Fabiandb649882016-08-26 05:45:27 -07002763 {
Matus Fabian066f0342017-02-10 03:48:01 -08002764 sm->in2out_node_index = snat_det_in2out_node.index;
Matus Fabian93d84c92017-07-19 08:06:01 -07002765 sm->in2out_output_node_index = ~0;
Matus Fabian066f0342017-02-10 03:48:01 -08002766 sm->out2in_node_index = snat_det_out2in_node.index;
Juraj Sloboda7a1bde02017-04-03 08:43:58 +02002767 sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2768 sm->icmp_match_out2in_cb = icmp_match_out2in_det;
Matus Fabiandb649882016-08-26 05:45:27 -07002769 }
Matus Fabian066f0342017-02-10 03:48:01 -08002770 else
2771 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002772 if (sm->endpoint_dependent)
Matus Fabianab395ec2018-09-20 23:18:41 -07002773 {
2774 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2775 sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
2776 sm->in2out_node_index = nat44_ed_in2out_node.index;
2777 sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
2778 sm->out2in_node_index = nat44_ed_out2in_node.index;
2779 sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
2780 sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
2781 nat_affinity_init (vm);
2782 }
Matus Fabiana6110b62018-06-13 05:39:07 -07002783 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002784 {
2785 sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2786 sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2787 sm->in2out_node_index = snat_in2out_node.index;
2788 sm->in2out_output_node_index = snat_in2out_output_node.index;
2789 sm->out2in_node_index = snat_out2in_node.index;
2790 sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2791 sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2792 }
Matus Fabian066f0342017-02-10 03:48:01 -08002793 if (!static_mapping_only ||
Matus Fabianab395ec2018-09-20 23:18:41 -07002794 (static_mapping_only && static_mapping_connection_tracking))
2795 {
2796 /* *INDENT-OFF* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07002797 vec_foreach (tsm, sm->per_thread_data)
2798 {
Matus Fabiana6110b62018-06-13 05:39:07 -07002799 if (sm->endpoint_dependent)
2800 {
2801 clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
2802 translation_buckets,
2803 translation_memory_size);
2804 clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
2805 format_ed_session_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07002806
Matus Fabiana6110b62018-06-13 05:39:07 -07002807 clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
2808 translation_buckets,
2809 translation_memory_size);
2810 clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
2811 format_ed_session_kvp);
2812 }
2813 else
2814 {
2815 clib_bihash_init_8_8 (&tsm->in2out, "in2out",
2816 translation_buckets,
2817 translation_memory_size);
2818 clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
2819 format_session_kvp);
2820
2821 clib_bihash_init_8_8 (&tsm->out2in, "out2in",
2822 translation_buckets,
2823 translation_memory_size);
2824 clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
2825 format_session_kvp);
2826 }
Matus Fabian092b3cd2017-09-19 05:42:38 -07002827
2828 clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2829 user_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002830 clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
2831 format_user_kvp);
Matus Fabian092b3cd2017-09-19 05:42:38 -07002832 }
Matus Fabianab395ec2018-09-20 23:18:41 -07002833 /* *INDENT-ON* */
Matus Fabian092b3cd2017-09-19 05:42:38 -07002834
Matus Fabianab395ec2018-09-20 23:18:41 -07002835 }
Juraj Sloboda557a71c2017-02-22 05:16:06 -08002836 else
Matus Fabianab395ec2018-09-20 23:18:41 -07002837 {
2838 sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2839 sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2840 }
Matus Fabian066f0342017-02-10 03:48:01 -08002841 clib_bihash_init_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07002842 "static_mapping_by_local", static_mapping_buckets,
2843 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002844 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
Matus Fabianab395ec2018-09-20 23:18:41 -07002845 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08002846
2847 clib_bihash_init_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07002848 "static_mapping_by_external",
2849 static_mapping_buckets,
2850 static_mapping_memory_size);
Matus Fabian229c1aa2018-05-28 04:09:52 -07002851 clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
Matus Fabianab395ec2018-09-20 23:18:41 -07002852 format_static_mapping_kvp);
Matus Fabian066f0342017-02-10 03:48:01 -08002853 }
2854
Dave Barach20c02cb2016-06-26 10:42:08 -04002855 return 0;
2856}
2857
Matus Fabian2ba92e32017-08-21 07:05:03 -07002858VLIB_CONFIG_FUNCTION (snat_config, "nat");
Dave Barach20c02cb2016-06-26 10:42:08 -04002859
Dave Barachcab65ec2017-01-11 13:01:14 -05002860static void
Matus Fabian4772e7a2018-04-04 00:38:02 -07002861nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002862 uword opaque,
2863 u32 sw_if_index,
2864 ip4_address_t * address,
2865 u32 address_length,
2866 u32 if_address_index, u32 is_delete)
Matus Fabian4772e7a2018-04-04 00:38:02 -07002867{
2868 snat_main_t *sm = &snat_main;
2869 snat_static_map_resolve_t *rp;
2870 snat_static_mapping_t *m;
2871 snat_session_key_t m_key;
2872 clib_bihash_kv_8_8_t kv, value;
2873 int i, rv;
2874 ip4_address_t l_addr;
2875
2876 for (i = 0; i < vec_len (sm->to_resolve); i++)
2877 {
2878 rp = sm->to_resolve + i;
2879 if (rp->addr_only == 0)
Matus Fabianab395ec2018-09-20 23:18:41 -07002880 continue;
Matus Fabian4772e7a2018-04-04 00:38:02 -07002881 if (rp->sw_if_index == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07002882 goto match;
Matus Fabian4772e7a2018-04-04 00:38:02 -07002883 }
2884
2885 return;
2886
2887match:
2888 m_key.addr.as_u32 = address->as_u32;
2889 m_key.port = rp->addr_only ? 0 : rp->e_port;
2890 m_key.protocol = rp->addr_only ? 0 : rp->proto;
2891 m_key.fib_index = sm->outside_fib_index;
2892 kv.key = m_key.as_u64;
2893 if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2894 m = 0;
2895 else
2896 m = pool_elt_at_index (sm->static_mappings, value.value);
2897
2898 if (!is_delete)
2899 {
2900 /* Don't trip over lease renewal, static config */
2901 if (m)
Matus Fabianab395ec2018-09-20 23:18:41 -07002902 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07002903 }
2904 else
2905 {
2906 if (!m)
Matus Fabianab395ec2018-09-20 23:18:41 -07002907 return;
Matus Fabian4772e7a2018-04-04 00:38:02 -07002908 }
2909
2910 /* Indetity mapping? */
2911 if (rp->l_addr.as_u32 == 0)
2912 l_addr.as_u32 = address[0].as_u32;
2913 else
2914 l_addr.as_u32 = rp->l_addr.as_u32;
2915 /* Add the static mapping */
2916 rv = snat_add_static_mapping (l_addr,
Matus Fabianab395ec2018-09-20 23:18:41 -07002917 address[0],
2918 rp->l_port,
2919 rp->e_port,
2920 rp->vrf_id,
2921 rp->addr_only, ~0 /* sw_if_index */ ,
2922 rp->proto, !is_delete, 0, 0, rp->tag);
Matus Fabian4772e7a2018-04-04 00:38:02 -07002923 if (rv)
Matus Fabian229c1aa2018-05-28 04:09:52 -07002924 nat_log_notice ("snat_add_static_mapping returned %d", rv);
Matus Fabian4772e7a2018-04-04 00:38:02 -07002925}
2926
2927static void
Dave Barachcab65ec2017-01-11 13:01:14 -05002928snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
Matus Fabianab395ec2018-09-20 23:18:41 -07002929 uword opaque,
2930 u32 sw_if_index,
2931 ip4_address_t * address,
2932 u32 address_length,
2933 u32 if_address_index, u32 is_delete)
Dave Barachcab65ec2017-01-11 13:01:14 -05002934{
2935 snat_main_t *sm = &snat_main;
Dave Barach8b275372017-01-16 10:54:02 -05002936 snat_static_map_resolve_t *rp;
Matus Fabianab7a8052017-11-28 04:29:41 -08002937 ip4_address_t l_addr;
Dave Barachcab65ec2017-01-11 13:01:14 -05002938 int i, j;
Dave Barach8b275372017-01-16 10:54:02 -05002939 int rv;
Matus Fabianb932d262017-12-18 05:38:24 -08002940 u8 twice_nat = 0;
2941 snat_address_t *addresses = sm->addresses;
Dave Barachcab65ec2017-01-11 13:01:14 -05002942
Matus Fabianab395ec2018-09-20 23:18:41 -07002943 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05002944 {
2945 if (sw_if_index == sm->auto_add_sw_if_indices[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07002946 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08002947 }
Dave Barachcab65ec2017-01-11 13:01:14 -05002948
Matus Fabianab395ec2018-09-20 23:18:41 -07002949 for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
Matus Fabianb932d262017-12-18 05:38:24 -08002950 {
2951 twice_nat = 1;
2952 addresses = sm->twice_nat_addresses;
2953 if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
Matus Fabianab395ec2018-09-20 23:18:41 -07002954 goto match;
Matus Fabianb932d262017-12-18 05:38:24 -08002955 }
2956
2957 return;
2958
2959match:
2960 if (!is_delete)
2961 {
2962 /* Don't trip over lease renewal, static config */
Matus Fabianab395ec2018-09-20 23:18:41 -07002963 for (j = 0; j < vec_len (addresses); j++)
2964 if (addresses[j].addr.as_u32 == address->as_u32)
2965 return;
Matus Fabianb932d262017-12-18 05:38:24 -08002966
Matus Fabiana6110b62018-06-13 05:39:07 -07002967 (void) snat_add_address (sm, address, ~0, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08002968 /* Scan static map resolution vector */
2969 for (j = 0; j < vec_len (sm->to_resolve); j++)
Matus Fabianab395ec2018-09-20 23:18:41 -07002970 {
2971 rp = sm->to_resolve + j;
2972 if (rp->addr_only)
2973 continue;
2974 /* On this interface? */
2975 if (rp->sw_if_index == sw_if_index)
2976 {
2977 /* Indetity mapping? */
2978 if (rp->l_addr.as_u32 == 0)
2979 l_addr.as_u32 = address[0].as_u32;
2980 else
2981 l_addr.as_u32 = rp->l_addr.as_u32;
2982 /* Add the static mapping */
2983 rv = snat_add_static_mapping (l_addr,
2984 address[0],
2985 rp->l_port,
2986 rp->e_port,
2987 rp->vrf_id,
2988 rp->addr_only,
2989 ~0 /* sw_if_index */ ,
2990 rp->proto,
2991 rp->is_add, 0, 0, rp->tag);
2992 if (rv)
2993 nat_log_notice ("snat_add_static_mapping returned %d", rv);
2994 }
2995 }
Matus Fabianb932d262017-12-18 05:38:24 -08002996 return;
2997 }
2998 else
2999 {
Matus Fabianab395ec2018-09-20 23:18:41 -07003000 (void) snat_del_address (sm, address[0], 1, twice_nat);
Matus Fabianb932d262017-12-18 05:38:24 -08003001 return;
Dave Barachcab65ec2017-01-11 13:01:14 -05003002 }
3003}
3004
3005
Matus Fabianab395ec2018-09-20 23:18:41 -07003006int
3007snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
3008 u8 twice_nat)
Dave Barachcab65ec2017-01-11 13:01:14 -05003009{
Matus Fabianab395ec2018-09-20 23:18:41 -07003010 ip4_main_t *ip4_main = sm->ip4_main;
3011 ip4_address_t *first_int_addr;
Matus Fabian36532bd2017-01-23 23:42:28 -08003012 snat_static_map_resolve_t *rp;
3013 u32 *indices_to_delete = 0;
3014 int i, j;
Matus Fabianb932d262017-12-18 05:38:24 -08003015 u32 *auto_add_sw_if_indices =
Matus Fabianab395ec2018-09-20 23:18:41 -07003016 twice_nat ? sm->
3017 auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
Dave Barachcab65ec2017-01-11 13:01:14 -05003018
Matus Fabianab395ec2018-09-20 23:18:41 -07003019 first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0 /* just want the address */
3020 );
Dave Barachcab65ec2017-01-11 13:01:14 -05003021
Matus Fabianab395ec2018-09-20 23:18:41 -07003022 for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
Dave Barachcab65ec2017-01-11 13:01:14 -05003023 {
Matus Fabianb932d262017-12-18 05:38:24 -08003024 if (auto_add_sw_if_indices[i] == sw_if_index)
Matus Fabianab395ec2018-09-20 23:18:41 -07003025 {
3026 if (is_del)
3027 {
3028 /* if have address remove it */
3029 if (first_int_addr)
3030 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3031 else
3032 {
3033 for (j = 0; j < vec_len (sm->to_resolve); j++)
3034 {
3035 rp = sm->to_resolve + j;
3036 if (rp->sw_if_index == sw_if_index)
3037 vec_add1 (indices_to_delete, j);
3038 }
3039 if (vec_len (indices_to_delete))
3040 {
3041 for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3042 vec_del1 (sm->to_resolve, j);
3043 vec_free (indices_to_delete);
3044 }
3045 }
3046 if (twice_nat)
3047 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3048 else
3049 vec_del1 (sm->auto_add_sw_if_indices, i);
3050 }
3051 else
3052 return VNET_API_ERROR_VALUE_EXIST;
Matus Fabian8bf68e82017-01-12 04:24:35 -08003053
Matus Fabianab395ec2018-09-20 23:18:41 -07003054 return 0;
3055 }
Dave Barachcab65ec2017-01-11 13:01:14 -05003056 }
Matus Fabian2ba92e32017-08-21 07:05:03 -07003057
Matus Fabian8bf68e82017-01-12 04:24:35 -08003058 if (is_del)
3059 return VNET_API_ERROR_NO_SUCH_ENTRY;
3060
Dave Barachcab65ec2017-01-11 13:01:14 -05003061 /* add to the auto-address list */
Matus Fabianb932d262017-12-18 05:38:24 -08003062 if (twice_nat)
Matus Fabianab395ec2018-09-20 23:18:41 -07003063 vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
Matus Fabianb932d262017-12-18 05:38:24 -08003064 else
Matus Fabianab395ec2018-09-20 23:18:41 -07003065 vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
Dave Barachcab65ec2017-01-11 13:01:14 -05003066
3067 /* If the address is already bound - or static - add it now */
3068 if (first_int_addr)
Matus Fabianab395ec2018-09-20 23:18:41 -07003069 (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
Dave Barachcab65ec2017-01-11 13:01:14 -05003070
3071 return 0;
3072}
3073
Matus Fabian5ba86f72017-10-26 03:37:38 -07003074int
Matus Fabianab395ec2018-09-20 23:18:41 -07003075nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3076 snat_protocol_t proto, u32 vrf_id, int is_in)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003077{
3078 snat_main_per_thread_data_t *tsm;
3079 clib_bihash_kv_8_8_t kv, value;
3080 ip4_header_t ip;
3081 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3082 snat_session_key_t key;
3083 snat_session_t *s;
3084 clib_bihash_8_8_t *t;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003085
Matus Fabiana6110b62018-06-13 05:39:07 -07003086 if (sm->endpoint_dependent)
3087 return VNET_API_ERROR_UNSUPPORTED;
3088
Matus Fabian5ba86f72017-10-26 03:37:38 -07003089 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
Matus Fabian4888b502018-03-27 01:07:25 -07003090 if (sm->num_workers > 1)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003091 tsm =
3092 vec_elt_at_index (sm->per_thread_data,
3093 sm->worker_in2out_cb (&ip, fib_index));
3094 else
3095 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3096
3097 key.addr.as_u32 = addr->as_u32;
3098 key.port = clib_host_to_net_u16 (port);
3099 key.protocol = proto;
3100 key.fib_index = fib_index;
3101 kv.key = key.as_u64;
3102 t = is_in ? &tsm->in2out : &tsm->out2in;
3103 if (!clib_bihash_search_8_8 (t, &kv, &value))
3104 {
Matus Fabian70a26ac2018-05-14 06:20:28 -07003105 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabianab395ec2018-09-20 23:18:41 -07003106 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003107
Matus Fabian5ba86f72017-10-26 03:37:38 -07003108 s = pool_elt_at_index (tsm->sessions, value.value);
Matus Fabian229c1aa2018-05-28 04:09:52 -07003109 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3110 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian5ba86f72017-10-26 03:37:38 -07003111 return 0;
3112 }
3113
3114 return VNET_API_ERROR_NO_SUCH_ENTRY;
3115}
3116
Matus Fabian70a26ac2018-05-14 06:20:28 -07003117int
Matus Fabianab395ec2018-09-20 23:18:41 -07003118nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3119 ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3120 u32 vrf_id, int is_in)
Matus Fabian70a26ac2018-05-14 06:20:28 -07003121{
3122 ip4_header_t ip;
3123 clib_bihash_16_8_t *t;
3124 nat_ed_ses_key_t key;
3125 clib_bihash_kv_16_8_t kv, value;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003126 u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3127 snat_session_t *s;
Matus Fabiana6110b62018-06-13 05:39:07 -07003128 snat_main_per_thread_data_t *tsm;
3129
3130 if (!sm->endpoint_dependent)
3131 return VNET_API_ERROR_FEATURE_DISABLED;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003132
3133 ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3134 if (sm->num_workers > 1)
Matus Fabiana6110b62018-06-13 05:39:07 -07003135 tsm =
3136 vec_elt_at_index (sm->per_thread_data,
3137 sm->worker_in2out_cb (&ip, fib_index));
Matus Fabian70a26ac2018-05-14 06:20:28 -07003138 else
Matus Fabiana6110b62018-06-13 05:39:07 -07003139 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
Matus Fabian70a26ac2018-05-14 06:20:28 -07003140
Matus Fabiana6110b62018-06-13 05:39:07 -07003141 t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003142 key.l_addr.as_u32 = addr->as_u32;
3143 key.r_addr.as_u32 = eh_addr->as_u32;
3144 key.l_port = clib_host_to_net_u16 (port);
3145 key.r_port = clib_host_to_net_u16 (eh_port);
3146 key.proto = proto;
Matus Fabianab395ec2018-09-20 23:18:41 -07003147 key.fib_index = fib_index;
Matus Fabian70a26ac2018-05-14 06:20:28 -07003148 kv.key[0] = key.as_u64[0];
3149 kv.key[1] = key.as_u64[1];
3150 if (clib_bihash_search_16_8 (t, &kv, &value))
3151 return VNET_API_ERROR_NO_SUCH_ENTRY;
3152
Matus Fabiana6110b62018-06-13 05:39:07 -07003153 if (pool_is_free_index (tsm->sessions, value.value))
Matus Fabian70a26ac2018-05-14 06:20:28 -07003154 return VNET_API_ERROR_UNSPECIFIED;
Matus Fabiana6110b62018-06-13 05:39:07 -07003155 s = pool_elt_at_index (tsm->sessions, value.value);
3156 nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3157 nat44_delete_session (sm, s, tsm - sm->per_thread_data);
Matus Fabian70a26ac2018-05-14 06:20:28 -07003158 return 0;
3159}
3160
Matus Fabian82119542018-01-25 01:13:22 -08003161void
3162nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
Matus Fabian5ba86f72017-10-26 03:37:38 -07003163{
3164 snat_main_t *sm = &snat_main;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003165
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003166 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
Matus Fabian82119542018-01-25 01:13:22 -08003167 sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3168 sm->psid = psid;
3169 sm->psid_offset = psid_offset;
3170 sm->psid_length = psid_length;
Matus Fabian5ba86f72017-10-26 03:37:38 -07003171}
3172
Matus Fabian82119542018-01-25 01:13:22 -08003173void
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003174nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
3175{
3176 snat_main_t *sm = &snat_main;
3177
3178 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
3179 sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
3180 sm->start_port = start_port;
3181 sm->end_port = end_port;
3182}
3183
3184void
Matus Fabian82119542018-01-25 01:13:22 -08003185nat_set_alloc_addr_and_port_default (void)
Matus Fabian27697102017-11-09 01:43:47 -08003186{
3187 snat_main_t *sm = &snat_main;
Matus Fabian27697102017-11-09 01:43:47 -08003188
Matus Fabian5d28c7a2018-09-04 03:55:45 -07003189 sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
Matus Fabian82119542018-01-25 01:13:22 -08003190 sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
Matus Fabian066f0342017-02-10 03:48:01 -08003191}
3192
Matus Fabianab395ec2018-09-20 23:18:41 -07003193/*
3194 * fd.io coding-style-patch-verification: ON
3195 *
3196 * Local Variables:
3197 * eval: (c-set-style "gnu")
3198 * End:
3199 */