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