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