a1d1f8536510513d1b0d4e07562d87e5b38d44d6
[vpp.git] / src / plugins / nat / nat.c
1 /*
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>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/ip4.h>
21 #include <vnet/plugin/plugin.h>
22 #include <nat/nat.h>
23 #include <nat/nat_dpo.h>
24 #include <nat/nat_ipfix_logging.h>
25 #include <nat/nat_det.h>
26 #include <nat/nat64.h>
27 #include <nat/nat66.h>
28 #include <nat/nat_inlines.h>
29 #include <nat/nat44/inlines.h>
30 #include <nat/nat_affinity.h>
31 #include <nat/nat_syslog.h>
32 #include <nat/nat_ha.h>
33 #include <vnet/fib/fib_table.h>
34 #include <vnet/fib/ip4_fib.h>
35 #include <vnet/ip/reass/ip4_sv_reass.h>
36 #include <vppinfra/bihash_16_8.h>
37
38 #include <vpp/app/version.h>
39
40 snat_main_t snat_main;
41
42 fib_source_t nat_fib_src_hi;
43 fib_source_t nat_fib_src_low;
44
45 /* *INDENT-OFF* */
46 /* Hook up input features */
47 VNET_FEATURE_INIT (nat_pre_in2out, static) = {
48   .arc_name = "ip4-unicast",
49   .node_name = "nat-pre-in2out",
50   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
51                                "ip4-sv-reassembly-feature"),
52 };
53 VNET_FEATURE_INIT (nat_pre_out2in, static) = {
54   .arc_name = "ip4-unicast",
55   .node_name = "nat-pre-out2in",
56   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
57                                "ip4-dhcp-client-detect",
58                                "ip4-sv-reassembly-feature"),
59 };
60 VNET_FEATURE_INIT (snat_in2out_worker_handoff, static) = {
61   .arc_name = "ip4-unicast",
62   .node_name = "nat44-in2out-worker-handoff",
63   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
64 };
65 VNET_FEATURE_INIT (snat_out2in_worker_handoff, static) = {
66   .arc_name = "ip4-unicast",
67   .node_name = "nat44-out2in-worker-handoff",
68   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
69                                "ip4-dhcp-client-detect"),
70 };
71 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
72   .arc_name = "ip4-unicast",
73   .node_name = "nat44-in2out",
74   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
75 };
76 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
77   .arc_name = "ip4-unicast",
78   .node_name = "nat44-out2in",
79   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
80                                "ip4-dhcp-client-detect"),
81 };
82 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
83   .arc_name = "ip4-unicast",
84   .node_name = "nat44-classify",
85   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
86 };
87 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
88   .arc_name = "ip4-unicast",
89   .node_name = "nat44-det-in2out",
90   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
91 };
92 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
93   .arc_name = "ip4-unicast",
94   .node_name = "nat44-det-out2in",
95   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
96                                "ip4-dhcp-client-detect"),
97 };
98 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
99   .arc_name = "ip4-unicast",
100   .node_name = "nat44-det-classify",
101   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
102 };
103 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
104   .arc_name = "ip4-unicast",
105   .node_name = "nat44-ed-in2out",
106   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
107 };
108 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
109   .arc_name = "ip4-unicast",
110   .node_name = "nat44-ed-out2in",
111   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
112                                "ip4-dhcp-client-detect"),
113 };
114 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
115   .arc_name = "ip4-unicast",
116   .node_name = "nat44-ed-classify",
117   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
118 };
119 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
120   .arc_name = "ip4-unicast",
121   .node_name = "nat44-handoff-classify",
122   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
123 };
124 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
125   .arc_name = "ip4-unicast",
126   .node_name = "nat44-in2out-fast",
127   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
128 };
129 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
130   .arc_name = "ip4-unicast",
131   .node_name = "nat44-out2in-fast",
132   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature",
133                                "ip4-dhcp-client-detect"),
134 };
135 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
136   .arc_name = "ip4-unicast",
137   .node_name = "nat44-hairpin-dst",
138   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
139 };
140 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
141   .arc_name = "ip4-unicast",
142   .node_name = "nat44-ed-hairpin-dst",
143   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa","ip4-sv-reassembly-feature"),
144 };
145
146 /* Hook up output features */
147 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
148   .arc_name = "ip4-output",
149   .node_name = "nat44-in2out-output",
150   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
151 };
152 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
153   .arc_name = "ip4-output",
154   .node_name = "nat44-in2out-output-worker-handoff",
155   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
156 };
157 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
158   .arc_name = "ip4-output",
159   .node_name = "nat44-hairpin-src",
160   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa","ip4-sv-reassembly-output-feature"),
161 };
162 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
163   .arc_name = "ip4-output",
164   .node_name = "nat44-ed-in2out-output",
165   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
166   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
167 };
168 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
169   .arc_name = "ip4-output",
170   .node_name = "nat44-ed-hairpin-src",
171   .runs_after = VNET_FEATURES ("ip4-sv-reassembly-output-feature"),
172   .runs_before = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
173 };
174
175 /* Hook up ip4-local features */
176 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
177 {
178   .arc_name = "ip4-local",
179   .node_name = "nat44-hairpinning",
180   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
181 };
182 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
183 {
184   .arc_name = "ip4-local",
185   .node_name = "nat44-ed-hairpinning",
186   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
187 };
188
189
190 VLIB_PLUGIN_REGISTER () = {
191     .version = VPP_BUILD_VER,
192     .description = "Network Address Translation (NAT)",
193 };
194 /* *INDENT-ON* */
195
196 void
197 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index,
198                        u8 is_ha)
199 {
200   snat_session_key_t key;
201   clib_bihash_kv_8_8_t kv;
202   u8 proto;
203   u16 r_port, l_port;
204   ip4_address_t *l_addr, *r_addr;
205   u32 fib_index = 0;
206   clib_bihash_kv_16_8_t ed_kv;
207   snat_main_per_thread_data_t *tsm =
208     vec_elt_at_index (sm->per_thread_data, thread_index);
209
210   if (is_fwd_bypass_session (s))
211     {
212       if (snat_is_unk_proto_session (s))
213         {
214           make_ed_kv (&s->in2out.addr, &s->ext_host_addr, s->in2out.port, 0,
215                       0, 0, ~0ULL, &ed_kv);
216         }
217       else
218         {
219           l_port = s->in2out.port;
220           r_port = s->ext_host_port;
221           l_addr = &s->in2out.addr;
222           r_addr = &s->ext_host_addr;
223           proto = snat_proto_to_ip_proto (s->in2out.protocol);
224           make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
225                       &ed_kv);
226         }
227       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
228         nat_elog_warn ("in2out_ed key del failed");
229       return;
230     }
231
232   /* session lookup tables */
233   if (is_ed_session (s))
234     {
235       if (is_affinity_sessions (s))
236         nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
237                              s->in2out.protocol, s->out2in.port);
238       l_addr = &s->out2in.addr;
239       r_addr = &s->ext_host_addr;
240       fib_index = s->out2in.fib_index;
241       if (snat_is_unk_proto_session (s))
242         {
243           proto = s->in2out.port;
244           r_port = 0;
245           l_port = 0;
246         }
247       else
248         {
249           proto = snat_proto_to_ip_proto (s->in2out.protocol);
250           l_port = s->out2in.port;
251           r_port = s->ext_host_port;
252         }
253       make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
254                   &ed_kv);
255       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
256         nat_elog_warn ("out2in_ed key del failed");
257       l_addr = &s->in2out.addr;
258       fib_index = s->in2out.fib_index;
259       if (!snat_is_unk_proto_session (s))
260         l_port = s->in2out.port;
261       if (is_twice_nat_session (s))
262         {
263           r_addr = &s->ext_host_nat_addr;
264           r_port = s->ext_host_nat_port;
265         }
266       make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
267                   &ed_kv);
268       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
269         nat_elog_warn ("in2out_ed key del failed");
270
271       if (!is_ha)
272         nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
273                                &s->in2out.addr, s->in2out.port,
274                                &s->ext_host_nat_addr, s->ext_host_nat_port,
275                                &s->out2in.addr, s->out2in.port,
276                                &s->ext_host_addr, s->ext_host_port,
277                                s->in2out.protocol, is_twice_nat_session (s));
278     }
279   else
280     {
281       kv.key = s->in2out.as_u64;
282       if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
283         nat_elog_warn ("in2out key del failed");
284       kv.key = s->out2in.as_u64;
285       if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
286         nat_elog_warn ("out2in key del failed");
287
288       if (!is_ha)
289         nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
290                                  &s->in2out.addr, s->in2out.port,
291                                  &s->out2in.addr, s->out2in.port,
292                                  s->in2out.protocol);
293     }
294
295   if (snat_is_unk_proto_session (s))
296     return;
297
298   if (!is_ha)
299     {
300       /* log NAT event */
301       snat_ipfix_logging_nat44_ses_delete (thread_index,
302                                            s->in2out.addr.as_u32,
303                                            s->out2in.addr.as_u32,
304                                            s->in2out.protocol,
305                                            s->in2out.port,
306                                            s->out2in.port,
307                                            s->in2out.fib_index);
308
309       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
310                    s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
311                    thread_index);
312     }
313
314   /* Twice NAT address and port for external host */
315   if (is_twice_nat_session (s))
316     {
317       key.protocol = s->in2out.protocol;
318       key.port = s->ext_host_nat_port;
319       key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
320       snat_free_outside_address_and_port (sm->twice_nat_addresses,
321                                           thread_index, &key);
322     }
323
324   if (snat_is_session_static (s))
325     return;
326
327   snat_free_outside_address_and_port (sm->addresses, thread_index,
328                                       &s->out2in);
329 }
330
331 int
332 nat44_set_session_limit (u32 session_limit, u32 vrf_id)
333 {
334   snat_main_t *sm = &snat_main;
335   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
336   u32 len = vec_len (sm->max_translations_per_fib);
337
338   if (len <= fib_index)
339     {
340       vec_validate (sm->max_translations_per_fib, fib_index + 1);
341
342       for (; len < vec_len (sm->max_translations_per_fib); len++)
343         sm->max_translations_per_fib[len] = sm->max_translations;
344     }
345
346   sm->max_translations_per_fib[fib_index] = session_limit;
347   return 0;
348 }
349
350 void
351 nat44_free_session_data (snat_main_t * sm, snat_session_t * s,
352                          u32 thread_index, u8 is_ha)
353 {
354   snat_session_key_t key;
355   u8 proto;
356   u16 r_port, l_port;
357   ip4_address_t *l_addr, *r_addr;
358   u32 fib_index;
359   clib_bihash_kv_16_8_t ed_kv;
360   snat_main_per_thread_data_t *tsm =
361     vec_elt_at_index (sm->per_thread_data, thread_index);
362
363   if (is_fwd_bypass_session (s))
364     {
365       if (snat_is_unk_proto_session (s))
366         {
367           proto = s->in2out.port;
368           r_port = 0;
369           l_port = 0;
370         }
371       else
372         {
373           proto = snat_proto_to_ip_proto (s->in2out.protocol);
374           l_port = s->in2out.port;
375           r_port = s->ext_host_port;
376         }
377
378       l_addr = &s->in2out.addr;
379       r_addr = &s->ext_host_addr;
380       fib_index = 0;
381       make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
382                   &ed_kv);
383
384       if (PREDICT_FALSE
385           (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
386         nat_elog_warn ("in2out_ed key del failed");
387       return;
388     }
389
390   /* session lookup tables */
391   if (is_affinity_sessions (s))
392     nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
393                          s->in2out.protocol, s->out2in.port);
394   l_addr = &s->out2in.addr;
395   r_addr = &s->ext_host_addr;
396   fib_index = s->out2in.fib_index;
397   if (snat_is_unk_proto_session (s))
398     {
399       proto = s->in2out.port;
400       r_port = 0;
401       l_port = 0;
402     }
403   else
404     {
405       proto = snat_proto_to_ip_proto (s->in2out.protocol);
406       l_port = s->out2in.port;
407       r_port = s->ext_host_port;
408     }
409   make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
410               &ed_kv);
411
412   if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0)))
413     nat_elog_warn ("out2in_ed key del failed");
414
415   l_addr = &s->in2out.addr;
416   fib_index = s->in2out.fib_index;
417
418   if (!snat_is_unk_proto_session (s))
419     l_port = s->in2out.port;
420
421   if (is_twice_nat_session (s))
422     {
423       r_addr = &s->ext_host_nat_addr;
424       r_port = s->ext_host_nat_port;
425     }
426   make_ed_kv (l_addr, r_addr, proto, fib_index, l_port, r_port, ~0ULL,
427               &ed_kv);
428
429   if (PREDICT_FALSE (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0)))
430     nat_elog_warn ("in2out_ed key del failed");
431
432   if (!is_ha)
433     {
434       nat_syslog_nat44_sdel (s->user_index, s->in2out.fib_index,
435                              &s->in2out.addr, s->in2out.port,
436                              &s->ext_host_nat_addr, s->ext_host_nat_port,
437                              &s->out2in.addr, s->out2in.port,
438                              &s->ext_host_addr, s->ext_host_port,
439                              s->in2out.protocol, is_twice_nat_session (s));
440     }
441
442   if (snat_is_unk_proto_session (s))
443     return;
444
445   // is this correct ?
446   if (!is_ha)
447     {
448       snat_ipfix_logging_nat44_ses_delete (thread_index,
449                                            s->in2out.addr.as_u32,
450                                            s->out2in.addr.as_u32,
451                                            s->in2out.protocol,
452                                            s->in2out.port,
453                                            s->out2in.port,
454                                            s->in2out.fib_index);
455       nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
456                    s->ext_host_port, s->out2in.protocol, s->out2in.fib_index,
457                    thread_index);
458     }
459
460   /* Twice NAT address and port for external host */
461   if (is_twice_nat_session (s))
462     {
463       key.protocol = s->in2out.protocol;
464       key.port = s->ext_host_nat_port;
465       key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
466       snat_free_outside_address_and_port (sm->twice_nat_addresses,
467                                           thread_index, &key);
468     }
469
470   if (snat_is_session_static (s))
471     return;
472
473   // should be called for every dynamic session
474   snat_free_outside_address_and_port (sm->addresses, thread_index,
475                                       &s->out2in);
476 }
477
478
479 snat_user_t *
480 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
481                         u32 thread_index)
482 {
483   snat_user_t *u = 0;
484   snat_user_key_t user_key;
485   clib_bihash_kv_8_8_t kv, value;
486   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
487   dlist_elt_t *per_user_list_head_elt;
488
489   user_key.addr.as_u32 = addr->as_u32;
490   user_key.fib_index = fib_index;
491   kv.key = user_key.as_u64;
492
493   /* Ever heard of the "user" = src ip4 address before? */
494   if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
495     {
496       /* no, make a new one */
497       pool_get (tsm->users, u);
498       clib_memset (u, 0, sizeof (*u));
499
500       u->addr.as_u32 = addr->as_u32;
501       u->fib_index = fib_index;
502
503       pool_get (tsm->list_pool, per_user_list_head_elt);
504
505       u->sessions_per_user_list_head_index = per_user_list_head_elt -
506         tsm->list_pool;
507
508       clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
509
510       kv.value = u - tsm->users;
511
512       /* add user */
513       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
514         {
515           nat_elog_warn ("user_hash key add failed");
516           nat44_delete_user_with_no_session (sm, u, thread_index);
517           return NULL;
518         }
519
520       vlib_set_simple_counter (&sm->total_users, thread_index, 0,
521                                pool_elts (tsm->users));
522     }
523   else
524     {
525       u = pool_elt_at_index (tsm->users, value.value);
526     }
527
528   return u;
529 }
530
531 snat_session_t *
532 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
533                               u32 thread_index, f64 now)
534 {
535   snat_session_t *s;
536   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
537   u32 oldest_per_user_translation_list_index, session_index;
538   dlist_elt_t *oldest_per_user_translation_list_elt;
539   dlist_elt_t *per_user_translation_list_elt;
540
541   /* Over quota? Recycle the least recently used translation */
542   if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
543     {
544       oldest_per_user_translation_list_index =
545         clib_dlist_remove_head (tsm->list_pool,
546                                 u->sessions_per_user_list_head_index);
547
548       ASSERT (oldest_per_user_translation_list_index != ~0);
549
550       /* Add it back to the end of the LRU list */
551       clib_dlist_addtail (tsm->list_pool,
552                           u->sessions_per_user_list_head_index,
553                           oldest_per_user_translation_list_index);
554       /* Get the list element */
555       oldest_per_user_translation_list_elt =
556         pool_elt_at_index (tsm->list_pool,
557                            oldest_per_user_translation_list_index);
558
559       /* Get the session index from the list element */
560       session_index = oldest_per_user_translation_list_elt->value;
561
562       /* Get the session */
563       s = pool_elt_at_index (tsm->sessions, session_index);
564       nat_free_session_data (sm, s, thread_index, 0);
565       if (snat_is_session_static (s))
566         u->nstaticsessions--;
567       else
568         u->nsessions--;
569       s->flags = 0;
570       s->total_bytes = 0;
571       s->total_pkts = 0;
572       s->state = 0;
573       s->ext_host_addr.as_u32 = 0;
574       s->ext_host_port = 0;
575       s->ext_host_nat_addr.as_u32 = 0;
576       s->ext_host_nat_port = 0;
577     }
578   else
579     {
580       pool_get (tsm->sessions, s);
581       clib_memset (s, 0, sizeof (*s));
582
583       /* Create list elts */
584       pool_get (tsm->list_pool, per_user_translation_list_elt);
585       clib_dlist_init (tsm->list_pool,
586                        per_user_translation_list_elt - tsm->list_pool);
587
588       per_user_translation_list_elt->value = s - tsm->sessions;
589       s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
590       s->per_user_list_head_index = u->sessions_per_user_list_head_index;
591
592       clib_dlist_addtail (tsm->list_pool,
593                           s->per_user_list_head_index,
594                           per_user_translation_list_elt - tsm->list_pool);
595
596       dlist_elt_t *global_lru_list_elt;
597       pool_get (tsm->global_lru_pool, global_lru_list_elt);
598       global_lru_list_elt->value = s - tsm->sessions;
599       s->global_lru_index = global_lru_list_elt - tsm->global_lru_pool;
600       clib_dlist_addtail (tsm->global_lru_pool, tsm->global_lru_head_index,
601                           s->global_lru_index);
602       s->last_lru_update = now;
603
604       s->user_index = u - tsm->users;
605       vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
606                                pool_elts (tsm->sessions));
607     }
608
609   s->ha_last_refreshed = now;
610
611   return s;
612 }
613
614 int
615 nat_global_lru_free_one (snat_main_t * sm, int thread_index, f64 now)
616 {
617   snat_session_t *s = NULL;
618   dlist_elt_t *oldest_elt;
619   u64 sess_timeout_time;
620   u32 oldest_index;
621   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
622   oldest_index = clib_dlist_remove_head (tsm->global_lru_pool,
623                                          tsm->global_lru_head_index);
624   if (~0 != oldest_index)
625     {
626       oldest_elt = pool_elt_at_index (tsm->global_lru_pool, oldest_index);
627       s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
628
629       sess_timeout_time =
630         s->last_heard + (f64) nat44_session_get_timeout (sm, s);
631       if (now >= sess_timeout_time
632           || (s->tcp_close_timestamp && now >= s->tcp_close_timestamp))
633         {
634           nat_free_session_data (sm, s, thread_index, 0);
635           nat44_ed_delete_session (sm, s, thread_index, 0);
636           return 1;
637         }
638       else
639         {
640           clib_dlist_addhead (tsm->global_lru_pool,
641                               tsm->global_lru_head_index, oldest_index);
642         }
643     }
644   return 0;
645 }
646
647 snat_session_t *
648 nat_ed_session_alloc (snat_main_t * sm, u32 thread_index, f64 now)
649 {
650   snat_session_t *s;
651   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
652
653   nat_global_lru_free_one (sm, thread_index, now);
654
655   pool_get (tsm->sessions, s);
656   clib_memset (s, 0, sizeof (*s));
657
658   nat44_global_lru_insert (tsm, s, now);
659
660   s->ha_last_refreshed = now;
661   vlib_set_simple_counter (&sm->total_sessions, thread_index, 0,
662                            pool_elts (tsm->sessions));
663   return s;
664 }
665
666 void
667 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
668                           int is_add)
669 {
670   fib_prefix_t prefix = {
671     .fp_len = p_len,
672     .fp_proto = FIB_PROTOCOL_IP4,
673     .fp_addr = {
674                 .ip4.as_u32 = addr->as_u32,
675                 },
676   };
677   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
678
679   if (is_add)
680     fib_table_entry_update_one_path (fib_index,
681                                      &prefix,
682                                      nat_fib_src_low,
683                                      (FIB_ENTRY_FLAG_CONNECTED |
684                                       FIB_ENTRY_FLAG_LOCAL |
685                                       FIB_ENTRY_FLAG_EXCLUSIVE),
686                                      DPO_PROTO_IP4,
687                                      NULL,
688                                      sw_if_index,
689                                      ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
690   else
691     fib_table_entry_delete (fib_index, &prefix, nat_fib_src_low);
692 }
693
694 int
695 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
696                   u8 twice_nat)
697 {
698   snat_address_t *ap;
699   snat_interface_t *i;
700   vlib_thread_main_t *tm = vlib_get_thread_main ();
701
702   if (twice_nat && !sm->endpoint_dependent)
703     return VNET_API_ERROR_FEATURE_DISABLED;
704
705   /* Check if address already exists */
706   /* *INDENT-OFF* */
707   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
708     {
709       if (ap->addr.as_u32 == addr->as_u32)
710         return VNET_API_ERROR_VALUE_EXIST;
711     }
712   /* *INDENT-ON* */
713
714   if (twice_nat)
715     vec_add2 (sm->twice_nat_addresses, ap, 1);
716   else
717     vec_add2 (sm->addresses, ap, 1);
718
719   ap->addr = *addr;
720   if (vrf_id != ~0)
721     ap->fib_index =
722       fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
723                                          nat_fib_src_low);
724   else
725     ap->fib_index = ~0;
726 #define _(N, i, n, s) \
727   clib_memset(ap->busy_##n##_port_refcounts, 0, sizeof(ap->busy_##n##_port_refcounts));\
728   ap->busy_##n##_ports = 0; \
729   ap->busy_##n##_ports_per_thread = 0;\
730   vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
731   foreach_snat_protocol
732 #undef _
733     if (twice_nat)
734     return 0;
735
736   /* Add external address to FIB */
737   /* *INDENT-OFF* */
738   pool_foreach (i, sm->interfaces,
739   ({
740     if (nat_interface_is_inside(i) || sm->out2in_dpo)
741       continue;
742
743     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
744     break;
745   }));
746   pool_foreach (i, sm->output_feature_interfaces,
747   ({
748     if (nat_interface_is_inside(i) || sm->out2in_dpo)
749       continue;
750
751     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
752     break;
753   }));
754   /* *INDENT-ON* */
755
756   return 0;
757 }
758
759 static int
760 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
761 {
762   snat_static_mapping_t *m;
763   /* *INDENT-OFF* */
764   pool_foreach (m, sm->static_mappings,
765   ({
766       if (is_addr_only_static_mapping (m) ||
767           is_out2in_only_static_mapping (m) ||
768           is_identity_static_mapping (m))
769         continue;
770       if (m->external_addr.as_u32 == addr.as_u32)
771         return 1;
772   }));
773   /* *INDENT-ON* */
774
775   return 0;
776 }
777
778 static void
779 snat_add_static_mapping_when_resolved (snat_main_t * sm,
780                                        ip4_address_t l_addr,
781                                        u16 l_port,
782                                        u32 sw_if_index,
783                                        u16 e_port,
784                                        u32 vrf_id,
785                                        snat_protocol_t proto,
786                                        int addr_only, int is_add, u8 * tag,
787                                        int twice_nat, int out2in_only,
788                                        int identity_nat)
789 {
790   snat_static_map_resolve_t *rp;
791
792   vec_add2 (sm->to_resolve, rp, 1);
793   rp->l_addr.as_u32 = l_addr.as_u32;
794   rp->l_port = l_port;
795   rp->sw_if_index = sw_if_index;
796   rp->e_port = e_port;
797   rp->vrf_id = vrf_id;
798   rp->proto = proto;
799   rp->addr_only = addr_only;
800   rp->is_add = is_add;
801   rp->twice_nat = twice_nat;
802   rp->out2in_only = out2in_only;
803   rp->identity_nat = identity_nat;
804   rp->tag = vec_dup (tag);
805 }
806
807 static u32
808 get_thread_idx_by_port (u16 e_port)
809 {
810   snat_main_t *sm = &snat_main;
811   u32 thread_idx = sm->num_workers;
812   if (sm->num_workers > 1)
813     {
814       thread_idx =
815         sm->first_worker_index +
816         sm->workers[(e_port - 1024) / sm->port_per_thread];
817     }
818   return thread_idx;
819 }
820
821 void
822 snat_static_mapping_del_sessions (snat_main_t * sm,
823                                   snat_main_per_thread_data_t * tsm,
824                                   snat_user_key_t u_key, int addr_only,
825                                   ip4_address_t e_addr, u16 e_port)
826 {
827   clib_bihash_kv_8_8_t kv, value;
828   kv.key = u_key.as_u64;
829   u64 user_index;
830   dlist_elt_t *head, *elt;
831   snat_user_t *u;
832   snat_session_t *s;
833   u32 elt_index, head_index, ses_index;
834   if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
835     {
836       user_index = value.value;
837       u = pool_elt_at_index (tsm->users, user_index);
838       if (u->nstaticsessions)
839         {
840           head_index = u->sessions_per_user_list_head_index;
841           head = pool_elt_at_index (tsm->list_pool, head_index);
842           elt_index = head->next;
843           elt = pool_elt_at_index (tsm->list_pool, elt_index);
844           ses_index = elt->value;
845           while (ses_index != ~0)
846             {
847               s = pool_elt_at_index (tsm->sessions, ses_index);
848               elt = pool_elt_at_index (tsm->list_pool, elt->next);
849               ses_index = elt->value;
850
851               if (!addr_only)
852                 {
853                   if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
854                       (clib_net_to_host_u16 (s->out2in.port) != e_port))
855                     continue;
856                 }
857
858               if (is_lb_session (s))
859                 continue;
860
861               if (!snat_is_session_static (s))
862                 continue;
863
864               nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
865               nat44_delete_session (sm, s, tsm - sm->per_thread_data);
866
867               if (!addr_only)
868                 break;
869             }
870         }
871     }
872 }
873
874 void
875 snat_ed_static_mapping_del_sessions (snat_main_t * sm,
876                                      snat_main_per_thread_data_t * tsm,
877                                      ip4_address_t l_addr,
878                                      u16 l_port,
879                                      u8 protocol,
880                                      u32 fib_index, int addr_only,
881                                      ip4_address_t e_addr, u16 e_port)
882 {
883   snat_session_t *s;
884   u32 *indexes_to_free = NULL;
885   /* *INDENT-OFF* */
886   pool_foreach (s, tsm->sessions, {
887     if (s->in2out.fib_index != fib_index ||
888         s->in2out.addr.as_u32 != l_addr.as_u32)
889       {
890         continue;
891       }
892     if (!addr_only)
893       {
894         if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
895             (clib_net_to_host_u16 (s->out2in.port) != e_port) ||
896             clib_net_to_host_u16 (s->in2out.port) != l_port ||
897             s->in2out.protocol != protocol)
898           continue;
899       }
900
901     if (is_lb_session (s))
902       continue;
903     if (!snat_is_session_static (s))
904       continue;
905     nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
906     vec_add1 (indexes_to_free, s - tsm->sessions);
907     if (!addr_only)
908       break;
909   });
910   /* *INDENT-ON* */
911   u32 *ses_index;
912   vec_foreach (ses_index, indexes_to_free)
913   {
914     s = pool_elt_at_index (tsm->sessions, *ses_index);
915     nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
916   }
917   vec_free (indexes_to_free);
918 }
919
920 int
921 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
922                          u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
923                          u32 sw_if_index, snat_protocol_t proto, int is_add,
924                          twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
925                          u8 identity_nat)
926 {
927   snat_main_t *sm = &snat_main;
928   snat_static_mapping_t *m;
929   snat_session_key_t m_key;
930   clib_bihash_kv_8_8_t kv, value;
931   snat_address_t *a = 0;
932   u32 fib_index = ~0;
933   snat_interface_t *interface;
934   int i;
935   snat_main_per_thread_data_t *tsm;
936   snat_user_key_t u_key;
937   snat_user_t *u;
938   dlist_elt_t *head, *elt;
939   u32 elt_index, head_index;
940   u32 ses_index;
941   u64 user_index;
942   snat_session_t *s;
943   snat_static_map_resolve_t *rp, *rp_match = 0;
944   nat44_lb_addr_port_t *local;
945   u32 find = ~0;
946
947   if (!sm->endpoint_dependent)
948     {
949       if (twice_nat || out2in_only)
950         return VNET_API_ERROR_FEATURE_DISABLED;
951     }
952
953   /* If the external address is a specific interface address */
954   if (sw_if_index != ~0)
955     {
956       ip4_address_t *first_int_addr;
957
958       for (i = 0; i < vec_len (sm->to_resolve); i++)
959         {
960           rp = sm->to_resolve + i;
961           if (rp->sw_if_index != sw_if_index ||
962               rp->l_addr.as_u32 != l_addr.as_u32 ||
963               rp->vrf_id != vrf_id || rp->addr_only != addr_only)
964             continue;
965
966           if (!addr_only)
967             {
968               if ((rp->l_port != l_port && rp->e_port != e_port)
969                   || rp->proto != proto)
970                 continue;
971             }
972
973           rp_match = rp;
974           break;
975         }
976
977       /* Might be already set... */
978       first_int_addr = ip4_interface_first_address
979         (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
980
981       if (is_add)
982         {
983           if (rp_match)
984             return VNET_API_ERROR_VALUE_EXIST;
985
986           snat_add_static_mapping_when_resolved
987             (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
988              addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
989
990           /* DHCP resolution required? */
991           if (first_int_addr == 0)
992             {
993               return 0;
994             }
995           else
996             {
997               e_addr.as_u32 = first_int_addr->as_u32;
998               /* Identity mapping? */
999               if (l_addr.as_u32 == 0)
1000                 l_addr.as_u32 = e_addr.as_u32;
1001             }
1002         }
1003       else
1004         {
1005           if (!rp_match)
1006             return VNET_API_ERROR_NO_SUCH_ENTRY;
1007
1008           vec_del1 (sm->to_resolve, i);
1009
1010           if (first_int_addr)
1011             {
1012               e_addr.as_u32 = first_int_addr->as_u32;
1013               /* Identity mapping? */
1014               if (l_addr.as_u32 == 0)
1015                 l_addr.as_u32 = e_addr.as_u32;
1016             }
1017           else
1018             return 0;
1019         }
1020     }
1021
1022   m_key.addr = e_addr;
1023   m_key.port = addr_only ? 0 : e_port;
1024   m_key.protocol = addr_only ? 0 : proto;
1025   m_key.fib_index = 0;
1026   kv.key = m_key.as_u64;
1027   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1028     m = 0;
1029   else
1030     m = pool_elt_at_index (sm->static_mappings, value.value);
1031
1032   if (is_add)
1033     {
1034       if (m)
1035         {
1036           if (is_identity_static_mapping (m))
1037             {
1038               /* *INDENT-OFF* */
1039               pool_foreach (local, m->locals,
1040               ({
1041                 if (local->vrf_id == vrf_id)
1042                   return VNET_API_ERROR_VALUE_EXIST;
1043               }));
1044               /* *INDENT-ON* */
1045               pool_get (m->locals, local);
1046               local->vrf_id = vrf_id;
1047               local->fib_index =
1048                 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1049                                                    nat_fib_src_low);
1050               m_key.addr = m->local_addr;
1051               m_key.port = m->local_port;
1052               m_key.protocol = m->proto;
1053               m_key.fib_index = local->fib_index;
1054               kv.key = m_key.as_u64;
1055               kv.value = m - sm->static_mappings;
1056               clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1057               return 0;
1058             }
1059           else
1060             return VNET_API_ERROR_VALUE_EXIST;
1061         }
1062
1063       if (twice_nat && addr_only)
1064         return VNET_API_ERROR_UNSUPPORTED;
1065
1066       /* Convert VRF id to FIB index */
1067       if (vrf_id != ~0)
1068         fib_index =
1069           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1070                                              nat_fib_src_low);
1071       /* If not specified use inside VRF id from SNAT plugin startup config */
1072       else
1073         {
1074           fib_index = sm->inside_fib_index;
1075           vrf_id = sm->inside_vrf_id;
1076           fib_table_lock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1077         }
1078
1079       if (!(out2in_only || identity_nat))
1080         {
1081           m_key.addr = l_addr;
1082           m_key.port = addr_only ? 0 : l_port;
1083           m_key.protocol = addr_only ? 0 : proto;
1084           m_key.fib_index = fib_index;
1085           kv.key = m_key.as_u64;
1086           if (!clib_bihash_search_8_8
1087               (&sm->static_mapping_by_local, &kv, &value))
1088             return VNET_API_ERROR_VALUE_EXIST;
1089         }
1090
1091       /* Find external address in allocated addresses and reserve port for
1092          address and port pair mapping when dynamic translations enabled */
1093       if (!(addr_only || sm->static_mapping_only || out2in_only))
1094         {
1095           for (i = 0; i < vec_len (sm->addresses); i++)
1096             {
1097               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1098                 {
1099                   a = sm->addresses + i;
1100                   /* External port must be unused */
1101                   switch (proto)
1102                     {
1103 #define _(N, j, n, s) \
1104                     case SNAT_PROTOCOL_##N: \
1105                       if (a->busy_##n##_port_refcounts[e_port]) \
1106                         return VNET_API_ERROR_INVALID_VALUE; \
1107                       ++a->busy_##n##_port_refcounts[e_port]; \
1108                       if (e_port > 1024) \
1109                         { \
1110                           a->busy_##n##_ports++; \
1111                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1112                         } \
1113                       break;
1114                       foreach_snat_protocol
1115 #undef _
1116                     default:
1117                       nat_elog_info ("unknown protocol");
1118                       return VNET_API_ERROR_INVALID_VALUE_2;
1119                     }
1120                   break;
1121                 }
1122             }
1123           /* External address must be allocated */
1124           if (!a && (l_addr.as_u32 != e_addr.as_u32))
1125             {
1126               if (sw_if_index != ~0)
1127                 {
1128                   for (i = 0; i < vec_len (sm->to_resolve); i++)
1129                     {
1130                       rp = sm->to_resolve + i;
1131                       if (rp->addr_only)
1132                         continue;
1133                       if (rp->sw_if_index != sw_if_index &&
1134                           rp->l_addr.as_u32 != l_addr.as_u32 &&
1135                           rp->vrf_id != vrf_id && rp->l_port != l_port &&
1136                           rp->e_port != e_port && rp->proto != proto)
1137                         continue;
1138
1139                       vec_del1 (sm->to_resolve, i);
1140                       break;
1141                     }
1142                 }
1143               return VNET_API_ERROR_NO_SUCH_ENTRY;
1144             }
1145         }
1146
1147       pool_get (sm->static_mappings, m);
1148       clib_memset (m, 0, sizeof (*m));
1149       m->tag = vec_dup (tag);
1150       m->local_addr = l_addr;
1151       m->external_addr = e_addr;
1152       m->twice_nat = twice_nat;
1153       if (out2in_only)
1154         m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1155       if (addr_only)
1156         m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
1157       if (identity_nat)
1158         {
1159           m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
1160           pool_get (m->locals, local);
1161           local->vrf_id = vrf_id;
1162           local->fib_index = fib_index;
1163         }
1164       else
1165         {
1166           m->vrf_id = vrf_id;
1167           m->fib_index = fib_index;
1168         }
1169       if (!addr_only)
1170         {
1171           m->local_port = l_port;
1172           m->external_port = e_port;
1173           m->proto = proto;
1174         }
1175
1176       if (sm->num_workers > 1)
1177         {
1178           ip4_header_t ip = {
1179             .src_address = m->local_addr,
1180           };
1181           vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index, 0));
1182           tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1183         }
1184       else
1185         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1186
1187       m_key.addr = m->local_addr;
1188       m_key.port = m->local_port;
1189       m_key.protocol = m->proto;
1190       m_key.fib_index = fib_index;
1191       kv.key = m_key.as_u64;
1192       kv.value = m - sm->static_mappings;
1193       if (!out2in_only)
1194         clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1195
1196       m_key.addr = m->external_addr;
1197       m_key.port = m->external_port;
1198       m_key.fib_index = 0;
1199       kv.key = m_key.as_u64;
1200       kv.value = m - sm->static_mappings;
1201       clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
1202
1203       /* Delete dynamic sessions matching local address (+ local port) */
1204       if (!(sm->static_mapping_only))
1205         {
1206           u_key.addr = m->local_addr;
1207           u_key.fib_index = m->fib_index;
1208           kv.key = u_key.as_u64;
1209           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1210             {
1211               user_index = value.value;
1212               u = pool_elt_at_index (tsm->users, user_index);
1213               if (u->nsessions)
1214                 {
1215                   head_index = u->sessions_per_user_list_head_index;
1216                   head = pool_elt_at_index (tsm->list_pool, head_index);
1217                   elt_index = head->next;
1218                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1219                   ses_index = elt->value;
1220                   while (ses_index != ~0)
1221                     {
1222                       s = pool_elt_at_index (tsm->sessions, ses_index);
1223                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1224                       ses_index = elt->value;
1225
1226                       if (snat_is_session_static (s))
1227                         continue;
1228
1229                       if (!addr_only
1230                           && (clib_net_to_host_u16 (s->in2out.port) !=
1231                               m->local_port))
1232                         continue;
1233
1234                       nat_free_session_data (sm, s,
1235                                              tsm - sm->per_thread_data, 0);
1236                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1237
1238                       if (!addr_only && !sm->endpoint_dependent)
1239                         break;
1240                     }
1241                 }
1242             }
1243         }
1244     }
1245   else
1246     {
1247       if (!m)
1248         {
1249           if (sw_if_index != ~0)
1250             return 0;
1251           else
1252             return VNET_API_ERROR_NO_SUCH_ENTRY;
1253         }
1254
1255       if (identity_nat)
1256         {
1257           if (vrf_id == ~0)
1258             vrf_id = sm->inside_vrf_id;
1259
1260           /* *INDENT-OFF* */
1261           pool_foreach (local, m->locals,
1262           ({
1263             if (local->vrf_id == vrf_id)
1264               find = local - m->locals;
1265           }));
1266           /* *INDENT-ON* */
1267           if (find == ~0)
1268             return VNET_API_ERROR_NO_SUCH_ENTRY;
1269
1270           local = pool_elt_at_index (m->locals, find);
1271           fib_index = local->fib_index;
1272           pool_put (m->locals, local);
1273         }
1274       else
1275         fib_index = m->fib_index;
1276
1277       /* Free external address port */
1278       if (!(addr_only || sm->static_mapping_only || out2in_only))
1279         {
1280           for (i = 0; i < vec_len (sm->addresses); i++)
1281             {
1282               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1283                 {
1284                   a = sm->addresses + i;
1285                   switch (proto)
1286                     {
1287 #define _(N, j, n, s) \
1288                     case SNAT_PROTOCOL_##N: \
1289                       --a->busy_##n##_port_refcounts[e_port]; \
1290                       if (e_port > 1024) \
1291                         { \
1292                           a->busy_##n##_ports--; \
1293                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1294                         } \
1295                       break;
1296                       foreach_snat_protocol
1297 #undef _
1298                     default:
1299                       nat_elog_info ("unknown protocol");
1300                       return VNET_API_ERROR_INVALID_VALUE_2;
1301                     }
1302                   break;
1303                 }
1304             }
1305         }
1306
1307       if (sm->num_workers > 1)
1308         tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1309       else
1310         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1311
1312       m_key.addr = m->local_addr;
1313       m_key.port = m->local_port;
1314       m_key.protocol = m->proto;
1315       m_key.fib_index = fib_index;
1316       kv.key = m_key.as_u64;
1317       if (!out2in_only)
1318         clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1319
1320       /* Delete session(s) for static mapping if exist */
1321       if (!(sm->static_mapping_only) ||
1322           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1323         {
1324           if (sm->endpoint_dependent)
1325             {
1326               snat_ed_static_mapping_del_sessions (sm, tsm, m->local_addr,
1327                                                    m->local_port, m->proto,
1328                                                    fib_index, addr_only,
1329                                                    e_addr, e_port);
1330             }
1331           else
1332             {
1333               u_key.addr = m->local_addr;
1334               u_key.fib_index = fib_index;
1335               kv.key = u_key.as_u64;
1336               snat_static_mapping_del_sessions (sm, tsm, u_key, addr_only,
1337                                                 e_addr, e_port);
1338             }
1339         }
1340
1341       fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1342       if (pool_elts (m->locals))
1343         return 0;
1344
1345       m_key.addr = m->external_addr;
1346       m_key.port = m->external_port;
1347       m_key.fib_index = 0;
1348       kv.key = m_key.as_u64;
1349       clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1350
1351       vec_free (m->tag);
1352       vec_free (m->workers);
1353       /* Delete static mapping from pool */
1354       pool_put (sm->static_mappings, m);
1355     }
1356
1357   if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1358     return 0;
1359
1360   /* Add/delete external address to FIB */
1361   /* *INDENT-OFF* */
1362   pool_foreach (interface, sm->interfaces,
1363   ({
1364     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1365       continue;
1366
1367     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1368     break;
1369   }));
1370   pool_foreach (interface, sm->output_feature_interfaces,
1371   ({
1372     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1373       continue;
1374
1375     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1376     break;
1377   }));
1378   /* *INDENT-ON* */
1379
1380   return 0;
1381 }
1382
1383 int
1384 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1385                                  snat_protocol_t proto,
1386                                  nat44_lb_addr_port_t * locals, u8 is_add,
1387                                  twice_nat_type_t twice_nat, u8 out2in_only,
1388                                  u8 * tag, u32 affinity)
1389 {
1390   snat_main_t *sm = &snat_main;
1391   snat_static_mapping_t *m;
1392   snat_session_key_t m_key;
1393   clib_bihash_kv_8_8_t kv, value;
1394   snat_address_t *a = 0;
1395   int i;
1396   nat44_lb_addr_port_t *local;
1397   snat_main_per_thread_data_t *tsm;
1398   snat_session_t *s;
1399   uword *bitmap = 0;
1400
1401   if (!sm->endpoint_dependent)
1402     return VNET_API_ERROR_FEATURE_DISABLED;
1403
1404   m_key.addr = e_addr;
1405   m_key.port = e_port;
1406   m_key.protocol = proto;
1407   m_key.fib_index = 0;
1408   kv.key = m_key.as_u64;
1409   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1410     m = 0;
1411   else
1412     m = pool_elt_at_index (sm->static_mappings, value.value);
1413
1414   if (is_add)
1415     {
1416       if (m)
1417         return VNET_API_ERROR_VALUE_EXIST;
1418
1419       if (vec_len (locals) < 2)
1420         return VNET_API_ERROR_INVALID_VALUE;
1421
1422       /* Find external address in allocated addresses and reserve port for
1423          address and port pair mapping when dynamic translations enabled */
1424       if (!(sm->static_mapping_only || out2in_only))
1425         {
1426           for (i = 0; i < vec_len (sm->addresses); i++)
1427             {
1428               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1429                 {
1430                   a = sm->addresses + i;
1431                   /* External port must be unused */
1432                   switch (proto)
1433                     {
1434 #define _(N, j, n, s) \
1435                     case SNAT_PROTOCOL_##N: \
1436                       if (a->busy_##n##_port_refcounts[e_port]) \
1437                         return VNET_API_ERROR_INVALID_VALUE; \
1438                       ++a->busy_##n##_port_refcounts[e_port]; \
1439                       if (e_port > 1024) \
1440                         { \
1441                           a->busy_##n##_ports++; \
1442                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1443                         } \
1444                       break;
1445                       foreach_snat_protocol
1446 #undef _
1447                     default:
1448                       nat_elog_info ("unknown protocol");
1449                       return VNET_API_ERROR_INVALID_VALUE_2;
1450                     }
1451                   break;
1452                 }
1453             }
1454           /* External address must be allocated */
1455           if (!a)
1456             return VNET_API_ERROR_NO_SUCH_ENTRY;
1457         }
1458
1459       pool_get (sm->static_mappings, m);
1460       clib_memset (m, 0, sizeof (*m));
1461       m->tag = vec_dup (tag);
1462       m->external_addr = e_addr;
1463       m->external_port = e_port;
1464       m->proto = proto;
1465       m->twice_nat = twice_nat;
1466       m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1467       if (out2in_only)
1468         m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1469       m->affinity = affinity;
1470
1471       if (affinity)
1472         m->affinity_per_service_list_head_index =
1473           nat_affinity_get_per_service_list_head_index ();
1474       else
1475         m->affinity_per_service_list_head_index = ~0;
1476
1477       m_key.addr = m->external_addr;
1478       m_key.port = m->external_port;
1479       m_key.protocol = m->proto;
1480       m_key.fib_index = 0;
1481       kv.key = m_key.as_u64;
1482       kv.value = m - sm->static_mappings;
1483       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1484         {
1485           nat_elog_err ("static_mapping_by_external key add failed");
1486           return VNET_API_ERROR_UNSPECIFIED;
1487         }
1488
1489       m_key.fib_index = m->fib_index;
1490       for (i = 0; i < vec_len (locals); i++)
1491         {
1492           locals[i].fib_index =
1493             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1494                                                locals[i].vrf_id,
1495                                                nat_fib_src_low);
1496           m_key.addr = locals[i].addr;
1497           m_key.fib_index = locals[i].fib_index;
1498           if (!out2in_only)
1499             {
1500               m_key.port = locals[i].port;
1501               kv.key = m_key.as_u64;
1502               kv.value = m - sm->static_mappings;
1503               clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1504             }
1505           locals[i].prefix = (i == 0) ? locals[i].probability :
1506             (locals[i - 1].prefix + locals[i].probability);
1507           pool_get (m->locals, local);
1508           *local = locals[i];
1509           if (sm->num_workers > 1)
1510             {
1511               ip4_header_t ip = {
1512                 .src_address = locals[i].addr,
1513               };
1514               bitmap =
1515                 clib_bitmap_set (bitmap,
1516                                  sm->worker_in2out_cb (&ip, m->fib_index, 0),
1517                                  1);
1518             }
1519         }
1520
1521       /* Assign workers */
1522       if (sm->num_workers > 1)
1523         {
1524           /* *INDENT-OFF* */
1525           clib_bitmap_foreach (i, bitmap,
1526             ({
1527                vec_add1(m->workers, i);
1528             }));
1529           /* *INDENT-ON* */
1530         }
1531     }
1532   else
1533     {
1534       if (!m)
1535         return VNET_API_ERROR_NO_SUCH_ENTRY;
1536
1537       if (!is_lb_static_mapping (m))
1538         return VNET_API_ERROR_INVALID_VALUE;
1539
1540       /* Free external address port */
1541       if (!(sm->static_mapping_only || out2in_only))
1542         {
1543           for (i = 0; i < vec_len (sm->addresses); i++)
1544             {
1545               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1546                 {
1547                   a = sm->addresses + i;
1548                   switch (proto)
1549                     {
1550 #define _(N, j, n, s) \
1551                     case SNAT_PROTOCOL_##N: \
1552                       --a->busy_##n##_port_refcounts[e_port]; \
1553                       if (e_port > 1024) \
1554                         { \
1555                           a->busy_##n##_ports--; \
1556                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1557                         } \
1558                       break;
1559                       foreach_snat_protocol
1560 #undef _
1561                     default:
1562                       nat_elog_info ("unknown protocol");
1563                       return VNET_API_ERROR_INVALID_VALUE_2;
1564                     }
1565                   break;
1566                 }
1567             }
1568         }
1569
1570       m_key.addr = m->external_addr;
1571       m_key.port = m->external_port;
1572       m_key.protocol = m->proto;
1573       m_key.fib_index = 0;
1574       kv.key = m_key.as_u64;
1575       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1576         {
1577           nat_elog_err ("static_mapping_by_external key del failed");
1578           return VNET_API_ERROR_UNSPECIFIED;
1579         }
1580
1581       /* *INDENT-OFF* */
1582       pool_foreach (local, m->locals,
1583       ({
1584           fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1585                             nat_fib_src_low);
1586           m_key.addr = local->addr;
1587           if (!out2in_only)
1588             {
1589               m_key.port = local->port;
1590               m_key.fib_index = local->fib_index;
1591               kv.key = m_key.as_u64;
1592               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1593                 {
1594                   nat_elog_err ("static_mapping_by_local key del failed");
1595                   return VNET_API_ERROR_UNSPECIFIED;
1596                 }
1597             }
1598
1599           if (sm->num_workers > 1)
1600             {
1601               ip4_header_t ip = {
1602                 .src_address = local->addr,
1603               };
1604               tsm = vec_elt_at_index (sm->per_thread_data,
1605                                       sm->worker_in2out_cb (&ip, m->fib_index, 0));
1606             }
1607           else
1608             tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1609
1610           /* Delete sessions */
1611           pool_foreach (s, tsm->sessions, {
1612             if (!(is_lb_session (s)))
1613               continue;
1614
1615             if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1616                 (clib_net_to_host_u16 (s->in2out.port) != local->port))
1617               continue;
1618
1619             nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1620             nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
1621           });
1622       }));
1623       /* *INDENT-ON* */
1624       if (m->affinity)
1625         nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1626       pool_free (m->locals);
1627       vec_free (m->tag);
1628       vec_free (m->workers);
1629
1630       pool_put (sm->static_mappings, m);
1631     }
1632
1633   return 0;
1634 }
1635
1636 int
1637 nat44_lb_static_mapping_add_del_local (ip4_address_t e_addr, u16 e_port,
1638                                        ip4_address_t l_addr, u16 l_port,
1639                                        snat_protocol_t proto, u32 vrf_id,
1640                                        u8 probability, u8 is_add)
1641 {
1642   snat_main_t *sm = &snat_main;
1643   snat_static_mapping_t *m = 0;
1644   snat_session_key_t m_key;
1645   clib_bihash_kv_8_8_t kv, value;
1646   nat44_lb_addr_port_t *local, *prev_local, *match_local = 0;
1647   snat_main_per_thread_data_t *tsm;
1648   snat_session_t *s;
1649   u32 *locals = 0;
1650   uword *bitmap = 0;
1651   int i;
1652
1653   if (!sm->endpoint_dependent)
1654     return VNET_API_ERROR_FEATURE_DISABLED;
1655
1656   m_key.addr = e_addr;
1657   m_key.port = e_port;
1658   m_key.protocol = proto;
1659   m_key.fib_index = 0;
1660   kv.key = m_key.as_u64;
1661   if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1662     m = pool_elt_at_index (sm->static_mappings, value.value);
1663
1664   if (!m)
1665     return VNET_API_ERROR_NO_SUCH_ENTRY;
1666
1667   if (!is_lb_static_mapping (m))
1668     return VNET_API_ERROR_INVALID_VALUE;
1669
1670   /* *INDENT-OFF* */
1671   pool_foreach (local, m->locals,
1672   ({
1673     if ((local->addr.as_u32 == l_addr.as_u32) && (local->port == l_port) &&
1674         (local->vrf_id == vrf_id))
1675       {
1676         match_local = local;
1677         break;
1678       }
1679   }));
1680   /* *INDENT-ON* */
1681
1682   if (is_add)
1683     {
1684       if (match_local)
1685         return VNET_API_ERROR_VALUE_EXIST;
1686
1687       pool_get (m->locals, local);
1688       clib_memset (local, 0, sizeof (*local));
1689       local->addr.as_u32 = l_addr.as_u32;
1690       local->port = l_port;
1691       local->probability = probability;
1692       local->vrf_id = vrf_id;
1693       local->fib_index =
1694         fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
1695                                            nat_fib_src_low);
1696
1697       if (!is_out2in_only_static_mapping (m))
1698         {
1699           m_key.addr = l_addr;
1700           m_key.port = l_port;
1701           m_key.fib_index = local->fib_index;
1702           kv.key = m_key.as_u64;
1703           kv.value = m - sm->static_mappings;
1704           if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1))
1705             nat_elog_err ("static_mapping_by_local key add failed");
1706         }
1707     }
1708   else
1709     {
1710       if (!match_local)
1711         return VNET_API_ERROR_NO_SUCH_ENTRY;
1712
1713       if (pool_elts (m->locals) < 3)
1714         return VNET_API_ERROR_UNSPECIFIED;
1715
1716       fib_table_unlock (match_local->fib_index, FIB_PROTOCOL_IP4,
1717                         nat_fib_src_low);
1718
1719       if (!is_out2in_only_static_mapping (m))
1720         {
1721           m_key.addr = l_addr;
1722           m_key.port = l_port;
1723           m_key.fib_index = match_local->fib_index;
1724           kv.key = m_key.as_u64;
1725           if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0))
1726             nat_elog_err ("static_mapping_by_local key del failed");
1727         }
1728
1729       if (sm->num_workers > 1)
1730         {
1731           ip4_header_t ip = {
1732             .src_address = local->addr,
1733           };
1734           tsm = vec_elt_at_index (sm->per_thread_data,
1735                                   sm->worker_in2out_cb (&ip, m->fib_index,
1736                                                         0));
1737         }
1738       else
1739         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1740
1741       /* Delete sessions */
1742       /* *INDENT-OFF* */
1743       pool_foreach (s, tsm->sessions, {
1744         if (!(is_lb_session (s)))
1745           continue;
1746
1747         if ((s->in2out.addr.as_u32 != match_local->addr.as_u32) ||
1748             (clib_net_to_host_u16 (s->in2out.port) != match_local->port))
1749           continue;
1750
1751         nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
1752         nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
1753       });
1754       /* *INDENT-ON* */
1755
1756       pool_put (m->locals, match_local);
1757     }
1758
1759   vec_free (m->workers);
1760
1761   /* *INDENT-OFF* */
1762   pool_foreach (local, m->locals,
1763   ({
1764     vec_add1 (locals, local - m->locals);
1765     if (sm->num_workers > 1)
1766       {
1767         ip4_header_t ip;
1768         ip.src_address.as_u32 = local->addr.as_u32,
1769         bitmap = clib_bitmap_set (bitmap,
1770                                   sm->worker_in2out_cb (&ip, local->fib_index, 0),
1771                                   1);
1772       }
1773   }));
1774   /* *INDENT-ON* */
1775
1776   ASSERT (vec_len (locals) > 1);
1777
1778   local = pool_elt_at_index (m->locals, locals[0]);
1779   local->prefix = local->probability;
1780   for (i = 1; i < vec_len (locals); i++)
1781     {
1782       local = pool_elt_at_index (m->locals, locals[i]);
1783       prev_local = pool_elt_at_index (m->locals, locals[i - 1]);
1784       local->prefix = local->probability + prev_local->prefix;
1785     }
1786
1787   /* Assign workers */
1788   if (sm->num_workers > 1)
1789     {
1790       /* *INDENT-OFF* */
1791       clib_bitmap_foreach (i, bitmap, ({ vec_add1(m->workers, i); }));
1792       /* *INDENT-ON* */
1793     }
1794
1795   return 0;
1796 }
1797
1798 int
1799 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1800                   u8 twice_nat)
1801 {
1802   snat_address_t *a = 0;
1803   snat_session_t *ses;
1804   u32 *ses_to_be_removed = 0, *ses_index;
1805   snat_main_per_thread_data_t *tsm;
1806   snat_static_mapping_t *m;
1807   snat_interface_t *interface;
1808   int i;
1809   snat_address_t *addresses =
1810     twice_nat ? sm->twice_nat_addresses : sm->addresses;
1811
1812   /* Find SNAT address */
1813   for (i = 0; i < vec_len (addresses); i++)
1814     {
1815       if (addresses[i].addr.as_u32 == addr.as_u32)
1816         {
1817           a = addresses + i;
1818           break;
1819         }
1820     }
1821   if (!a)
1822     return VNET_API_ERROR_NO_SUCH_ENTRY;
1823
1824   if (delete_sm)
1825     {
1826       /* *INDENT-OFF* */
1827       pool_foreach (m, sm->static_mappings,
1828       ({
1829           if (m->external_addr.as_u32 == addr.as_u32)
1830             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1831                                             m->local_port, m->external_port,
1832                                             m->vrf_id, is_addr_only_static_mapping(m), ~0,
1833                                             m->proto, 0, m->twice_nat,
1834                                             is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1835       }));
1836       /* *INDENT-ON* */
1837     }
1838   else
1839     {
1840       /* Check if address is used in some static mapping */
1841       if (is_snat_address_used_in_static_mapping (sm, addr))
1842         {
1843           nat_elog_notice ("address used in static mapping");
1844           return VNET_API_ERROR_UNSPECIFIED;
1845         }
1846     }
1847
1848   if (a->fib_index != ~0)
1849     fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, nat_fib_src_low);
1850
1851   /* Delete sessions using address */
1852   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1853     {
1854       /* *INDENT-OFF* */
1855       vec_foreach (tsm, sm->per_thread_data)
1856         {
1857           pool_foreach (ses, tsm->sessions, ({
1858             if (ses->out2in.addr.as_u32 == addr.as_u32)
1859               {
1860                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data, 0);
1861                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1862               }
1863           }));
1864
1865           if (sm->endpoint_dependent){
1866               vec_foreach (ses_index, ses_to_be_removed)
1867                 {
1868                   ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1869                   nat44_ed_delete_session (sm, ses, tsm - sm->per_thread_data, 1);
1870                 }
1871           }else{
1872               vec_foreach (ses_index, ses_to_be_removed)
1873                 {
1874                   ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1875                   nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1876                 }
1877           }
1878
1879           vec_free (ses_to_be_removed);
1880         }
1881       /* *INDENT-ON* */
1882     }
1883
1884 #define _(N, i, n, s) \
1885   vec_free (a->busy_##n##_ports_per_thread);
1886   foreach_snat_protocol
1887 #undef _
1888     if (twice_nat)
1889     {
1890       vec_del1 (sm->twice_nat_addresses, i);
1891       return 0;
1892     }
1893   else
1894     vec_del1 (sm->addresses, i);
1895
1896   /* Delete external address from FIB */
1897   /* *INDENT-OFF* */
1898   pool_foreach (interface, sm->interfaces,
1899   ({
1900     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1901       continue;
1902
1903     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1904     break;
1905   }));
1906   pool_foreach (interface, sm->output_feature_interfaces,
1907   ({
1908     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1909       continue;
1910
1911     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1912     break;
1913   }));
1914   /* *INDENT-ON* */
1915
1916   return 0;
1917 }
1918
1919 int
1920 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1921 {
1922   snat_main_t *sm = &snat_main;
1923   snat_interface_t *i;
1924   const char *feature_name, *del_feature_name;
1925   snat_address_t *ap;
1926   snat_static_mapping_t *m;
1927   snat_det_map_t *dm;
1928   nat_outside_fib_t *outside_fib;
1929   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1930                                                        sw_if_index);
1931
1932   if (sm->out2in_dpo && !is_inside)
1933     return VNET_API_ERROR_UNSUPPORTED;
1934
1935   /* *INDENT-OFF* */
1936   pool_foreach (i, sm->output_feature_interfaces,
1937   ({
1938     if (i->sw_if_index == sw_if_index)
1939       return VNET_API_ERROR_VALUE_EXIST;
1940   }));
1941   /* *INDENT-ON* */
1942
1943   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1944     feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1945   else
1946     {
1947       if (sm->num_workers > 1 && !sm->deterministic)
1948         feature_name =
1949           is_inside ? "nat44-in2out-worker-handoff" :
1950           "nat44-out2in-worker-handoff";
1951       else if (sm->deterministic)
1952         feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1953       else if (sm->endpoint_dependent)
1954         {
1955           feature_name = is_inside ? "nat-pre-in2out" : "nat-pre-out2in";
1956         }
1957       else
1958         feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1959     }
1960
1961   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1962     sm->fq_in2out_index =
1963       vlib_frame_queue_main_init (sm->handoff_in2out_index, NAT_FQ_NELTS);
1964
1965   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1966     sm->fq_out2in_index =
1967       vlib_frame_queue_main_init (sm->handoff_out2in_index, NAT_FQ_NELTS);
1968
1969   if (!is_inside)
1970     {
1971       /* *INDENT-OFF* */
1972       vec_foreach (outside_fib, sm->outside_fibs)
1973         {
1974           if (outside_fib->fib_index == fib_index)
1975             {
1976               if (is_del)
1977                 {
1978                   outside_fib->refcount--;
1979                   if (!outside_fib->refcount)
1980                     vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1981                 }
1982               else
1983                 outside_fib->refcount++;
1984               goto feature_set;
1985             }
1986         }
1987       /* *INDENT-ON* */
1988       if (!is_del)
1989         {
1990           vec_add2 (sm->outside_fibs, outside_fib, 1);
1991           outside_fib->refcount = 1;
1992           outside_fib->fib_index = fib_index;
1993         }
1994     }
1995 feature_set:
1996   /* *INDENT-OFF* */
1997   pool_foreach (i, sm->interfaces,
1998   ({
1999     if (i->sw_if_index == sw_if_index)
2000       {
2001         if (is_del)
2002           {
2003             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
2004               {
2005                 if (is_inside)
2006                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
2007                 else
2008                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
2009
2010                 if (sm->num_workers > 1 && !sm->deterministic)
2011                   {
2012                     del_feature_name = "nat44-handoff-classify";
2013                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
2014                                                  "nat44-out2in-worker-handoff";
2015                   }
2016                 else if (sm->deterministic)
2017                   {
2018                     del_feature_name = "nat44-det-classify";
2019                     feature_name = !is_inside ?  "nat44-det-in2out" :
2020                                                  "nat44-det-out2in";
2021                   }
2022                 else if (sm->endpoint_dependent)
2023                   {
2024                     del_feature_name = "nat44-ed-classify";
2025                     feature_name = !is_inside ?  "nat-pre-in2out" :
2026                                                  "nat-pre-out2in";
2027                   }
2028                 else
2029                   {
2030                     del_feature_name = "nat44-classify";
2031                     feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
2032                   }
2033
2034                 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2035                 if (rv)
2036                   return rv;
2037                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2038                                              sw_if_index, 0, 0, 0);
2039                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2040                                              sw_if_index, 1, 0, 0);
2041                 if (!is_inside)
2042                   {
2043                     if (sm->endpoint_dependent)
2044                       vnet_feature_enable_disable ("ip4-local",
2045                                                    "nat44-ed-hairpinning",
2046                                                    sw_if_index, 1, 0, 0);
2047                     else if (!sm->deterministic)
2048                       vnet_feature_enable_disable ("ip4-local",
2049                                                    "nat44-hairpinning",
2050                                                    sw_if_index, 1, 0, 0);
2051                   }
2052               }
2053             else
2054               {
2055                 int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 0);
2056                 if (rv)
2057                   return rv;
2058                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
2059                                              sw_if_index, 0, 0, 0);
2060                 pool_put (sm->interfaces, i);
2061                 if (is_inside)
2062                   {
2063                     if (sm->endpoint_dependent)
2064                       vnet_feature_enable_disable ("ip4-local",
2065                                                    "nat44-ed-hairpinning",
2066                                                    sw_if_index, 0, 0, 0);
2067                     else if (!sm->deterministic)
2068                       vnet_feature_enable_disable ("ip4-local",
2069                                                    "nat44-hairpinning",
2070                                                    sw_if_index, 0, 0, 0);
2071                   }
2072               }
2073           }
2074         else
2075           {
2076             if ((nat_interface_is_inside(i) && is_inside) ||
2077                 (nat_interface_is_outside(i) && !is_inside))
2078               return 0;
2079
2080             if (sm->num_workers > 1 && !sm->deterministic)
2081               {
2082                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
2083                                                  "nat44-out2in-worker-handoff";
2084                 feature_name = "nat44-handoff-classify";
2085               }
2086             else if (sm->deterministic)
2087               {
2088                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
2089                                                  "nat44-det-out2in";
2090                 feature_name = "nat44-det-classify";
2091               }
2092             else if (sm->endpoint_dependent)
2093               {
2094                 del_feature_name = !is_inside ?  "nat-pre-in2out" :
2095                                                  "nat-pre-out2in";
2096
2097                 feature_name = "nat44-ed-classify";
2098               }
2099             else
2100               {
2101                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
2102                 feature_name = "nat44-classify";
2103               }
2104
2105             int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2106             if (rv)
2107               return rv;
2108             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
2109                                          sw_if_index, 0, 0, 0);
2110             vnet_feature_enable_disable ("ip4-unicast", feature_name,
2111                                          sw_if_index, 1, 0, 0);
2112             if (!is_inside)
2113               {
2114                 if (sm->endpoint_dependent)
2115                   vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2116                                                sw_if_index, 0, 0, 0);
2117                 else if (!sm->deterministic)
2118                   vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2119                                                sw_if_index, 0, 0, 0);
2120               }
2121             goto set_flags;
2122           }
2123
2124         goto fib;
2125       }
2126   }));
2127   /* *INDENT-ON* */
2128
2129   if (is_del)
2130     return VNET_API_ERROR_NO_SUCH_ENTRY;
2131
2132   pool_get (sm->interfaces, i);
2133   i->sw_if_index = sw_if_index;
2134   i->flags = 0;
2135   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
2136                                0);
2137
2138   int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, 1);
2139   if (rv)
2140     return rv;
2141
2142   if (is_inside && !sm->out2in_dpo)
2143     {
2144       if (sm->endpoint_dependent)
2145         vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
2146                                      sw_if_index, 1, 0, 0);
2147       else if (!sm->deterministic)
2148         vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
2149                                      sw_if_index, 1, 0, 0);
2150     }
2151
2152 set_flags:
2153   if (is_inside)
2154     {
2155       i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2156       return 0;
2157     }
2158   else
2159     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2160
2161   /* Add/delete external addresses to FIB */
2162 fib:
2163   /* *INDENT-OFF* */
2164   vec_foreach (ap, sm->addresses)
2165     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2166
2167   pool_foreach (m, sm->static_mappings,
2168   ({
2169     if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
2170       continue;
2171
2172     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2173   }));
2174
2175   pool_foreach (dm, sm->det_maps,
2176   ({
2177     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
2178   }));
2179   /* *INDENT-ON* */
2180
2181   return 0;
2182 }
2183
2184 int
2185 snat_interface_add_del_output_feature (u32 sw_if_index,
2186                                        u8 is_inside, int is_del)
2187 {
2188   snat_main_t *sm = &snat_main;
2189   snat_interface_t *i;
2190   snat_address_t *ap;
2191   snat_static_mapping_t *m;
2192   nat_outside_fib_t *outside_fib;
2193   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
2194                                                        sw_if_index);
2195
2196
2197   if (sm->deterministic ||
2198       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
2199     return VNET_API_ERROR_UNSUPPORTED;
2200
2201   /* *INDENT-OFF* */
2202   pool_foreach (i, sm->interfaces,
2203   ({
2204     if (i->sw_if_index == sw_if_index)
2205       return VNET_API_ERROR_VALUE_EXIST;
2206   }));
2207   /* *INDENT-ON* */
2208
2209   if (!is_inside)
2210     {
2211       /* *INDENT-OFF* */
2212       vec_foreach (outside_fib, sm->outside_fibs)
2213         {
2214           if (outside_fib->fib_index == fib_index)
2215             {
2216               if (is_del)
2217                 {
2218                   outside_fib->refcount--;
2219                   if (!outside_fib->refcount)
2220                     vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2221                 }
2222               else
2223                 outside_fib->refcount++;
2224               goto feature_set;
2225             }
2226         }
2227       /* *INDENT-ON* */
2228       if (!is_del)
2229         {
2230           vec_add2 (sm->outside_fibs, outside_fib, 1);
2231           outside_fib->refcount = 1;
2232           outside_fib->fib_index = fib_index;
2233         }
2234     }
2235
2236 feature_set:
2237   if (is_inside)
2238     {
2239       if (sm->endpoint_dependent)
2240         {
2241           int rv =
2242             ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2243           if (rv)
2244             return rv;
2245           rv =
2246             ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2247                                                             !is_del);
2248           if (rv)
2249             return rv;
2250           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
2251                                        sw_if_index, !is_del, 0, 0);
2252           vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
2253                                        sw_if_index, !is_del, 0, 0);
2254         }
2255       else
2256         {
2257           int rv =
2258             ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2259           if (rv)
2260             return rv;
2261           rv =
2262             ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2263                                                             !is_del);
2264           if (rv)
2265             return rv;
2266           vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
2267                                        sw_if_index, !is_del, 0, 0);
2268           vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
2269                                        sw_if_index, !is_del, 0, 0);
2270         }
2271       goto fq;
2272     }
2273
2274   if (sm->num_workers > 1)
2275     {
2276       int rv = ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2277       if (rv)
2278         return rv;
2279       rv =
2280         ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index, !is_del);
2281       if (rv)
2282         return rv;
2283       vnet_feature_enable_disable ("ip4-unicast",
2284                                    "nat44-out2in-worker-handoff",
2285                                    sw_if_index, !is_del, 0, 0);
2286       vnet_feature_enable_disable ("ip4-output",
2287                                    "nat44-in2out-output-worker-handoff",
2288                                    sw_if_index, !is_del, 0, 0);
2289     }
2290   else
2291     {
2292       if (sm->endpoint_dependent)
2293         {
2294           int rv =
2295             ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2296           if (rv)
2297             return rv;
2298           rv =
2299             ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2300                                                             !is_del);
2301           if (rv)
2302             return rv;
2303           vnet_feature_enable_disable ("ip4-unicast", "nat-pre-out2in",
2304                                        sw_if_index, !is_del, 0, 0);
2305           vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
2306                                        sw_if_index, !is_del, 0, 0);
2307         }
2308       else
2309         {
2310           int rv =
2311             ip4_sv_reass_enable_disable_with_refcnt (sw_if_index, !is_del);
2312           if (rv)
2313             return rv;
2314           rv =
2315             ip4_sv_reass_output_enable_disable_with_refcnt (sw_if_index,
2316                                                             !is_del);
2317           if (rv)
2318             return rv;
2319           vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
2320                                        sw_if_index, !is_del, 0, 0);
2321           vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
2322                                        sw_if_index, !is_del, 0, 0);
2323         }
2324     }
2325
2326 fq:
2327   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
2328     sm->fq_in2out_output_index =
2329       vlib_frame_queue_main_init (sm->handoff_in2out_output_index, 0);
2330
2331   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
2332     sm->fq_out2in_index =
2333       vlib_frame_queue_main_init (sm->handoff_out2in_index, 0);
2334
2335   /* *INDENT-OFF* */
2336   pool_foreach (i, sm->output_feature_interfaces,
2337   ({
2338     if (i->sw_if_index == sw_if_index)
2339       {
2340         if (is_del)
2341           pool_put (sm->output_feature_interfaces, i);
2342         else
2343           return VNET_API_ERROR_VALUE_EXIST;
2344
2345         goto fib;
2346       }
2347   }));
2348   /* *INDENT-ON* */
2349
2350   if (is_del)
2351     return VNET_API_ERROR_NO_SUCH_ENTRY;
2352
2353   pool_get (sm->output_feature_interfaces, i);
2354   i->sw_if_index = sw_if_index;
2355   i->flags = 0;
2356   if (is_inside)
2357     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
2358   else
2359     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
2360
2361   /* Add/delete external addresses to FIB */
2362 fib:
2363   if (is_inside)
2364     return 0;
2365
2366   /* *INDENT-OFF* */
2367   vec_foreach (ap, sm->addresses)
2368     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
2369
2370   pool_foreach (m, sm->static_mappings,
2371   ({
2372     if (!((is_addr_only_static_mapping(m)))  || (m->local_addr.as_u32 == m->external_addr.as_u32))
2373       continue;
2374
2375     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
2376   }));
2377   /* *INDENT-ON* */
2378
2379   return 0;
2380 }
2381
2382 int
2383 snat_set_workers (uword * bitmap)
2384 {
2385   snat_main_t *sm = &snat_main;
2386   int i, j = 0;
2387
2388   if (sm->num_workers < 2)
2389     return VNET_API_ERROR_FEATURE_DISABLED;
2390
2391   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
2392     return VNET_API_ERROR_INVALID_WORKER;
2393
2394   vec_free (sm->workers);
2395   /* *INDENT-OFF* */
2396   clib_bitmap_foreach (i, bitmap,
2397     ({
2398       vec_add1(sm->workers, i);
2399       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
2400       sm->per_thread_data[sm->first_worker_index + i].thread_index = i;
2401       j++;
2402     }));
2403   /* *INDENT-ON* */
2404
2405   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
2406   sm->num_snat_thread = _vec_len (sm->workers);
2407
2408   return 0;
2409 }
2410
2411 static void
2412 snat_update_outside_fib (u32 sw_if_index, u32 new_fib_index,
2413                          u32 old_fib_index)
2414 {
2415   snat_main_t *sm = &snat_main;
2416   nat_outside_fib_t *outside_fib;
2417   snat_interface_t *i;
2418   u8 is_add = 1;
2419   u8 match = 0;
2420
2421   if (new_fib_index == old_fib_index)
2422     return;
2423
2424   if (!vec_len (sm->outside_fibs))
2425     return;
2426
2427   /* *INDENT-OFF* */
2428   pool_foreach (i, sm->interfaces,
2429     ({
2430       if (i->sw_if_index == sw_if_index)
2431         {
2432           if (!(nat_interface_is_outside (i)))
2433             return;
2434           match = 1;
2435         }
2436     }));
2437
2438   pool_foreach (i, sm->output_feature_interfaces,
2439     ({
2440       if (i->sw_if_index == sw_if_index)
2441         {
2442           if (!(nat_interface_is_outside (i)))
2443             return;
2444           match = 1;
2445         }
2446     }));
2447   /* *INDENT-ON* */
2448
2449   if (!match)
2450     return;
2451
2452   vec_foreach (outside_fib, sm->outside_fibs)
2453   {
2454     if (outside_fib->fib_index == old_fib_index)
2455       {
2456         outside_fib->refcount--;
2457         if (!outside_fib->refcount)
2458           vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
2459         break;
2460       }
2461   }
2462
2463   vec_foreach (outside_fib, sm->outside_fibs)
2464   {
2465     if (outside_fib->fib_index == new_fib_index)
2466       {
2467         outside_fib->refcount++;
2468         is_add = 0;
2469         break;
2470       }
2471   }
2472
2473   if (is_add)
2474     {
2475       vec_add2 (sm->outside_fibs, outside_fib, 1);
2476       outside_fib->refcount = 1;
2477       outside_fib->fib_index = new_fib_index;
2478     }
2479 }
2480
2481 static void
2482 snat_ip4_table_bind (ip4_main_t * im,
2483                      uword opaque,
2484                      u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
2485 {
2486   snat_update_outside_fib (sw_if_index, new_fib_index, old_fib_index);
2487 }
2488
2489 static void
2490 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2491                                        uword opaque,
2492                                        u32 sw_if_index,
2493                                        ip4_address_t * address,
2494                                        u32 address_length,
2495                                        u32 if_address_index, u32 is_delete);
2496
2497 static void
2498 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2499                                  uword opaque,
2500                                  u32 sw_if_index,
2501                                  ip4_address_t * address,
2502                                  u32 address_length,
2503                                  u32 if_address_index, u32 is_delete);
2504
2505 static int
2506 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2507                                  u32 fib_index,
2508                                  u32 thread_index,
2509                                  snat_session_key_t * k,
2510                                  u16 port_per_thread, u32 snat_thread_index);
2511
2512 void
2513 test_ed_make_split ()
2514 {
2515   ip4_address_t l_addr;
2516   l_addr.as_u8[0] = 1;
2517   l_addr.as_u8[1] = 1;
2518   l_addr.as_u8[2] = 1;
2519   l_addr.as_u8[3] = 1;
2520   ip4_address_t r_addr;
2521   r_addr.as_u8[0] = 2;
2522   r_addr.as_u8[1] = 2;
2523   r_addr.as_u8[2] = 2;
2524   r_addr.as_u8[3] = 2;
2525   u16 l_port = 40001;
2526   u16 r_port = 40301;
2527   u8 proto = 9;
2528   u32 fib_index = 9000001;
2529   u64 value = ~0ULL;
2530   clib_bihash_kv_16_8_t kv;
2531   make_ed_kv (&l_addr, &r_addr, proto, fib_index, l_port, r_port, value, &kv);
2532   ip4_address_t l_addr2;
2533   ip4_address_t r_addr2;
2534   clib_memset (&l_addr2, 0, sizeof (l_addr2));
2535   clib_memset (&r_addr2, 0, sizeof (r_addr2));
2536   u16 l_port2 = 0;
2537   u16 r_port2 = 0;
2538   u8 proto2 = 0;
2539   u32 fib_index2 = 0;
2540   split_ed_kv (&kv, &l_addr2, &r_addr2, &proto2, &fib_index2, &l_port2,
2541                &r_port2);
2542   u64 value2 = kv.value;
2543   ASSERT (l_addr.as_u32 == l_addr2.as_u32);
2544   ASSERT (r_addr.as_u32 == r_addr2.as_u32);
2545   ASSERT (l_port == l_port2);
2546   ASSERT (r_port == r_port2);
2547   ASSERT (proto == proto2);
2548   ASSERT (fib_index == fib_index2);
2549   ASSERT (value == value2);
2550 }
2551
2552 always_inline vlib_main_t *
2553 nat_get_vlib_main (u32 thread_index)
2554 {
2555   vlib_main_t *vm;
2556   vm = vlib_mains[thread_index];
2557   ASSERT (vm);
2558   return vm;
2559 }
2560
2561 static clib_error_t *
2562 snat_init (vlib_main_t * vm)
2563 {
2564   snat_main_per_thread_data_t *tsm;
2565
2566   snat_main_t *sm = &snat_main;
2567   clib_error_t *error = 0;
2568   ip4_main_t *im = &ip4_main;
2569   ip_lookup_main_t *lm = &im->lookup_main;
2570   uword *p;
2571   vlib_thread_registration_t *tr;
2572   vlib_thread_main_t *tm = vlib_get_thread_main ();
2573   uword *bitmap = 0;
2574   u32 i;
2575   ip4_add_del_interface_address_callback_t cb4;
2576   vlib_node_t *node;
2577
2578   sm->vnet_main = vnet_get_main ();
2579   sm->ip4_main = im;
2580   sm->ip4_lookup_main = lm;
2581   sm->api_main = vlibapi_get_main ();
2582   sm->first_worker_index = 0;
2583   sm->num_workers = 0;
2584   sm->num_snat_thread = 1;
2585   sm->workers = 0;
2586   sm->port_per_thread = 0xffff - 1024;
2587   sm->fq_in2out_index = ~0;
2588   sm->fq_in2out_output_index = ~0;
2589   sm->fq_out2in_index = ~0;
2590
2591   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
2592   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
2593   sm->forwarding_enabled = 0;
2594   sm->log_class = vlib_log_register_class ("nat", 0);
2595   sm->log_level = SNAT_LOG_ERROR;
2596   sm->mss_clamping = 0;
2597
2598   node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
2599   sm->error_node_index = node->index;
2600
2601   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2602   sm->pre_in2out_node_index = node->index;
2603   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2604   sm->pre_out2in_node_index = node->index;
2605
2606   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-in2out");
2607   sm->pre_in2out_node_index = node->index;
2608
2609   node = vlib_get_node_by_name (vm, (u8 *) "nat-pre-out2in");
2610   sm->pre_out2in_node_index = node->index;
2611
2612   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out");
2613   sm->in2out_node_index = node->index;
2614   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output");
2615   sm->in2out_output_node_index = node->index;
2616   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-fast");
2617   sm->in2out_fast_node_index = node->index;
2618   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-slowpath");
2619   sm->in2out_slowpath_node_index = node->index;
2620   node = vlib_get_node_by_name (vm, (u8 *) "nat44-in2out-output-slowpath");
2621   sm->in2out_slowpath_output_node_index = node->index;
2622
2623   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out");
2624   sm->ed_in2out_node_index = node->index;
2625   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-in2out-slowpath");
2626   sm->ed_in2out_slowpath_node_index = node->index;
2627
2628   node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in");
2629   sm->out2in_node_index = node->index;
2630   node = vlib_get_node_by_name (vm, (u8 *) "nat44-out2in-fast");
2631   sm->out2in_fast_node_index = node->index;
2632
2633   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in");
2634   sm->ed_out2in_node_index = node->index;
2635   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-out2in-slowpath");
2636   sm->ed_out2in_slowpath_node_index = node->index;
2637
2638   node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-in2out");
2639   sm->det_in2out_node_index = node->index;
2640   node = vlib_get_node_by_name (vm, (u8 *) "nat44-det-out2in");
2641   sm->det_out2in_node_index = node->index;
2642
2643   node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpinning");
2644   sm->hairpinning_node_index = node->index;
2645   node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-dst");
2646   sm->hairpin_dst_node_index = node->index;
2647   node = vlib_get_node_by_name (vm, (u8 *) "nat44-hairpin-src");
2648   sm->hairpin_src_node_index = node->index;
2649   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpinning");
2650   sm->ed_hairpinning_node_index = node->index;
2651   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-dst");
2652   sm->ed_hairpin_dst_node_index = node->index;
2653   node = vlib_get_node_by_name (vm, (u8 *) "nat44-ed-hairpin-src");
2654   sm->ed_hairpin_src_node_index = node->index;
2655
2656   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
2657   if (p)
2658     {
2659       tr = (vlib_thread_registration_t *) p[0];
2660       if (tr)
2661         {
2662           sm->num_workers = tr->count;
2663           sm->first_worker_index = tr->first_index;
2664         }
2665     }
2666
2667   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2668
2669   /* Use all available workers by default */
2670   if (sm->num_workers > 1)
2671     {
2672       for (i = 0; i < sm->num_workers; i++)
2673         bitmap = clib_bitmap_set (bitmap, i, 1);
2674       // sets thread indexes for workes
2675       snat_set_workers (bitmap);
2676       clib_bitmap_free (bitmap);
2677     }
2678   else
2679     {
2680       sm->per_thread_data[0].snat_thread_index = 0;
2681     }
2682
2683   vec_foreach (tsm, sm->per_thread_data)
2684   {
2685     tsm->vlib_main = nat_get_vlib_main (tsm->thread_index);
2686   }
2687
2688   error = snat_api_init (vm, sm);
2689   if (error)
2690     return error;
2691
2692   /* Set up the interface address add/del callback */
2693   cb4.function = snat_ip4_add_del_interface_address_cb;
2694   cb4.function_opaque = 0;
2695
2696   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2697
2698   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2699   cb4.function_opaque = 0;
2700
2701   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2702
2703   nat_dpo_module_init ();
2704
2705   /* Init counters */
2706   sm->total_users.name = "total-users";
2707   sm->total_users.stat_segment_name = "/nat44/total-users";
2708   vlib_validate_simple_counter (&sm->total_users, 0);
2709   vlib_zero_simple_counter (&sm->total_users, 0);
2710   sm->total_sessions.name = "total-sessions";
2711   sm->total_sessions.stat_segment_name = "/nat44/total-sessions";
2712   vlib_validate_simple_counter (&sm->total_sessions, 0);
2713   vlib_zero_simple_counter (&sm->total_sessions, 0);
2714
2715   /* Init IPFIX logging */
2716   snat_ipfix_logging_init (vm);
2717
2718   /* Init NAT64 */
2719   error = nat64_init (vm);
2720   if (error)
2721     return error;
2722
2723   nat66_init (vm);
2724
2725   ip4_table_bind_callback_t cbt4 = {
2726     .function = snat_ip4_table_bind,
2727   };
2728   vec_add1 (ip4_main.table_bind_callbacks, cbt4);
2729
2730   nat_fib_src_hi = fib_source_allocate ("nat-hi",
2731                                         FIB_SOURCE_PRIORITY_HI,
2732                                         FIB_SOURCE_BH_SIMPLE);
2733   nat_fib_src_low = fib_source_allocate ("nat-low",
2734                                          FIB_SOURCE_PRIORITY_LOW,
2735                                          FIB_SOURCE_BH_SIMPLE);
2736
2737   test_ed_make_split ();
2738   return error;
2739 }
2740
2741 VLIB_INIT_FUNCTION (snat_init);
2742
2743 void
2744 snat_free_outside_address_and_port (snat_address_t * addresses,
2745                                     u32 thread_index, snat_session_key_t * k)
2746 {
2747   snat_address_t *a;
2748   u32 address_index;
2749   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2750
2751   for (address_index = 0; address_index < vec_len (addresses);
2752        address_index++)
2753     {
2754       if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2755         break;
2756     }
2757
2758   ASSERT (address_index < vec_len (addresses));
2759
2760   a = addresses + address_index;
2761
2762   switch (k->protocol)
2763     {
2764 #define _(N, i, n, s) \
2765     case SNAT_PROTOCOL_##N: \
2766       ASSERT (a->busy_##n##_port_refcounts[port_host_byte_order] >= 1); \
2767       --a->busy_##n##_port_refcounts[port_host_byte_order]; \
2768       a->busy_##n##_ports--; \
2769       a->busy_##n##_ports_per_thread[thread_index]--; \
2770       break;
2771       foreach_snat_protocol
2772 #undef _
2773     default:
2774       nat_elog_info ("unknown protocol");
2775       return;
2776     }
2777 }
2778
2779 static int
2780 nat_set_outside_address_and_port (snat_address_t * addresses,
2781                                   u32 thread_index, snat_session_key_t * k)
2782 {
2783   snat_address_t *a = 0;
2784   u32 address_index;
2785   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2786
2787   for (address_index = 0; address_index < vec_len (addresses);
2788        address_index++)
2789     {
2790       if (addresses[address_index].addr.as_u32 != k->addr.as_u32)
2791         continue;
2792
2793       a = addresses + address_index;
2794       switch (k->protocol)
2795         {
2796 #define _(N, j, n, s) \
2797         case SNAT_PROTOCOL_##N: \
2798           if (a->busy_##n##_port_refcounts[port_host_byte_order]) \
2799             return VNET_API_ERROR_INSTANCE_IN_USE; \
2800           ++a->busy_##n##_port_refcounts[port_host_byte_order]; \
2801           a->busy_##n##_ports_per_thread[thread_index]++; \
2802           a->busy_##n##_ports++; \
2803           return 0;
2804           foreach_snat_protocol
2805 #undef _
2806         default:
2807           nat_elog_info ("unknown protocol");
2808           return 1;
2809         }
2810     }
2811
2812   return VNET_API_ERROR_NO_SUCH_ENTRY;
2813 }
2814
2815 int
2816 snat_static_mapping_match (snat_main_t * sm,
2817                            snat_session_key_t match,
2818                            snat_session_key_t * mapping,
2819                            u8 by_external,
2820                            u8 * is_addr_only,
2821                            twice_nat_type_t * twice_nat,
2822                            lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2823                            u8 * is_identity_nat)
2824 {
2825   clib_bihash_kv_8_8_t kv, value;
2826   snat_static_mapping_t *m;
2827   snat_session_key_t m_key;
2828   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2829   u32 rand, lo = 0, hi, mid, *tmp = 0, i;
2830   u8 backend_index;
2831   nat44_lb_addr_port_t *local;
2832
2833   m_key.fib_index = match.fib_index;
2834   if (by_external)
2835     {
2836       mapping_hash = &sm->static_mapping_by_external;
2837       m_key.fib_index = 0;
2838     }
2839
2840   m_key.addr = match.addr;
2841   m_key.port = clib_net_to_host_u16 (match.port);
2842   m_key.protocol = match.protocol;
2843
2844   kv.key = m_key.as_u64;
2845
2846   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2847     {
2848       /* Try address only mapping */
2849       m_key.port = 0;
2850       m_key.protocol = 0;
2851       kv.key = m_key.as_u64;
2852       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2853         return 1;
2854     }
2855
2856   m = pool_elt_at_index (sm->static_mappings, value.value);
2857
2858   if (by_external)
2859     {
2860       if (is_lb_static_mapping (m))
2861         {
2862           if (PREDICT_FALSE (lb != 0))
2863             *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2864           if (m->affinity && !nat_affinity_find_and_lock (ext_host_addr[0],
2865                                                           match.addr,
2866                                                           match.protocol,
2867                                                           match.port,
2868                                                           &backend_index))
2869             {
2870               local = pool_elt_at_index (m->locals, backend_index);
2871               mapping->addr = local->addr;
2872               mapping->port = clib_host_to_net_u16 (local->port);
2873               mapping->fib_index = local->fib_index;
2874               goto end;
2875             }
2876           // pick locals matching this worker
2877           if (PREDICT_FALSE (sm->num_workers > 1))
2878             {
2879               u32 thread_index = vlib_get_thread_index ();
2880               /* *INDENT-OFF* */
2881               pool_foreach_index (i, m->locals,
2882               ({
2883                 local = pool_elt_at_index (m->locals, i);
2884
2885                 ip4_header_t ip = {
2886                   .src_address = local->addr,
2887                 };
2888
2889                 if (sm->worker_in2out_cb (&ip, m->fib_index, 0) ==
2890                     thread_index)
2891                   {
2892                     vec_add1 (tmp, i);
2893                   }
2894               }));
2895               /* *INDENT-ON* */
2896               ASSERT (vec_len (tmp) != 0);
2897             }
2898           else
2899             {
2900               /* *INDENT-OFF* */
2901               pool_foreach_index (i, m->locals,
2902               ({
2903                 vec_add1 (tmp, i);
2904               }));
2905               /* *INDENT-ON* */
2906             }
2907           hi = vec_len (tmp) - 1;
2908           local = pool_elt_at_index (m->locals, tmp[hi]);
2909           rand = 1 + (random_u32 (&sm->random_seed) % local->prefix);
2910           while (lo < hi)
2911             {
2912               mid = ((hi - lo) >> 1) + lo;
2913               local = pool_elt_at_index (m->locals, tmp[mid]);
2914               (rand > local->prefix) ? (lo = mid + 1) : (hi = mid);
2915             }
2916           local = pool_elt_at_index (m->locals, tmp[lo]);
2917           if (!(local->prefix >= rand))
2918             return 1;
2919           mapping->addr = local->addr;
2920           mapping->port = clib_host_to_net_u16 (local->port);
2921           mapping->fib_index = local->fib_index;
2922           if (m->affinity)
2923             {
2924               if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2925                                                 match.protocol, match.port,
2926                                                 tmp[lo], m->affinity,
2927                                                 m->affinity_per_service_list_head_index))
2928                 nat_elog_info ("create affinity record failed");
2929             }
2930           vec_free (tmp);
2931         }
2932       else
2933         {
2934           if (PREDICT_FALSE (lb != 0))
2935             *lb = NO_LB_NAT;
2936           mapping->fib_index = m->fib_index;
2937           mapping->addr = m->local_addr;
2938           /* Address only mapping doesn't change port */
2939           mapping->port = is_addr_only_static_mapping (m) ? match.port
2940             : clib_host_to_net_u16 (m->local_port);
2941         }
2942       mapping->protocol = m->proto;
2943     }
2944   else
2945     {
2946       mapping->addr = m->external_addr;
2947       /* Address only mapping doesn't change port */
2948       mapping->port = is_addr_only_static_mapping (m) ? match.port
2949         : clib_host_to_net_u16 (m->external_port);
2950       mapping->fib_index = sm->outside_fib_index;
2951     }
2952
2953 end:
2954   if (PREDICT_FALSE (is_addr_only != 0))
2955     *is_addr_only = is_addr_only_static_mapping (m);
2956
2957   if (PREDICT_FALSE (twice_nat != 0))
2958     *twice_nat = m->twice_nat;
2959
2960   if (PREDICT_FALSE (is_identity_nat != 0))
2961     *is_identity_nat = is_identity_static_mapping (m);
2962
2963   return 0;
2964 }
2965
2966 static_always_inline u16
2967 snat_random_port (u16 min, u16 max)
2968 {
2969   snat_main_t *sm = &snat_main;
2970   return min + random_u32 (&sm->random_seed) /
2971     (random_u32_max () / (max - min + 1) + 1);
2972 }
2973
2974 int
2975 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2976                                      u32 fib_index,
2977                                      u32 thread_index,
2978                                      snat_session_key_t * k,
2979                                      u16 port_per_thread,
2980                                      u32 snat_thread_index)
2981 {
2982   snat_main_t *sm = &snat_main;
2983
2984   return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2985                                   port_per_thread, snat_thread_index);
2986 }
2987
2988 static int
2989 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2990                                  u32 fib_index,
2991                                  u32 thread_index,
2992                                  snat_session_key_t * k,
2993                                  u16 port_per_thread, u32 snat_thread_index)
2994 {
2995   int i;
2996   snat_address_t *a, *ga = 0;
2997   u32 portnum;
2998
2999   for (i = 0; i < vec_len (addresses); i++)
3000     {
3001       a = addresses + i;
3002       switch (k->protocol)
3003         {
3004 #define _(N, j, n, s) \
3005         case SNAT_PROTOCOL_##N: \
3006           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
3007             { \
3008               if (a->fib_index == fib_index) \
3009                 { \
3010                   while (1) \
3011                     { \
3012                       portnum = (port_per_thread * \
3013                         snat_thread_index) + \
3014                         snat_random_port(1, port_per_thread) + 1024; \
3015                       if (a->busy_##n##_port_refcounts[portnum]) \
3016                         continue; \
3017                       --a->busy_##n##_port_refcounts[portnum]; \
3018                       a->busy_##n##_ports_per_thread[thread_index]++; \
3019                       a->busy_##n##_ports++; \
3020                       k->addr = a->addr; \
3021                       k->port = clib_host_to_net_u16(portnum); \
3022                       return 0; \
3023                     } \
3024                 } \
3025               else if (a->fib_index == ~0) \
3026                 { \
3027                   ga = a; \
3028                 } \
3029             } \
3030           break;
3031           foreach_snat_protocol
3032 #undef _
3033         default:
3034           nat_elog_info ("unknown protocol");
3035           return 1;
3036         }
3037
3038     }
3039
3040   if (ga)
3041     {
3042       a = ga;
3043       switch (k->protocol)
3044         {
3045 #define _(N, j, n, s) \
3046         case SNAT_PROTOCOL_##N: \
3047           while (1) \
3048             { \
3049               portnum = (port_per_thread * \
3050                 snat_thread_index) + \
3051                 snat_random_port(1, port_per_thread) + 1024; \
3052               if (a->busy_##n##_port_refcounts[portnum]) \
3053                 continue; \
3054               ++a->busy_##n##_port_refcounts[portnum]; \
3055               a->busy_##n##_ports_per_thread[thread_index]++; \
3056               a->busy_##n##_ports++; \
3057               k->addr = a->addr; \
3058               k->port = clib_host_to_net_u16(portnum); \
3059               return 0; \
3060             }
3061           break;
3062           foreach_snat_protocol
3063 #undef _
3064         default:
3065           nat_elog_info ("unknown protocol");
3066           return 1;
3067         }
3068     }
3069
3070   /* Totally out of translations to use... */
3071   snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3072   return 1;
3073 }
3074
3075 static int
3076 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
3077                               u32 fib_index,
3078                               u32 thread_index,
3079                               snat_session_key_t * k,
3080                               u16 port_per_thread, u32 snat_thread_index)
3081 {
3082   snat_main_t *sm = &snat_main;
3083   snat_address_t *a = addresses;
3084   u16 m, ports, portnum, A, j;
3085   m = 16 - (sm->psid_offset + sm->psid_length);
3086   ports = (1 << (16 - sm->psid_length)) - (1 << m);
3087
3088   if (!vec_len (addresses))
3089     goto exhausted;
3090
3091   switch (k->protocol)
3092     {
3093 #define _(N, i, n, s) \
3094     case SNAT_PROTOCOL_##N: \
3095       if (a->busy_##n##_ports < ports) \
3096         { \
3097           while (1) \
3098             { \
3099               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
3100               j = snat_random_port(0, pow2_mask(m)); \
3101               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
3102               if (a->busy_##n##_port_refcounts[portnum]) \
3103                 continue; \
3104               ++a->busy_##n##_port_refcounts[portnum]; \
3105               a->busy_##n##_ports++; \
3106               k->addr = a->addr; \
3107               k->port = clib_host_to_net_u16 (portnum); \
3108               return 0; \
3109             } \
3110         } \
3111       break;
3112       foreach_snat_protocol
3113 #undef _
3114     default:
3115       nat_elog_info ("unknown protocol");
3116       return 1;
3117     }
3118
3119 exhausted:
3120   /* Totally out of translations to use... */
3121   snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3122   return 1;
3123 }
3124
3125 static int
3126 nat_alloc_addr_and_port_range (snat_address_t * addresses,
3127                                u32 fib_index,
3128                                u32 thread_index,
3129                                snat_session_key_t * k,
3130                                u16 port_per_thread, u32 snat_thread_index)
3131 {
3132   snat_main_t *sm = &snat_main;
3133   snat_address_t *a = addresses;
3134   u16 portnum, ports;
3135
3136   ports = sm->end_port - sm->start_port + 1;
3137
3138   if (!vec_len (addresses))
3139     goto exhausted;
3140
3141   switch (k->protocol)
3142     {
3143 #define _(N, i, n, s) \
3144     case SNAT_PROTOCOL_##N: \
3145       if (a->busy_##n##_ports < ports) \
3146         { \
3147           while (1) \
3148             { \
3149               portnum = snat_random_port(sm->start_port, sm->end_port); \
3150               if (a->busy_##n##_port_refcounts[portnum]) \
3151                 continue; \
3152               ++a->busy_##n##_port_refcounts[portnum]; \
3153               a->busy_##n##_ports++; \
3154               k->addr = a->addr; \
3155               k->port = clib_host_to_net_u16 (portnum); \
3156               return 0; \
3157             } \
3158         } \
3159       break;
3160       foreach_snat_protocol
3161 #undef _
3162     default:
3163       nat_elog_info ("unknown protocol");
3164       return 1;
3165     }
3166
3167 exhausted:
3168   /* Totally out of translations to use... */
3169   snat_ipfix_logging_addresses_exhausted (thread_index, 0);
3170   return 1;
3171 }
3172
3173 void
3174 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
3175 {
3176   dpo_id_t dpo_v4 = DPO_INVALID;
3177   fib_prefix_t pfx = {
3178     .fp_proto = FIB_PROTOCOL_IP4,
3179     .fp_len = 32,
3180     .fp_addr.ip4.as_u32 = addr.as_u32,
3181   };
3182
3183   if (is_add)
3184     {
3185       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
3186       fib_table_entry_special_dpo_add (0, &pfx, nat_fib_src_hi,
3187                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
3188       dpo_reset (&dpo_v4);
3189     }
3190   else
3191     {
3192       fib_table_entry_special_remove (0, &pfx, nat_fib_src_hi);
3193     }
3194 }
3195
3196 u8 *
3197 format_session_kvp (u8 * s, va_list * args)
3198 {
3199   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3200   snat_session_key_t k;
3201
3202   k.as_u64 = v->key;
3203
3204   s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
3205
3206   return s;
3207 }
3208
3209 u8 *
3210 format_static_mapping_kvp (u8 * s, va_list * args)
3211 {
3212   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3213   snat_session_key_t k;
3214
3215   k.as_u64 = v->key;
3216
3217   s = format (s, "%U static-mapping-index %llu",
3218               format_static_mapping_key, &k, v->value);
3219
3220   return s;
3221 }
3222
3223 u8 *
3224 format_user_kvp (u8 * s, va_list * args)
3225 {
3226   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
3227   snat_user_key_t k;
3228
3229   k.as_u64 = v->key;
3230
3231   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
3232               k.fib_index, v->value);
3233
3234   return s;
3235 }
3236
3237 u8 *
3238 format_ed_session_kvp (u8 * s, va_list * args)
3239 {
3240   clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
3241
3242   u8 proto;
3243   u16 r_port, l_port;
3244   ip4_address_t l_addr, r_addr;
3245   u32 fib_index;
3246
3247   split_ed_kv (v, &l_addr, &r_addr, &proto, &fib_index, &l_port, &r_port);
3248   s =
3249     format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
3250             format_ip4_address, &l_addr, clib_net_to_host_u16 (l_port),
3251             format_ip4_address, &r_addr, clib_net_to_host_u16 (r_port),
3252             format_ip_protocol, proto, fib_index, v->value);
3253
3254   return s;
3255 }
3256
3257 static u32
3258 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0,
3259                            u8 is_output)
3260 {
3261   snat_main_t *sm = &snat_main;
3262   u32 next_worker_index = 0;
3263   u32 hash;
3264
3265   next_worker_index = sm->first_worker_index;
3266   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
3267     (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
3268
3269   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3270     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3271   else
3272     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3273
3274   return next_worker_index;
3275 }
3276
3277 static u32
3278 snat_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip0,
3279                            u32 rx_fib_index0, u8 is_output)
3280 {
3281   snat_main_t *sm = &snat_main;
3282   udp_header_t *udp;
3283   u16 port;
3284   snat_session_key_t m_key;
3285   clib_bihash_kv_8_8_t kv, value;
3286   snat_static_mapping_t *m;
3287   u32 proto;
3288   u32 next_worker_index = 0;
3289
3290   /* first try static mappings without port */
3291   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3292     {
3293       m_key.addr = ip0->dst_address;
3294       m_key.port = 0;
3295       m_key.protocol = 0;
3296       m_key.fib_index = rx_fib_index0;
3297       kv.key = m_key.as_u64;
3298       if (!clib_bihash_search_8_8
3299           (&sm->static_mapping_by_external, &kv, &value))
3300         {
3301           m = pool_elt_at_index (sm->static_mappings, value.value);
3302           return m->workers[0];
3303         }
3304     }
3305
3306   proto = ip_proto_to_snat_proto (ip0->protocol);
3307   udp = ip4_next_header (ip0);
3308   port = udp->dst_port;
3309
3310   /* unknown protocol */
3311   if (PREDICT_FALSE (proto == ~0))
3312     {
3313       /* use current thread */
3314       return vlib_get_thread_index ();
3315     }
3316
3317   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
3318     {
3319       icmp46_header_t *icmp = (icmp46_header_t *) udp;
3320       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3321       if (!icmp_type_is_error_message
3322           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3323         port = vnet_buffer (b)->ip.reass.l4_src_port;
3324       else
3325         {
3326           /* if error message, then it's not fragmented and we can access it */
3327           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3328           proto = ip_proto_to_snat_proto (inner_ip->protocol);
3329           void *l4_header = ip4_next_header (inner_ip);
3330           switch (proto)
3331             {
3332             case SNAT_PROTOCOL_ICMP:
3333               icmp = (icmp46_header_t *) l4_header;
3334               echo = (icmp_echo_header_t *) (icmp + 1);
3335               port = echo->identifier;
3336               break;
3337             case SNAT_PROTOCOL_UDP:
3338             case SNAT_PROTOCOL_TCP:
3339               port = ((tcp_udp_header_t *) l4_header)->src_port;
3340               break;
3341             default:
3342               return vlib_get_thread_index ();
3343             }
3344         }
3345     }
3346
3347   /* try static mappings with port */
3348   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3349     {
3350       m_key.addr = ip0->dst_address;
3351       m_key.port = clib_net_to_host_u16 (port);
3352       m_key.protocol = proto;
3353       m_key.fib_index = rx_fib_index0;
3354       kv.key = m_key.as_u64;
3355       if (!clib_bihash_search_8_8
3356           (&sm->static_mapping_by_external, &kv, &value))
3357         {
3358           m = pool_elt_at_index (sm->static_mappings, value.value);
3359           return m->workers[0];
3360         }
3361     }
3362
3363   /* worker by outside port */
3364   next_worker_index = sm->first_worker_index;
3365   next_worker_index +=
3366     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3367   return next_worker_index;
3368 }
3369
3370 static u32
3371 nat44_ed_get_worker_in2out_cb (ip4_header_t * ip, u32 rx_fib_index,
3372                                u8 is_output)
3373 {
3374   snat_main_t *sm = &snat_main;
3375   u32 next_worker_index = sm->first_worker_index;
3376   u32 hash;
3377
3378   clib_bihash_kv_16_8_t kv16, value16;
3379   snat_main_per_thread_data_t *tsm;
3380   udp_header_t *udp;
3381
3382   if (PREDICT_FALSE (is_output))
3383     {
3384       u32 fib_index = sm->outside_fib_index;
3385       nat_outside_fib_t *outside_fib;
3386       fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3387       fib_prefix_t pfx = {
3388         .fp_proto = FIB_PROTOCOL_IP4,
3389         .fp_len = 32,
3390         .fp_addr = {
3391                     .ip4.as_u32 = ip->dst_address.as_u32,
3392                     }
3393         ,
3394       };
3395
3396       udp = ip4_next_header (ip);
3397
3398       switch (vec_len (sm->outside_fibs))
3399         {
3400         case 0:
3401           fib_index = sm->outside_fib_index;
3402           break;
3403         case 1:
3404           fib_index = sm->outside_fibs[0].fib_index;
3405           break;
3406         default:
3407             /* *INDENT-OFF* */
3408             vec_foreach (outside_fib, sm->outside_fibs)
3409               {
3410                 fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3411                 if (FIB_NODE_INDEX_INVALID != fei)
3412                   {
3413                     if (fib_entry_get_resolving_interface (fei) != ~0)
3414                       {
3415                         fib_index = outside_fib->fib_index;
3416                         break;
3417                       }
3418                   }
3419               }
3420             /* *INDENT-ON* */
3421           break;
3422         }
3423
3424       make_ed_kv (&ip->src_address, &ip->dst_address,
3425                   ip->protocol, fib_index, udp->src_port, udp->dst_port,
3426                   ~0ULL, &kv16);
3427
3428       /* *INDENT-OFF* */
3429       vec_foreach (tsm, sm->per_thread_data)
3430         {
3431           if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3432                                                       &kv16, &value16)))
3433             {
3434               next_worker_index += tsm->thread_index;
3435
3436               nat_elog_debug_handoff (
3437                 "HANDOFF IN2OUT-OUTPUT-FEATURE (session)",
3438                 next_worker_index, fib_index,
3439                 clib_net_to_host_u32 (ip->src_address.as_u32),
3440                 clib_net_to_host_u32 (ip->dst_address.as_u32));
3441
3442               return next_worker_index;
3443             }
3444         }
3445       /* *INDENT-ON* */
3446     }
3447
3448   hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3449     (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3450
3451   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
3452     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
3453   else
3454     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
3455
3456   if (PREDICT_TRUE (!is_output))
3457     {
3458       nat_elog_debug_handoff ("HANDOFF IN2OUT",
3459                               next_worker_index, rx_fib_index,
3460                               clib_net_to_host_u32 (ip->src_address.as_u32),
3461                               clib_net_to_host_u32 (ip->dst_address.as_u32));
3462     }
3463   else
3464     {
3465       nat_elog_debug_handoff ("HANDOFF IN2OUT-OUTPUT-FEATURE",
3466                               next_worker_index, rx_fib_index,
3467                               clib_net_to_host_u32 (ip->src_address.as_u32),
3468                               clib_net_to_host_u32 (ip->dst_address.as_u32));
3469     }
3470
3471   return next_worker_index;
3472 }
3473
3474 static u32
3475 nat44_ed_get_worker_out2in_cb (vlib_buffer_t * b, ip4_header_t * ip,
3476                                u32 rx_fib_index, u8 is_output)
3477 {
3478   snat_main_t *sm = &snat_main;
3479   clib_bihash_kv_8_8_t kv, value;
3480   clib_bihash_kv_16_8_t kv16, value16;
3481   snat_main_per_thread_data_t *tsm;
3482
3483   u32 proto, next_worker_index = 0;
3484   udp_header_t *udp;
3485   u16 port;
3486   snat_static_mapping_t *m;
3487   u32 hash;
3488
3489   proto = ip_proto_to_snat_proto (ip->protocol);
3490
3491   if (PREDICT_TRUE (proto == SNAT_PROTOCOL_UDP || proto == SNAT_PROTOCOL_TCP))
3492     {
3493       udp = ip4_next_header (ip);
3494
3495       make_ed_kv (&ip->dst_address, &ip->src_address,
3496                   ip->protocol, rx_fib_index, udp->dst_port, udp->src_port,
3497                   ~0ULL, &kv16);
3498
3499       /* *INDENT-OFF* */
3500       vec_foreach (tsm, sm->per_thread_data)
3501         {
3502           if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3503                                                       &kv16, &value16)))
3504             {
3505               next_worker_index = sm->first_worker_index + tsm->thread_index;
3506               nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3507                           next_worker_index, rx_fib_index,
3508                           clib_net_to_host_u32 (ip->src_address.as_u32),
3509                           clib_net_to_host_u32 (ip->dst_address.as_u32));
3510               return next_worker_index;
3511             }
3512           }
3513         /* *INDENT-ON* */
3514     }
3515   else if (proto == SNAT_PROTOCOL_ICMP)
3516     {
3517       if (!get_icmp_o2i_ed_key (b, ip, rx_fib_index, ~0ULL, 0, 0, 0, &kv16))
3518         {
3519           /* *INDENT-OFF* */
3520           vec_foreach (tsm, sm->per_thread_data)
3521             {
3522               if (PREDICT_TRUE (!clib_bihash_search_16_8 (&tsm->out2in_ed,
3523                                                           &kv16, &value16)))
3524                 {
3525                   next_worker_index = sm->first_worker_index +
3526                                       tsm->thread_index;
3527                   nat_elog_debug_handoff ("HANDOFF OUT2IN (session)",
3528                               next_worker_index, rx_fib_index,
3529                               clib_net_to_host_u32 (ip->src_address.as_u32),
3530                               clib_net_to_host_u32 (ip->dst_address.as_u32));
3531                   return next_worker_index;
3532                 }
3533             }
3534           /* *INDENT-ON* */
3535         }
3536     }
3537
3538   /* first try static mappings without port */
3539   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3540     {
3541       make_sm_kv (&kv, &ip->dst_address, 0, 0, 0);
3542       if (!clib_bihash_search_8_8
3543           (&sm->static_mapping_by_external, &kv, &value))
3544         {
3545           m = pool_elt_at_index (sm->static_mappings, value.value);
3546           next_worker_index = m->workers[0];
3547           goto done;
3548         }
3549     }
3550
3551   /* unknown protocol */
3552   if (PREDICT_FALSE (proto == ~0))
3553     {
3554       /* use current thread */
3555       next_worker_index = vlib_get_thread_index ();
3556       goto done;
3557     }
3558
3559   udp = ip4_next_header (ip);
3560   port = udp->dst_port;
3561
3562   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
3563     {
3564       icmp46_header_t *icmp = (icmp46_header_t *) udp;
3565       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
3566       if (!icmp_type_is_error_message
3567           (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
3568         port = vnet_buffer (b)->ip.reass.l4_src_port;
3569       else
3570         {
3571           /* if error message, then it's not fragmented and we can access it */
3572           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
3573           proto = ip_proto_to_snat_proto (inner_ip->protocol);
3574           void *l4_header = ip4_next_header (inner_ip);
3575           switch (proto)
3576             {
3577             case SNAT_PROTOCOL_ICMP:
3578               icmp = (icmp46_header_t *) l4_header;
3579               echo = (icmp_echo_header_t *) (icmp + 1);
3580               port = echo->identifier;
3581               break;
3582             case SNAT_PROTOCOL_UDP:
3583             case SNAT_PROTOCOL_TCP:
3584               port = ((tcp_udp_header_t *) l4_header)->src_port;
3585               break;
3586             default:
3587               next_worker_index = vlib_get_thread_index ();
3588               goto done;
3589             }
3590         }
3591     }
3592
3593   /* try static mappings with port */
3594   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
3595     {
3596       make_sm_kv (&kv, &ip->dst_address, proto, 0,
3597                   clib_net_to_host_u16 (port));
3598       if (!clib_bihash_search_8_8
3599           (&sm->static_mapping_by_external, &kv, &value))
3600         {
3601           m = pool_elt_at_index (sm->static_mappings, value.value);
3602           if (!is_lb_static_mapping (m))
3603             {
3604               next_worker_index = m->workers[0];
3605               goto done;
3606             }
3607
3608           hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
3609             (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
3610
3611           if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
3612             next_worker_index =
3613               m->workers[hash & (_vec_len (m->workers) - 1)];
3614           else
3615             next_worker_index = m->workers[hash % _vec_len (m->workers)];
3616           goto done;
3617         }
3618     }
3619
3620   /* worker by outside port */
3621   next_worker_index = sm->first_worker_index;
3622   next_worker_index +=
3623     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
3624
3625 done:
3626   nat_elog_debug_handoff ("HANDOFF OUT2IN", next_worker_index, rx_fib_index,
3627                           clib_net_to_host_u32 (ip->src_address.as_u32),
3628                           clib_net_to_host_u32 (ip->dst_address.as_u32));
3629   return next_worker_index;
3630 }
3631
3632 void
3633 nat_ha_sadd_cb (ip4_address_t * in_addr, u16 in_port,
3634                 ip4_address_t * out_addr, u16 out_port,
3635                 ip4_address_t * eh_addr, u16 eh_port,
3636                 ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3637                 u32 fib_index, u16 flags, u32 thread_index)
3638 {
3639   snat_main_t *sm = &snat_main;
3640   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3641   snat_session_key_t key;
3642   snat_user_t *u;
3643   snat_session_t *s;
3644   clib_bihash_kv_8_8_t kv;
3645   f64 now = vlib_time_now (tsm->vlib_main);
3646   nat_outside_fib_t *outside_fib;
3647   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3648   fib_prefix_t pfx = {
3649     .fp_proto = FIB_PROTOCOL_IP4,
3650     .fp_len = 32,
3651     .fp_addr = {
3652                 .ip4.as_u32 = eh_addr->as_u32,
3653                 },
3654   };
3655
3656   key.addr.as_u32 = out_addr->as_u32;
3657   key.port = out_port;
3658   key.protocol = proto;
3659
3660   if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3661     {
3662       if (nat_set_outside_address_and_port
3663           (sm->addresses, thread_index, &key))
3664         return;
3665     }
3666
3667   u = nat_user_get_or_create (sm, in_addr, fib_index, thread_index);
3668   if (!u)
3669     return;
3670
3671   s = nat_session_alloc_or_recycle (sm, u, thread_index, now);
3672   if (!s)
3673     return;
3674
3675   s->last_heard = now;
3676   s->flags = flags;
3677   s->ext_host_addr.as_u32 = eh_addr->as_u32;
3678   s->ext_host_port = eh_port;
3679   user_session_increment (sm, u, snat_is_session_static (s));
3680   switch (vec_len (sm->outside_fibs))
3681     {
3682     case 0:
3683       key.fib_index = sm->outside_fib_index;
3684       break;
3685     case 1:
3686       key.fib_index = sm->outside_fibs[0].fib_index;
3687       break;
3688     default:
3689       /* *INDENT-OFF* */
3690       vec_foreach (outside_fib, sm->outside_fibs)
3691         {
3692           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3693           if (FIB_NODE_INDEX_INVALID != fei)
3694             {
3695               if (fib_entry_get_resolving_interface (fei) != ~0)
3696                 {
3697                   key.fib_index = outside_fib->fib_index;
3698                   break;
3699                 }
3700             }
3701         }
3702       /* *INDENT-ON* */
3703       break;
3704     }
3705   s->out2in = key;
3706   kv.key = key.as_u64;
3707   kv.value = s - tsm->sessions;
3708   if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 1))
3709     nat_elog_warn ("out2in key add failed");
3710
3711   key.addr.as_u32 = in_addr->as_u32;
3712   key.port = in_port;
3713   key.fib_index = fib_index;
3714   s->in2out = key;
3715   kv.key = key.as_u64;
3716   if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 1))
3717     nat_elog_warn ("in2out key add failed");
3718 }
3719
3720 void
3721 nat_ha_sdel_cb (ip4_address_t * out_addr, u16 out_port,
3722                 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3723                 u32 ti)
3724 {
3725   snat_main_t *sm = &snat_main;
3726   snat_session_key_t key;
3727   clib_bihash_kv_8_8_t kv, value;
3728   u32 thread_index;
3729   snat_session_t *s;
3730   snat_main_per_thread_data_t *tsm;
3731
3732   if (sm->num_workers > 1)
3733     thread_index =
3734       sm->first_worker_index +
3735       (sm->workers[(clib_net_to_host_u16 (out_port) -
3736                     1024) / sm->port_per_thread]);
3737   else
3738     thread_index = sm->num_workers;
3739   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3740
3741   key.addr.as_u32 = out_addr->as_u32;
3742   key.port = out_port;
3743   key.protocol = proto;
3744   key.fib_index = fib_index;
3745   kv.key = key.as_u64;
3746   if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3747     return;
3748
3749   s = pool_elt_at_index (tsm->sessions, value.value);
3750   nat_free_session_data (sm, s, thread_index, 1);
3751   nat44_delete_session (sm, s, thread_index);
3752 }
3753
3754 void
3755 nat_ha_sref_cb (ip4_address_t * out_addr, u16 out_port,
3756                 ip4_address_t * eh_addr, u16 eh_port, u8 proto, u32 fib_index,
3757                 u32 total_pkts, u64 total_bytes, u32 thread_index)
3758 {
3759   snat_main_t *sm = &snat_main;
3760   snat_session_key_t key;
3761   clib_bihash_kv_8_8_t kv, value;
3762   snat_session_t *s;
3763   snat_main_per_thread_data_t *tsm;
3764
3765   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3766
3767   key.addr.as_u32 = out_addr->as_u32;
3768   key.port = out_port;
3769   key.protocol = proto;
3770   key.fib_index = fib_index;
3771   kv.key = key.as_u64;
3772   if (clib_bihash_search_8_8 (&tsm->out2in, &kv, &value))
3773     return;
3774
3775   s = pool_elt_at_index (tsm->sessions, value.value);
3776   s->total_pkts = total_pkts;
3777   s->total_bytes = total_bytes;
3778 }
3779
3780 void
3781 nat_ha_sadd_ed_cb (ip4_address_t * in_addr, u16 in_port,
3782                    ip4_address_t * out_addr, u16 out_port,
3783                    ip4_address_t * eh_addr, u16 eh_port,
3784                    ip4_address_t * ehn_addr, u16 ehn_port, u8 proto,
3785                    u32 fib_index, u16 flags, u32 thread_index)
3786 {
3787   snat_main_t *sm = &snat_main;
3788   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
3789   snat_session_key_t key;
3790   snat_session_t *s;
3791   clib_bihash_kv_16_8_t kv;
3792   f64 now = vlib_time_now (tsm->vlib_main);
3793   nat_outside_fib_t *outside_fib;
3794   fib_node_index_t fei = FIB_NODE_INDEX_INVALID;
3795   fib_prefix_t pfx = {
3796     .fp_proto = FIB_PROTOCOL_IP4,
3797     .fp_len = 32,
3798     .fp_addr = {
3799                 .ip4.as_u32 = eh_addr->as_u32,
3800                 },
3801   };
3802
3803   key.addr.as_u32 = out_addr->as_u32;
3804   key.port = out_port;
3805   key.protocol = proto;
3806
3807   if (!(flags & SNAT_SESSION_FLAG_STATIC_MAPPING))
3808     {
3809       if (nat_set_outside_address_and_port
3810           (sm->addresses, thread_index, &key))
3811         return;
3812     }
3813
3814   key.addr.as_u32 = ehn_addr->as_u32;
3815   key.port = ehn_port;
3816   if (flags & SNAT_SESSION_FLAG_TWICE_NAT)
3817     {
3818       if (nat_set_outside_address_and_port
3819           (sm->twice_nat_addresses, thread_index, &key))
3820         return;
3821     }
3822
3823   s = nat_ed_session_alloc (sm, thread_index, now);
3824   if (!s)
3825     return;
3826
3827   s->last_heard = now;
3828   s->flags = flags;
3829   s->ext_host_nat_addr.as_u32 = s->ext_host_addr.as_u32 = eh_addr->as_u32;
3830   s->ext_host_nat_port = s->ext_host_port = eh_port;
3831   if (is_twice_nat_session (s))
3832     {
3833       s->ext_host_nat_addr.as_u32 = ehn_addr->as_u32;
3834       s->ext_host_nat_port = ehn_port;
3835     }
3836   switch (vec_len (sm->outside_fibs))
3837     {
3838     case 0:
3839       key.fib_index = sm->outside_fib_index;
3840       break;
3841     case 1:
3842       key.fib_index = sm->outside_fibs[0].fib_index;
3843       break;
3844     default:
3845       /* *INDENT-OFF* */
3846       vec_foreach (outside_fib, sm->outside_fibs)
3847         {
3848           fei = fib_table_lookup (outside_fib->fib_index, &pfx);
3849           if (FIB_NODE_INDEX_INVALID != fei)
3850             {
3851               if (fib_entry_get_resolving_interface (fei) != ~0)
3852                 {
3853                   key.fib_index = outside_fib->fib_index;
3854                   break;
3855                 }
3856             }
3857         }
3858       /* *INDENT-ON* */
3859       break;
3860     }
3861   key.addr.as_u32 = out_addr->as_u32;
3862   key.port = out_port;
3863   s->out2in = key;
3864   kv.value = s - tsm->sessions;
3865
3866   key.addr.as_u32 = in_addr->as_u32;
3867   key.port = in_port;
3868   key.fib_index = fib_index;
3869   s->in2out = key;
3870
3871   make_ed_kv (in_addr, &s->ext_host_nat_addr,
3872               snat_proto_to_ip_proto (proto), fib_index, in_port,
3873               s->ext_host_nat_port, s - tsm->sessions, &kv);
3874   if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &kv, 1))
3875     nat_elog_warn ("in2out key add failed");
3876
3877   make_ed_kv (out_addr, eh_addr, snat_proto_to_ip_proto (proto),
3878               s->out2in.fib_index, out_port, eh_port, s - tsm->sessions, &kv);
3879   if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &kv, 1))
3880     nat_elog_warn ("out2in key add failed");
3881 }
3882
3883 void
3884 nat_ha_sdel_ed_cb (ip4_address_t * out_addr, u16 out_port,
3885                    ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3886                    u32 fib_index, u32 ti)
3887 {
3888   snat_main_t *sm = &snat_main;
3889   clib_bihash_kv_16_8_t kv, value;
3890   u32 thread_index;
3891   snat_session_t *s;
3892   snat_main_per_thread_data_t *tsm;
3893
3894   if (sm->num_workers > 1)
3895     thread_index =
3896       sm->first_worker_index +
3897       (sm->workers[(clib_net_to_host_u16 (out_port) -
3898                     1024) / sm->port_per_thread]);
3899   else
3900     thread_index = sm->num_workers;
3901   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3902
3903   make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
3904               &kv);
3905   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3906     return;
3907
3908   s = pool_elt_at_index (tsm->sessions, value.value);
3909   nat_free_session_data (sm, s, thread_index, 1);
3910   nat44_delete_session (sm, s, thread_index);
3911 }
3912
3913 void
3914 nat_ha_sref_ed_cb (ip4_address_t * out_addr, u16 out_port,
3915                    ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3916                    u32 fib_index, u32 total_pkts, u64 total_bytes,
3917                    u32 thread_index)
3918 {
3919   snat_main_t *sm = &snat_main;
3920   clib_bihash_kv_16_8_t kv, value;
3921   snat_session_t *s;
3922   snat_main_per_thread_data_t *tsm;
3923
3924   tsm = vec_elt_at_index (sm->per_thread_data, thread_index);
3925
3926   make_ed_kv (out_addr, eh_addr, proto, fib_index, out_port, eh_port, ~0ULL,
3927               &kv);
3928   if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv, &value))
3929     return;
3930
3931   s = pool_elt_at_index (tsm->sessions, value.value);
3932   s->total_pkts = total_pkts;
3933   s->total_bytes = total_bytes;
3934 }
3935
3936 void
3937 nat44_db_init (snat_main_per_thread_data_t * tsm)
3938 {
3939   snat_main_t *sm = &snat_main;
3940
3941   pool_alloc (tsm->sessions, sm->max_translations);
3942   pool_alloc (tsm->global_lru_pool, sm->max_translations);
3943
3944   dlist_elt_t *head;
3945   pool_get (tsm->global_lru_pool, head);
3946   tsm->global_lru_head_index = head - tsm->global_lru_pool;
3947   clib_dlist_init (tsm->global_lru_pool, tsm->global_lru_head_index);
3948
3949   if (sm->endpoint_dependent)
3950     {
3951       clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
3952                              sm->translation_buckets,
3953                              sm->translation_memory_size);
3954       clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
3955                                           format_ed_session_kvp);
3956       clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
3957                              sm->translation_buckets,
3958                              sm->translation_memory_size);
3959       clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
3960                                           format_ed_session_kvp);
3961     }
3962   else
3963     {
3964       clib_bihash_init_8_8 (&tsm->in2out, "in2out",
3965                             sm->translation_buckets,
3966                             sm->translation_memory_size);
3967       clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out, format_session_kvp);
3968       clib_bihash_init_8_8 (&tsm->out2in, "out2in",
3969                             sm->translation_buckets,
3970                             sm->translation_memory_size);
3971       clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in, format_session_kvp);
3972     }
3973
3974   // TODO: resolve static mappings (put only to !ED)
3975   pool_alloc (tsm->list_pool, sm->max_translations);
3976   clib_bihash_init_8_8 (&tsm->user_hash, "users", sm->user_buckets,
3977                         sm->user_memory_size);
3978   clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash, format_user_kvp);
3979 }
3980
3981 void
3982 nat44_db_free (snat_main_per_thread_data_t * tsm)
3983 {
3984   snat_main_t *sm = &snat_main;
3985
3986   pool_free (tsm->sessions);
3987   pool_free (tsm->global_lru_pool);
3988
3989   if (sm->endpoint_dependent)
3990     {
3991       clib_bihash_free_16_8 (&tsm->in2out_ed);
3992       clib_bihash_free_16_8 (&tsm->out2in_ed);
3993     }
3994   else
3995     {
3996       clib_bihash_free_8_8 (&tsm->in2out);
3997       clib_bihash_free_8_8 (&tsm->out2in);
3998     }
3999
4000   // TODO: resolve static mappings (put only to !ED)
4001   pool_free (tsm->users);
4002   pool_free (tsm->list_pool);
4003   clib_bihash_free_8_8 (&tsm->user_hash);
4004 }
4005
4006 static clib_error_t *
4007 snat_config (vlib_main_t * vm, unformat_input_t * input)
4008 {
4009   snat_main_t *sm = &snat_main;
4010   nat66_main_t *nm = &nat66_main;
4011   //dslite_main_t *dm = &dslite_main;
4012   snat_main_per_thread_data_t *tsm;
4013
4014   u32 static_mapping_buckets = 1024;
4015   uword static_mapping_memory_size = 64 << 20;
4016
4017   u32 nat64_bib_buckets = 1024;
4018   u32 nat64_bib_memory_size = 128 << 20;
4019
4020   u32 nat64_st_buckets = 2048;
4021   uword nat64_st_memory_size = 256 << 20;
4022
4023   u32 user_buckets = 128;
4024   uword user_memory_size = 64 << 20;
4025   u32 translation_buckets = 1024;
4026   uword translation_memory_size = 128 << 20;
4027
4028   u32 max_translations_per_user = ~0;
4029
4030   u32 outside_vrf_id = 0;
4031   u32 outside_ip6_vrf_id = 0;
4032   u32 inside_vrf_id = 0;
4033   u8 static_mapping_only = 0;
4034   u8 static_mapping_connection_tracking = 0;
4035
4036   // configurable timeouts
4037   u32 udp_timeout = SNAT_UDP_TIMEOUT;
4038   u32 icmp_timeout = SNAT_ICMP_TIMEOUT;
4039   u32 tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
4040   u32 tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
4041
4042   sm->deterministic = 0;
4043   sm->out2in_dpo = 0;
4044   sm->endpoint_dependent = 0;
4045
4046   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4047     {
4048       if (unformat
4049           (input, "translation hash buckets %d", &translation_buckets))
4050         ;
4051       else if (unformat (input, "udp timeout %d", &udp_timeout))
4052         ;
4053       else if (unformat (input, "icmp timeout %d", &icmp_timeout))
4054         ;
4055       else if (unformat (input, "tcp transitory timeout %d",
4056                          &tcp_transitory_timeout));
4057       else if (unformat (input, "tcp established timeout %d",
4058                          &tcp_established_timeout));
4059       else if (unformat (input, "translation hash memory %d",
4060                          &translation_memory_size));
4061       else if (unformat (input, "user hash buckets %d", &user_buckets))
4062         ;
4063       else if (unformat (input, "user hash memory %d", &user_memory_size))
4064         ;
4065       else if (unformat (input, "max translations per user %d",
4066                          &max_translations_per_user))
4067         ;
4068       else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
4069         ;
4070       else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
4071         ;
4072       else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
4073         ;
4074       else if (unformat (input, "static mapping only"))
4075         {
4076           static_mapping_only = 1;
4077           if (unformat (input, "connection tracking"))
4078             static_mapping_connection_tracking = 1;
4079         }
4080       else if (unformat (input, "deterministic"))
4081         sm->deterministic = 1;
4082       else if (unformat (input, "nat64 bib hash buckets %d",
4083                          &nat64_bib_buckets))
4084         ;
4085       else if (unformat (input, "nat64 bib hash memory %d",
4086                          &nat64_bib_memory_size))
4087         ;
4088       else
4089         if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
4090         ;
4091       else if (unformat (input, "nat64 st hash memory %d",
4092                          &nat64_st_memory_size))
4093         ;
4094       else if (unformat (input, "out2in dpo"))
4095         sm->out2in_dpo = 1;
4096       //else if (unformat (input, "dslite ce"))
4097       //dslite_set_ce (dm, 1);
4098       else if (unformat (input, "endpoint-dependent"))
4099         sm->endpoint_dependent = 1;
4100       else
4101         return clib_error_return (0, "unknown input '%U'",
4102                                   format_unformat_error, input);
4103     }
4104
4105   if (sm->deterministic && sm->endpoint_dependent)
4106     return clib_error_return (0,
4107                               "deterministic and endpoint-dependent modes are mutually exclusive");
4108
4109   if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
4110     return clib_error_return (0,
4111                               "static mapping only mode available only for simple nat");
4112
4113   if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
4114     return clib_error_return (0,
4115                               "out2in dpo mode available only for simple nat");
4116
4117   /* optionally configurable timeouts for testing purposes */
4118   sm->udp_timeout = udp_timeout;
4119   sm->tcp_transitory_timeout = tcp_transitory_timeout;
4120   sm->tcp_established_timeout = tcp_established_timeout;
4121   sm->icmp_timeout = icmp_timeout;
4122
4123   sm->user_buckets = user_buckets;
4124   sm->user_memory_size = user_memory_size;
4125
4126   sm->translation_buckets = translation_buckets;
4127   sm->translation_memory_size = translation_memory_size;
4128   /* do not exceed load factor 10 */
4129   sm->max_translations = 10 * translation_buckets;
4130   vec_add1 (sm->max_translations_per_fib, sm->max_translations);
4131
4132   sm->max_translations_per_user = max_translations_per_user == ~0 ?
4133     sm->max_translations : max_translations_per_user;
4134
4135   sm->outside_vrf_id = outside_vrf_id;
4136   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4137                                                              outside_vrf_id,
4138                                                              nat_fib_src_hi);
4139   nm->outside_vrf_id = outside_ip6_vrf_id;
4140   nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
4141                                                              outside_ip6_vrf_id,
4142                                                              nat_fib_src_hi);
4143   sm->inside_vrf_id = inside_vrf_id;
4144   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
4145                                                             inside_vrf_id,
4146                                                             nat_fib_src_hi);
4147   sm->static_mapping_only = static_mapping_only;
4148   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
4149
4150   nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
4151                   nat64_st_memory_size);
4152
4153   if (sm->deterministic)
4154     {
4155       sm->in2out_node_index = snat_det_in2out_node.index;
4156       sm->in2out_output_node_index = ~0;
4157       sm->out2in_node_index = snat_det_out2in_node.index;
4158       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
4159       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
4160     }
4161   else
4162     {
4163       if (sm->endpoint_dependent)
4164         {
4165           sm->worker_in2out_cb = nat44_ed_get_worker_in2out_cb;
4166           sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
4167
4168           sm->handoff_out2in_index = nat_pre_out2in_node.index;
4169           sm->handoff_in2out_index = nat_pre_in2out_node.index;
4170           sm->handoff_in2out_output_index = nat44_ed_in2out_output_node.index;
4171
4172           sm->in2out_node_index = nat44_ed_in2out_node.index;
4173           sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
4174           sm->out2in_node_index = nat44_ed_out2in_node.index;
4175
4176           sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
4177           sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
4178           nat_affinity_init (vm);
4179           nat_ha_init (vm, nat_ha_sadd_ed_cb, nat_ha_sdel_ed_cb,
4180                        nat_ha_sref_ed_cb);
4181         }
4182       else
4183         {
4184           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
4185           sm->worker_out2in_cb = snat_get_worker_out2in_cb;
4186
4187           sm->handoff_out2in_index = snat_out2in_node.index;
4188           sm->handoff_in2out_index = snat_in2out_node.index;
4189           sm->handoff_in2out_output_index = snat_in2out_output_node.index;
4190
4191           sm->in2out_node_index = snat_in2out_node.index;
4192           sm->in2out_output_node_index = snat_in2out_output_node.index;
4193           sm->out2in_node_index = snat_out2in_node.index;
4194           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
4195           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
4196           nat_ha_init (vm, nat_ha_sadd_cb, nat_ha_sdel_cb, nat_ha_sref_cb);
4197         }
4198       if (!static_mapping_only ||
4199           (static_mapping_only && static_mapping_connection_tracking))
4200         {
4201           /* *INDENT-OFF* */
4202           vec_foreach (tsm, sm->per_thread_data)
4203             {
4204               nat44_db_init (tsm);
4205             }
4206           /* *INDENT-ON* */
4207         }
4208       else
4209         {
4210           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
4211           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
4212         }
4213       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
4214                             "static_mapping_by_local", static_mapping_buckets,
4215                             static_mapping_memory_size);
4216       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
4217                                          format_static_mapping_kvp);
4218
4219       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
4220                             "static_mapping_by_external",
4221                             static_mapping_buckets,
4222                             static_mapping_memory_size);
4223       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
4224                                          format_static_mapping_kvp);
4225     }
4226
4227   return 0;
4228 }
4229
4230 VLIB_CONFIG_FUNCTION (snat_config, "nat");
4231
4232 static void
4233 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
4234                                  uword opaque,
4235                                  u32 sw_if_index,
4236                                  ip4_address_t * address,
4237                                  u32 address_length,
4238                                  u32 if_address_index, u32 is_delete)
4239 {
4240   snat_main_t *sm = &snat_main;
4241   snat_static_map_resolve_t *rp;
4242   snat_static_mapping_t *m;
4243   snat_session_key_t m_key;
4244   clib_bihash_kv_8_8_t kv, value;
4245   int i, rv;
4246   ip4_address_t l_addr;
4247
4248   for (i = 0; i < vec_len (sm->to_resolve); i++)
4249     {
4250       rp = sm->to_resolve + i;
4251       if (rp->addr_only == 0)
4252         continue;
4253       if (rp->sw_if_index == sw_if_index)
4254         goto match;
4255     }
4256
4257   return;
4258
4259 match:
4260   m_key.addr.as_u32 = address->as_u32;
4261   m_key.port = rp->addr_only ? 0 : rp->e_port;
4262   m_key.protocol = rp->addr_only ? 0 : rp->proto;
4263   m_key.fib_index = sm->outside_fib_index;
4264   kv.key = m_key.as_u64;
4265   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
4266     m = 0;
4267   else
4268     m = pool_elt_at_index (sm->static_mappings, value.value);
4269
4270   if (!is_delete)
4271     {
4272       /* Don't trip over lease renewal, static config */
4273       if (m)
4274         return;
4275     }
4276   else
4277     {
4278       if (!m)
4279         return;
4280     }
4281
4282   /* Indetity mapping? */
4283   if (rp->l_addr.as_u32 == 0)
4284     l_addr.as_u32 = address[0].as_u32;
4285   else
4286     l_addr.as_u32 = rp->l_addr.as_u32;
4287   /* Add the static mapping */
4288   rv = snat_add_static_mapping (l_addr,
4289                                 address[0],
4290                                 rp->l_port,
4291                                 rp->e_port,
4292                                 rp->vrf_id,
4293                                 rp->addr_only, ~0 /* sw_if_index */ ,
4294                                 rp->proto, !is_delete, rp->twice_nat,
4295                                 rp->out2in_only, rp->tag, rp->identity_nat);
4296   if (rv)
4297     nat_elog_notice_X1 ("snat_add_static_mapping returned %d", "i4", rv);
4298 }
4299
4300 static void
4301 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
4302                                        uword opaque,
4303                                        u32 sw_if_index,
4304                                        ip4_address_t * address,
4305                                        u32 address_length,
4306                                        u32 if_address_index, u32 is_delete)
4307 {
4308   snat_main_t *sm = &snat_main;
4309   snat_static_map_resolve_t *rp;
4310   ip4_address_t l_addr;
4311   int i, j;
4312   int rv;
4313   u8 twice_nat = 0;
4314   snat_address_t *addresses = sm->addresses;
4315
4316   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
4317     {
4318       if (sw_if_index == sm->auto_add_sw_if_indices[i])
4319         goto match;
4320     }
4321
4322   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
4323     {
4324       twice_nat = 1;
4325       addresses = sm->twice_nat_addresses;
4326       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
4327         goto match;
4328     }
4329
4330   return;
4331
4332 match:
4333   if (!is_delete)
4334     {
4335       /* Don't trip over lease renewal, static config */
4336       for (j = 0; j < vec_len (addresses); j++)
4337         if (addresses[j].addr.as_u32 == address->as_u32)
4338           return;
4339
4340       (void) snat_add_address (sm, address, ~0, twice_nat);
4341       /* Scan static map resolution vector */
4342       for (j = 0; j < vec_len (sm->to_resolve); j++)
4343         {
4344           rp = sm->to_resolve + j;
4345           if (rp->addr_only)
4346             continue;
4347           /* On this interface? */
4348           if (rp->sw_if_index == sw_if_index)
4349             {
4350               /* Indetity mapping? */
4351               if (rp->l_addr.as_u32 == 0)
4352                 l_addr.as_u32 = address[0].as_u32;
4353               else
4354                 l_addr.as_u32 = rp->l_addr.as_u32;
4355               /* Add the static mapping */
4356               rv = snat_add_static_mapping (l_addr,
4357                                             address[0],
4358                                             rp->l_port,
4359                                             rp->e_port,
4360                                             rp->vrf_id,
4361                                             rp->addr_only,
4362                                             ~0 /* sw_if_index */ ,
4363                                             rp->proto,
4364                                             rp->is_add, rp->twice_nat,
4365                                             rp->out2in_only, rp->tag,
4366                                             rp->identity_nat);
4367               if (rv)
4368                 nat_elog_notice_X1 ("snat_add_static_mapping returned %d",
4369                                     "i4", rv);
4370             }
4371         }
4372       return;
4373     }
4374   else
4375     {
4376       (void) snat_del_address (sm, address[0], 1, twice_nat);
4377       return;
4378     }
4379 }
4380
4381
4382 int
4383 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
4384                             u8 twice_nat)
4385 {
4386   ip4_main_t *ip4_main = sm->ip4_main;
4387   ip4_address_t *first_int_addr;
4388   snat_static_map_resolve_t *rp;
4389   u32 *indices_to_delete = 0;
4390   int i, j;
4391   u32 *auto_add_sw_if_indices =
4392     twice_nat ? sm->
4393     auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
4394
4395   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0        /* just want the address */
4396     );
4397
4398   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
4399     {
4400       if (auto_add_sw_if_indices[i] == sw_if_index)
4401         {
4402           if (is_del)
4403             {
4404               /* if have address remove it */
4405               if (first_int_addr)
4406                 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
4407               else
4408                 {
4409                   for (j = 0; j < vec_len (sm->to_resolve); j++)
4410                     {
4411                       rp = sm->to_resolve + j;
4412                       if (rp->sw_if_index == sw_if_index)
4413                         vec_add1 (indices_to_delete, j);
4414                     }
4415                   if (vec_len (indices_to_delete))
4416                     {
4417                       for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
4418                         vec_del1 (sm->to_resolve, j);
4419                       vec_free (indices_to_delete);
4420                     }
4421                 }
4422               if (twice_nat)
4423                 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
4424               else
4425                 vec_del1 (sm->auto_add_sw_if_indices, i);
4426             }
4427           else
4428             return VNET_API_ERROR_VALUE_EXIST;
4429
4430           return 0;
4431         }
4432     }
4433
4434   if (is_del)
4435     return VNET_API_ERROR_NO_SUCH_ENTRY;
4436
4437   /* add to the auto-address list */
4438   if (twice_nat)
4439     vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
4440   else
4441     vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
4442
4443   /* If the address is already bound - or static - add it now */
4444   if (first_int_addr)
4445     (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
4446
4447   return 0;
4448 }
4449
4450 int
4451 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4452                    snat_protocol_t proto, u32 vrf_id, int is_in)
4453 {
4454   snat_main_per_thread_data_t *tsm;
4455   clib_bihash_kv_8_8_t kv, value;
4456   ip4_header_t ip;
4457   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4458   snat_session_key_t key;
4459   snat_session_t *s;
4460   clib_bihash_8_8_t *t;
4461
4462   if (sm->endpoint_dependent)
4463     return VNET_API_ERROR_UNSUPPORTED;
4464
4465   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4466   if (sm->num_workers > 1)
4467     tsm =
4468       vec_elt_at_index (sm->per_thread_data,
4469                         sm->worker_in2out_cb (&ip, fib_index, 0));
4470   else
4471     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4472
4473   key.addr.as_u32 = addr->as_u32;
4474   key.port = clib_host_to_net_u16 (port);
4475   key.protocol = proto;
4476   key.fib_index = fib_index;
4477   kv.key = key.as_u64;
4478   t = is_in ? &tsm->in2out : &tsm->out2in;
4479   if (!clib_bihash_search_8_8 (t, &kv, &value))
4480     {
4481       if (pool_is_free_index (tsm->sessions, value.value))
4482         return VNET_API_ERROR_UNSPECIFIED;
4483
4484       s = pool_elt_at_index (tsm->sessions, value.value);
4485       nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4486       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
4487       return 0;
4488     }
4489
4490   return VNET_API_ERROR_NO_SUCH_ENTRY;
4491 }
4492
4493 int
4494 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
4495                       ip4_address_t * eh_addr, u16 eh_port, u8 proto,
4496                       u32 vrf_id, int is_in)
4497 {
4498   ip4_header_t ip;
4499   clib_bihash_16_8_t *t;
4500   clib_bihash_kv_16_8_t kv, value;
4501   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
4502   snat_session_t *s;
4503   snat_main_per_thread_data_t *tsm;
4504
4505   if (!sm->endpoint_dependent)
4506     return VNET_API_ERROR_FEATURE_DISABLED;
4507
4508   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
4509   if (sm->num_workers > 1)
4510     tsm =
4511       vec_elt_at_index (sm->per_thread_data,
4512                         sm->worker_in2out_cb (&ip, fib_index, 0));
4513   else
4514     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
4515
4516   t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
4517   make_ed_kv (addr, eh_addr, proto, fib_index, clib_host_to_net_u16 (port),
4518               clib_host_to_net_u16 (eh_port), ~0ULL, &kv);
4519   if (clib_bihash_search_16_8 (t, &kv, &value))
4520     {
4521       return VNET_API_ERROR_NO_SUCH_ENTRY;
4522     }
4523
4524   if (pool_is_free_index (tsm->sessions, value.value))
4525     return VNET_API_ERROR_UNSPECIFIED;
4526   s = pool_elt_at_index (tsm->sessions, value.value);
4527   nat_free_session_data (sm, s, tsm - sm->per_thread_data, 0);
4528   nat44_ed_delete_session (sm, s, tsm - sm->per_thread_data, 1);
4529   return 0;
4530 }
4531
4532 void
4533 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
4534 {
4535   snat_main_t *sm = &snat_main;
4536
4537   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
4538   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
4539   sm->psid = psid;
4540   sm->psid_offset = psid_offset;
4541   sm->psid_length = psid_length;
4542 }
4543
4544 void
4545 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
4546 {
4547   snat_main_t *sm = &snat_main;
4548
4549   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
4550   sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
4551   sm->start_port = start_port;
4552   sm->end_port = end_port;
4553 }
4554
4555 void
4556 nat_set_alloc_addr_and_port_default (void)
4557 {
4558   snat_main_t *sm = &snat_main;
4559
4560   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
4561   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
4562 }
4563
4564 VLIB_NODE_FN (nat_default_node) (vlib_main_t * vm,
4565                                  vlib_node_runtime_t * node,
4566                                  vlib_frame_t * frame)
4567 {
4568   return 0;
4569 }
4570
4571 /* *INDENT-OFF* */
4572 VLIB_REGISTER_NODE (nat_default_node) = {
4573   .name = "nat-default",
4574   .vector_size = sizeof (u32),
4575   .format_trace = 0,
4576   .type = VLIB_NODE_TYPE_INTERNAL,
4577   .n_errors = 0,
4578   .n_next_nodes = NAT_N_NEXT,
4579   .next_nodes = {
4580     [NAT_NEXT_DROP] = "error-drop",
4581     [NAT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
4582     [NAT_NEXT_IN2OUT_PRE] = "nat-pre-in2out",
4583     [NAT_NEXT_OUT2IN_PRE] = "nat-pre-out2in",
4584     [NAT_NEXT_IN2OUT_ED_FAST_PATH] = "nat44-ed-in2out",
4585     [NAT_NEXT_IN2OUT_ED_SLOW_PATH] = "nat44-ed-in2out-slowpath",
4586     [NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH] = "nat44-ed-in2out-output-slowpath",
4587     [NAT_NEXT_OUT2IN_ED_FAST_PATH] = "nat44-ed-out2in",
4588     [NAT_NEXT_OUT2IN_ED_SLOW_PATH] = "nat44-ed-out2in-slowpath",
4589   },
4590 };
4591 /* *INDENT-ON* */
4592
4593 /*
4594  * fd.io coding-style-patch-verification: ON
4595  *
4596  * Local Variables:
4597  * eval: (c-set-style "gnu")
4598  * End:
4599  */