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