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