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