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