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