NAT44: improve expired sessions reuse (VPP-1503)
[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 <vnet/fib/fib_table.h>
33 #include <vnet/fib/ip4_fib.h>
34
35 #include <vpp/app/version.h>
36
37 snat_main_t snat_main;
38
39 /* *INDENT-OFF* */
40
41 /* Hook up input features */
42 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
43   .arc_name = "ip4-unicast",
44   .node_name = "nat44-in2out",
45   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
46 };
47 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
48   .arc_name = "ip4-unicast",
49   .node_name = "nat44-out2in",
50   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
51                                "ip4-dhcp-client-detect"),
52 };
53 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
54   .arc_name = "ip4-unicast",
55   .node_name = "nat44-classify",
56   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
57 };
58 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
59   .arc_name = "ip4-unicast",
60   .node_name = "nat44-det-in2out",
61   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
62 };
63 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
64   .arc_name = "ip4-unicast",
65   .node_name = "nat44-det-out2in",
66   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
67                                "ip4-dhcp-client-detect"),
68 };
69 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
70   .arc_name = "ip4-unicast",
71   .node_name = "nat44-det-classify",
72   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
73 };
74 VNET_FEATURE_INIT (ip4_nat44_ed_in2out, static) = {
75   .arc_name = "ip4-unicast",
76   .node_name = "nat44-ed-in2out",
77   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
78 };
79 VNET_FEATURE_INIT (ip4_nat44_ed_out2in, static) = {
80   .arc_name = "ip4-unicast",
81   .node_name = "nat44-ed-out2in",
82   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
83                                "ip4-dhcp-client-detect"),
84 };
85 VNET_FEATURE_INIT (ip4_nat44_ed_classify, static) = {
86   .arc_name = "ip4-unicast",
87   .node_name = "nat44-ed-classify",
88   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
89 };
90 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
91   .arc_name = "ip4-unicast",
92   .node_name = "nat44-in2out-worker-handoff",
93   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
94 };
95 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
96   .arc_name = "ip4-unicast",
97   .node_name = "nat44-out2in-worker-handoff",
98   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
99                                "ip4-dhcp-client-detect"),
100 };
101 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
102   .arc_name = "ip4-unicast",
103   .node_name = "nat44-handoff-classify",
104   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
105 };
106 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
107   .arc_name = "ip4-unicast",
108   .node_name = "nat44-in2out-fast",
109   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
110 };
111 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
112   .arc_name = "ip4-unicast",
113   .node_name = "nat44-out2in-fast",
114   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa",
115                                "ip4-dhcp-client-detect"),
116 };
117 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
118   .arc_name = "ip4-unicast",
119   .node_name = "nat44-hairpin-dst",
120   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
121 };
122 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_dst, static) = {
123   .arc_name = "ip4-unicast",
124   .node_name = "nat44-ed-hairpin-dst",
125   .runs_after = VNET_FEATURES ("acl-plugin-in-ip4-fa"),
126 };
127
128 /* Hook up output features */
129 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
130   .arc_name = "ip4-output",
131   .node_name = "nat44-in2out-output",
132   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
133 };
134 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
135   .arc_name = "ip4-output",
136   .node_name = "nat44-in2out-output-worker-handoff",
137   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
138 };
139 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
140   .arc_name = "ip4-output",
141   .node_name = "nat44-hairpin-src",
142   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
143 };
144 VNET_FEATURE_INIT (ip4_nat44_ed_in2out_output, static) = {
145   .arc_name = "ip4-output",
146   .node_name = "nat44-ed-in2out-output",
147   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
148 };
149 VNET_FEATURE_INIT (ip4_nat44_ed_hairpin_src, static) = {
150   .arc_name = "ip4-output",
151   .node_name = "nat44-ed-hairpin-src",
152   .runs_after = VNET_FEATURES ("acl-plugin-out-ip4-fa"),
153 };
154
155 /* Hook up ip4-local features */
156 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
157 {
158   .arc_name = "ip4-local",
159   .node_name = "nat44-hairpinning",
160   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
161 };
162 VNET_FEATURE_INIT (ip4_nat44_ed_hairpinning, static) =
163 {
164   .arc_name = "ip4-local",
165   .node_name = "nat44-ed-hairpinning",
166   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
167 };
168
169
170 VLIB_PLUGIN_REGISTER () = {
171     .version = VPP_BUILD_VER,
172     .description = "Network Address Translation",
173 };
174 /* *INDENT-ON* */
175
176 void
177 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
178 {
179   snat_session_key_t key;
180   clib_bihash_kv_8_8_t kv;
181   nat_ed_ses_key_t ed_key;
182   clib_bihash_kv_16_8_t ed_kv;
183   snat_main_per_thread_data_t *tsm =
184     vec_elt_at_index (sm->per_thread_data, thread_index);
185
186   if (is_fwd_bypass_session (s))
187     {
188       ed_key.l_addr = s->in2out.addr;
189       ed_key.r_addr = s->ext_host_addr;
190       ed_key.l_port = s->in2out.port;
191       ed_key.r_port = s->ext_host_port;
192       ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
193       ed_key.fib_index = 0;
194       ed_kv.key[0] = ed_key.as_u64[0];
195       ed_kv.key[1] = ed_key.as_u64[1];
196       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
197         nat_log_warn ("in2out_ed key del failed");
198       return;
199     }
200
201   /* session lookup tables */
202   if (is_ed_session (s))
203     {
204       if (is_affinity_sessions (s))
205         nat_affinity_unlock (s->ext_host_addr, s->out2in.addr,
206                              s->in2out.protocol, s->out2in.port);
207       ed_key.l_addr = s->out2in.addr;
208       ed_key.r_addr = s->ext_host_addr;
209       ed_key.fib_index = s->out2in.fib_index;
210       if (snat_is_unk_proto_session (s))
211         {
212           ed_key.proto = s->in2out.port;
213           ed_key.r_port = 0;
214           ed_key.l_port = 0;
215         }
216       else
217         {
218           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
219           ed_key.l_port = s->out2in.port;
220           ed_key.r_port = s->ext_host_port;
221         }
222       ed_kv.key[0] = ed_key.as_u64[0];
223       ed_kv.key[1] = ed_key.as_u64[1];
224       if (clib_bihash_add_del_16_8 (&tsm->out2in_ed, &ed_kv, 0))
225         nat_log_warn ("out2in_ed key del failed");
226       ed_key.l_addr = s->in2out.addr;
227       ed_key.fib_index = s->in2out.fib_index;
228       if (!snat_is_unk_proto_session (s))
229         ed_key.l_port = s->in2out.port;
230       if (is_twice_nat_session (s))
231         {
232           ed_key.r_addr = s->ext_host_nat_addr;
233           ed_key.r_port = s->ext_host_nat_port;
234         }
235       ed_kv.key[0] = ed_key.as_u64[0];
236       ed_kv.key[1] = ed_key.as_u64[1];
237       if (clib_bihash_add_del_16_8 (&tsm->in2out_ed, &ed_kv, 0))
238         nat_log_warn ("in2out_ed key del failed");
239     }
240   else
241     {
242       kv.key = s->in2out.as_u64;
243       if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
244         nat_log_warn ("in2out key del failed");
245       kv.key = s->out2in.as_u64;
246       if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
247         nat_log_warn ("out2in key del failed");
248     }
249
250   if (snat_is_unk_proto_session (s))
251     return;
252
253   /* log NAT event */
254   snat_ipfix_logging_nat44_ses_delete (s->in2out.addr.as_u32,
255                                        s->out2in.addr.as_u32,
256                                        s->in2out.protocol,
257                                        s->in2out.port,
258                                        s->out2in.port, s->in2out.fib_index);
259
260   /* Twice NAT address and port for external host */
261   if (is_twice_nat_session (s))
262     {
263       key.protocol = s->in2out.protocol;
264       key.port = s->ext_host_nat_port;
265       key.addr.as_u32 = s->ext_host_nat_addr.as_u32;
266       snat_free_outside_address_and_port (sm->twice_nat_addresses,
267                                           thread_index, &key);
268     }
269
270   if (snat_is_session_static (s))
271     return;
272
273   snat_free_outside_address_and_port (sm->addresses, thread_index,
274                                       &s->out2in);
275 }
276
277 snat_user_t *
278 nat_user_get_or_create (snat_main_t * sm, ip4_address_t * addr, u32 fib_index,
279                         u32 thread_index)
280 {
281   snat_user_t *u = 0;
282   snat_user_key_t user_key;
283   clib_bihash_kv_8_8_t kv, value;
284   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
285   dlist_elt_t *per_user_list_head_elt;
286
287   user_key.addr.as_u32 = addr->as_u32;
288   user_key.fib_index = fib_index;
289   kv.key = user_key.as_u64;
290
291   /* Ever heard of the "user" = src ip4 address before? */
292   if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
293     {
294       /* no, make a new one */
295       pool_get (tsm->users, u);
296       clib_memset (u, 0, sizeof (*u));
297       u->addr.as_u32 = addr->as_u32;
298       u->fib_index = fib_index;
299
300       pool_get (tsm->list_pool, per_user_list_head_elt);
301
302       u->sessions_per_user_list_head_index = per_user_list_head_elt -
303         tsm->list_pool;
304
305       clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
306
307       kv.value = u - tsm->users;
308
309       /* add user */
310       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
311         nat_log_warn ("user_hash keay add failed");
312     }
313   else
314     {
315       u = pool_elt_at_index (tsm->users, value.value);
316     }
317
318   return u;
319 }
320
321 snat_session_t *
322 nat_session_alloc_or_recycle (snat_main_t * sm, snat_user_t * u,
323                               u32 thread_index)
324 {
325   snat_session_t *s;
326   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
327   u32 oldest_per_user_translation_list_index, session_index;
328   dlist_elt_t *oldest_per_user_translation_list_elt;
329   dlist_elt_t *per_user_translation_list_elt;
330
331   /* Over quota? Recycle the least recently used translation */
332   if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
333     {
334       oldest_per_user_translation_list_index =
335         clib_dlist_remove_head (tsm->list_pool,
336                                 u->sessions_per_user_list_head_index);
337
338       ASSERT (oldest_per_user_translation_list_index != ~0);
339
340       /* Add it back to the end of the LRU list */
341       clib_dlist_addtail (tsm->list_pool,
342                           u->sessions_per_user_list_head_index,
343                           oldest_per_user_translation_list_index);
344       /* Get the list element */
345       oldest_per_user_translation_list_elt =
346         pool_elt_at_index (tsm->list_pool,
347                            oldest_per_user_translation_list_index);
348
349       /* Get the session index from the list element */
350       session_index = oldest_per_user_translation_list_elt->value;
351
352       /* Get the session */
353       s = pool_elt_at_index (tsm->sessions, session_index);
354       nat_free_session_data (sm, s, thread_index);
355       if (snat_is_session_static (s))
356         u->nstaticsessions--;
357       else
358         u->nsessions--;
359       s->flags = 0;
360       s->total_bytes = 0;
361       s->total_pkts = 0;
362       s->state = 0;
363       s->ext_host_addr.as_u32 = 0;
364       s->ext_host_port = 0;
365       s->ext_host_nat_addr.as_u32 = 0;
366       s->ext_host_nat_port = 0;
367     }
368   else
369     {
370       pool_get (tsm->sessions, s);
371       clib_memset (s, 0, sizeof (*s));
372
373       /* Create list elts */
374       pool_get (tsm->list_pool, per_user_translation_list_elt);
375       clib_dlist_init (tsm->list_pool,
376                        per_user_translation_list_elt - tsm->list_pool);
377
378       per_user_translation_list_elt->value = s - tsm->sessions;
379       s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
380       s->per_user_list_head_index = u->sessions_per_user_list_head_index;
381
382       clib_dlist_addtail (tsm->list_pool,
383                           s->per_user_list_head_index,
384                           per_user_translation_list_elt - tsm->list_pool);
385     }
386
387   return s;
388 }
389
390 snat_session_t *
391 nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index,
392                       f64 now)
393 {
394   snat_session_t *s;
395   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
396   dlist_elt_t *per_user_translation_list_elt, *oldest_elt;
397   u32 oldest_index;
398   u64 sess_timeout_time;
399
400   if (PREDICT_FALSE (!(u->nsessions) && !(u->nstaticsessions)))
401     goto alloc_new;
402
403   oldest_index =
404     clib_dlist_remove_head (tsm->list_pool,
405                             u->sessions_per_user_list_head_index);
406   oldest_elt = pool_elt_at_index (tsm->list_pool, oldest_index);
407   s = pool_elt_at_index (tsm->sessions, oldest_elt->value);
408   sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s);
409   if (now >= sess_timeout_time)
410     {
411       clib_dlist_addtail (tsm->list_pool,
412                           u->sessions_per_user_list_head_index, oldest_index);
413       nat_free_session_data (sm, s, thread_index);
414       if (snat_is_session_static (s))
415         u->nstaticsessions--;
416       else
417         u->nsessions--;
418       s->flags = 0;
419       s->total_bytes = 0;
420       s->total_pkts = 0;
421       s->state = 0;
422       s->ext_host_addr.as_u32 = 0;
423       s->ext_host_port = 0;
424       s->ext_host_nat_addr.as_u32 = 0;
425       s->ext_host_nat_port = 0;
426     }
427   else
428     {
429       clib_dlist_addhead (tsm->list_pool,
430                           u->sessions_per_user_list_head_index, oldest_index);
431       if ((u->nsessions + u->nstaticsessions) >=
432           sm->max_translations_per_user)
433         {
434           nat_log_warn ("max translations per user %U", format_ip4_address,
435                         &u->addr);
436           snat_ipfix_logging_max_entries_per_user
437             (sm->max_translations_per_user, u->addr.as_u32);
438           return 0;
439         }
440       else
441         {
442         alloc_new:
443           pool_get (tsm->sessions, s);
444           clib_memset (s, 0, sizeof (*s));
445
446           /* Create list elts */
447           pool_get (tsm->list_pool, per_user_translation_list_elt);
448           clib_dlist_init (tsm->list_pool,
449                            per_user_translation_list_elt - tsm->list_pool);
450
451           per_user_translation_list_elt->value = s - tsm->sessions;
452           s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
453           s->per_user_list_head_index = u->sessions_per_user_list_head_index;
454
455           clib_dlist_addtail (tsm->list_pool,
456                               s->per_user_list_head_index,
457                               per_user_translation_list_elt - tsm->list_pool);
458         }
459     }
460
461   return s;
462 }
463
464 void
465 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
466                           int is_add)
467 {
468   fib_prefix_t prefix = {
469     .fp_len = p_len,
470     .fp_proto = FIB_PROTOCOL_IP4,
471     .fp_addr = {
472                 .ip4.as_u32 = addr->as_u32,
473                 },
474   };
475   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
476
477   if (is_add)
478     fib_table_entry_update_one_path (fib_index,
479                                      &prefix,
480                                      FIB_SOURCE_PLUGIN_LOW,
481                                      (FIB_ENTRY_FLAG_CONNECTED |
482                                       FIB_ENTRY_FLAG_LOCAL |
483                                       FIB_ENTRY_FLAG_EXCLUSIVE),
484                                      DPO_PROTO_IP4,
485                                      NULL,
486                                      sw_if_index,
487                                      ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
488   else
489     fib_table_entry_delete (fib_index, &prefix, FIB_SOURCE_PLUGIN_LOW);
490 }
491
492 int
493 snat_add_address (snat_main_t * sm, ip4_address_t * addr, u32 vrf_id,
494                   u8 twice_nat)
495 {
496   snat_address_t *ap;
497   snat_interface_t *i;
498   vlib_thread_main_t *tm = vlib_get_thread_main ();
499
500   if (twice_nat && !sm->endpoint_dependent)
501     return VNET_API_ERROR_FEATURE_DISABLED;
502
503   /* Check if address already exists */
504   /* *INDENT-OFF* */
505   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
506     {
507       if (ap->addr.as_u32 == addr->as_u32)
508         return VNET_API_ERROR_VALUE_EXIST;
509     }
510   /* *INDENT-ON* */
511
512   if (twice_nat)
513     vec_add2 (sm->twice_nat_addresses, ap, 1);
514   else
515     vec_add2 (sm->addresses, ap, 1);
516
517   ap->addr = *addr;
518   if (vrf_id != ~0)
519     ap->fib_index =
520       fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
521                                          FIB_SOURCE_PLUGIN_LOW);
522   else
523     ap->fib_index = ~0;
524 #define _(N, i, n, s) \
525   clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
526   ap->busy_##n##_ports = 0; \
527   ap->busy_##n##_ports_per_thread = 0;\
528   vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
529   foreach_snat_protocol
530 #undef _
531     if (twice_nat)
532     return 0;
533
534   /* Add external address to FIB */
535   /* *INDENT-OFF* */
536   pool_foreach (i, sm->interfaces,
537   ({
538     if (nat_interface_is_inside(i) || sm->out2in_dpo)
539       continue;
540
541     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
542     break;
543   }));
544   pool_foreach (i, sm->output_feature_interfaces,
545   ({
546     if (nat_interface_is_inside(i) || sm->out2in_dpo)
547       continue;
548
549     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
550     break;
551   }));
552   /* *INDENT-ON* */
553
554   return 0;
555 }
556
557 static int
558 is_snat_address_used_in_static_mapping (snat_main_t * sm, ip4_address_t addr)
559 {
560   snat_static_mapping_t *m;
561   /* *INDENT-OFF* */
562   pool_foreach (m, sm->static_mappings,
563   ({
564       if (is_addr_only_static_mapping (m) ||
565           is_out2in_only_static_mapping (m) ||
566           is_identity_static_mapping (m))
567         continue;
568       if (m->external_addr.as_u32 == addr.as_u32)
569         return 1;
570   }));
571   /* *INDENT-ON* */
572
573   return 0;
574 }
575
576 void
577 increment_v4_address (ip4_address_t * a)
578 {
579   u32 v;
580
581   v = clib_net_to_host_u32 (a->as_u32) + 1;
582   a->as_u32 = clib_host_to_net_u32 (v);
583 }
584
585 static void
586 snat_add_static_mapping_when_resolved (snat_main_t * sm,
587                                        ip4_address_t l_addr,
588                                        u16 l_port,
589                                        u32 sw_if_index,
590                                        u16 e_port,
591                                        u32 vrf_id,
592                                        snat_protocol_t proto,
593                                        int addr_only, int is_add, u8 * tag,
594                                        int twice_nat, int out2in_only,
595                                        int identity_nat)
596 {
597   snat_static_map_resolve_t *rp;
598
599   vec_add2 (sm->to_resolve, rp, 1);
600   rp->l_addr.as_u32 = l_addr.as_u32;
601   rp->l_port = l_port;
602   rp->sw_if_index = sw_if_index;
603   rp->e_port = e_port;
604   rp->vrf_id = vrf_id;
605   rp->proto = proto;
606   rp->addr_only = addr_only;
607   rp->is_add = is_add;
608   rp->twice_nat = twice_nat;
609   rp->out2in_only = out2in_only;
610   rp->identity_nat = identity_nat;
611   rp->tag = vec_dup (tag);
612 }
613
614 static u32
615 get_thread_idx_by_port (u16 e_port)
616 {
617   snat_main_t *sm = &snat_main;
618   u32 thread_idx = sm->num_workers;
619   if (sm->num_workers > 1)
620     {
621       thread_idx =
622         sm->first_worker_index +
623         sm->workers[(e_port - 1024) / sm->port_per_thread];
624     }
625   return thread_idx;
626 }
627
628 int
629 snat_add_static_mapping (ip4_address_t l_addr, ip4_address_t e_addr,
630                          u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
631                          u32 sw_if_index, snat_protocol_t proto, int is_add,
632                          twice_nat_type_t twice_nat, u8 out2in_only, u8 * tag,
633                          u8 identity_nat)
634 {
635   snat_main_t *sm = &snat_main;
636   snat_static_mapping_t *m;
637   snat_session_key_t m_key;
638   clib_bihash_kv_8_8_t kv, value;
639   snat_address_t *a = 0;
640   u32 fib_index = ~0;
641   snat_interface_t *interface;
642   int i;
643   snat_main_per_thread_data_t *tsm;
644   snat_user_key_t u_key;
645   snat_user_t *u;
646   dlist_elt_t *head, *elt;
647   u32 elt_index, head_index;
648   u32 ses_index;
649   u64 user_index;
650   snat_session_t *s;
651   snat_static_map_resolve_t *rp, *rp_match = 0;
652   nat44_lb_addr_port_t *local;
653   u8 find = 0;
654
655   if (!sm->endpoint_dependent)
656     {
657       if (twice_nat || out2in_only)
658         return VNET_API_ERROR_FEATURE_DISABLED;
659     }
660
661   /* If the external address is a specific interface address */
662   if (sw_if_index != ~0)
663     {
664       ip4_address_t *first_int_addr;
665
666       for (i = 0; i < vec_len (sm->to_resolve); i++)
667         {
668           rp = sm->to_resolve + i;
669           if (rp->sw_if_index != sw_if_index ||
670               rp->l_addr.as_u32 != l_addr.as_u32 ||
671               rp->vrf_id != vrf_id || rp->addr_only != addr_only)
672             continue;
673
674           if (!addr_only)
675             {
676               if (rp->l_port != l_port || rp->e_port != e_port
677                   || rp->proto != proto)
678                 continue;
679             }
680
681           rp_match = rp;
682           break;
683         }
684
685       /* Might be already set... */
686       first_int_addr = ip4_interface_first_address
687         (sm->ip4_main, sw_if_index, 0 /* just want the address */ );
688
689       if (is_add)
690         {
691           if (rp_match)
692             return VNET_API_ERROR_VALUE_EXIST;
693
694           snat_add_static_mapping_when_resolved
695             (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
696              addr_only, is_add, tag, twice_nat, out2in_only, identity_nat);
697
698           /* DHCP resolution required? */
699           if (first_int_addr == 0)
700             {
701               return 0;
702             }
703           else
704             {
705               e_addr.as_u32 = first_int_addr->as_u32;
706               /* Identity mapping? */
707               if (l_addr.as_u32 == 0)
708                 l_addr.as_u32 = e_addr.as_u32;
709             }
710         }
711       else
712         {
713           if (!rp_match)
714             return VNET_API_ERROR_NO_SUCH_ENTRY;
715
716           vec_del1 (sm->to_resolve, i);
717
718           if (first_int_addr)
719             {
720               e_addr.as_u32 = first_int_addr->as_u32;
721               /* Identity mapping? */
722               if (l_addr.as_u32 == 0)
723                 l_addr.as_u32 = e_addr.as_u32;
724             }
725           else
726             return 0;
727         }
728     }
729
730   m_key.addr = e_addr;
731   m_key.port = addr_only ? 0 : e_port;
732   m_key.protocol = addr_only ? 0 : proto;
733   m_key.fib_index = 0;
734   kv.key = m_key.as_u64;
735   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
736     m = 0;
737   else
738     m = pool_elt_at_index (sm->static_mappings, value.value);
739
740   if (is_add)
741     {
742       if (m)
743         {
744           if (is_identity_static_mapping (m))
745             {
746               /* *INDENT-OFF* */
747               vec_foreach (local, m->locals)
748                 {
749                   if (local->vrf_id == vrf_id)
750                     return VNET_API_ERROR_VALUE_EXIST;
751                 }
752               /* *INDENT-ON* */
753               vec_add2 (m->locals, local, 1);
754               local->vrf_id = vrf_id;
755               local->fib_index =
756                 fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
757                                                    FIB_SOURCE_PLUGIN_LOW);
758               m_key.addr = m->local_addr;
759               m_key.port = m->local_port;
760               m_key.protocol = m->proto;
761               m_key.fib_index = local->fib_index;
762               kv.key = m_key.as_u64;
763               kv.value = m - sm->static_mappings;
764               clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
765               return 0;
766             }
767           else
768             return VNET_API_ERROR_VALUE_EXIST;
769         }
770
771       if (twice_nat && addr_only)
772         return VNET_API_ERROR_UNSUPPORTED;
773
774       /* Convert VRF id to FIB index */
775       if (vrf_id != ~0)
776         fib_index =
777           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
778                                              FIB_SOURCE_PLUGIN_LOW);
779       /* If not specified use inside VRF id from SNAT plugin startup config */
780       else
781         {
782           fib_index = sm->inside_fib_index;
783           vrf_id = sm->inside_vrf_id;
784         }
785
786       if (!(out2in_only || identity_nat))
787         {
788           m_key.addr = l_addr;
789           m_key.port = addr_only ? 0 : l_port;
790           m_key.protocol = addr_only ? 0 : proto;
791           m_key.fib_index = fib_index;
792           kv.key = m_key.as_u64;
793           if (!clib_bihash_search_8_8
794               (&sm->static_mapping_by_local, &kv, &value))
795             return VNET_API_ERROR_VALUE_EXIST;
796         }
797
798       /* Find external address in allocated addresses and reserve port for
799          address and port pair mapping when dynamic translations enabled */
800       if (!(addr_only || sm->static_mapping_only || out2in_only))
801         {
802           for (i = 0; i < vec_len (sm->addresses); i++)
803             {
804               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
805                 {
806                   a = sm->addresses + i;
807                   /* External port must be unused */
808                   switch (proto)
809                     {
810 #define _(N, j, n, s) \
811                     case SNAT_PROTOCOL_##N: \
812                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
813                         return VNET_API_ERROR_INVALID_VALUE; \
814                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
815                       if (e_port > 1024) \
816                         { \
817                           a->busy_##n##_ports++; \
818                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
819                         } \
820                       break;
821                       foreach_snat_protocol
822 #undef _
823                     default:
824                       nat_log_info ("unknown protocol");
825                       return VNET_API_ERROR_INVALID_VALUE_2;
826                     }
827                   break;
828                 }
829             }
830           /* External address must be allocated */
831           if (!a && (l_addr.as_u32 != e_addr.as_u32))
832             {
833               if (sw_if_index != ~0)
834                 {
835                   for (i = 0; i < vec_len (sm->to_resolve); i++)
836                     {
837                       rp = sm->to_resolve + i;
838                       if (rp->addr_only)
839                         continue;
840                       if (rp->sw_if_index != sw_if_index &&
841                           rp->l_addr.as_u32 != l_addr.as_u32 &&
842                           rp->vrf_id != vrf_id && rp->l_port != l_port &&
843                           rp->e_port != e_port && rp->proto != proto)
844                         continue;
845
846                       vec_del1 (sm->to_resolve, i);
847                       break;
848                     }
849                 }
850               return VNET_API_ERROR_NO_SUCH_ENTRY;
851             }
852         }
853
854       pool_get (sm->static_mappings, m);
855       clib_memset (m, 0, sizeof (*m));
856       m->tag = vec_dup (tag);
857       m->local_addr = l_addr;
858       m->external_addr = e_addr;
859       m->twice_nat = twice_nat;
860       if (out2in_only)
861         m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
862       if (addr_only)
863         m->flags |= NAT_STATIC_MAPPING_FLAG_ADDR_ONLY;
864       if (identity_nat)
865         {
866           m->flags |= NAT_STATIC_MAPPING_FLAG_IDENTITY_NAT;
867           vec_add2 (m->locals, local, 1);
868           local->vrf_id = vrf_id;
869           local->fib_index = fib_index;
870         }
871       else
872         {
873           m->vrf_id = vrf_id;
874           m->fib_index = fib_index;
875         }
876       if (!addr_only)
877         {
878           m->local_port = l_port;
879           m->external_port = e_port;
880           m->proto = proto;
881         }
882
883       if (sm->num_workers > 1)
884         {
885           ip4_header_t ip = {
886             .src_address = m->local_addr,
887           };
888           vec_add1 (m->workers, sm->worker_in2out_cb (&ip, m->fib_index));
889           tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
890         }
891       else
892         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
893
894       m_key.addr = m->local_addr;
895       m_key.port = m->local_port;
896       m_key.protocol = m->proto;
897       m_key.fib_index = fib_index;
898       kv.key = m_key.as_u64;
899       kv.value = m - sm->static_mappings;
900       if (!out2in_only)
901         clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
902
903       m_key.addr = m->external_addr;
904       m_key.port = m->external_port;
905       m_key.fib_index = 0;
906       kv.key = m_key.as_u64;
907       kv.value = m - sm->static_mappings;
908       clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1);
909
910       /* Delete dynamic sessions matching local address (+ local port) */
911       if (!(sm->static_mapping_only))
912         {
913           u_key.addr = m->local_addr;
914           u_key.fib_index = m->fib_index;
915           kv.key = u_key.as_u64;
916           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
917             {
918               user_index = value.value;
919               u = pool_elt_at_index (tsm->users, user_index);
920               if (u->nsessions)
921                 {
922                   head_index = u->sessions_per_user_list_head_index;
923                   head = pool_elt_at_index (tsm->list_pool, head_index);
924                   elt_index = head->next;
925                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
926                   ses_index = elt->value;
927                   while (ses_index != ~0)
928                     {
929                       s = pool_elt_at_index (tsm->sessions, ses_index);
930                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
931                       ses_index = elt->value;
932
933                       if (snat_is_session_static (s))
934                         continue;
935
936                       if (!addr_only
937                           && (clib_net_to_host_u16 (s->in2out.port) !=
938                               m->local_port))
939                         continue;
940
941                       nat_free_session_data (sm, s,
942                                              tsm - sm->per_thread_data);
943                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
944
945                       if (!addr_only && !sm->endpoint_dependent)
946                         break;
947                     }
948                 }
949             }
950         }
951     }
952   else
953     {
954       if (!m)
955         {
956           if (sw_if_index != ~0)
957             return 0;
958           else
959             return VNET_API_ERROR_NO_SUCH_ENTRY;
960         }
961
962       if (identity_nat)
963         {
964           if (vrf_id == ~0)
965             vrf_id = sm->inside_vrf_id;
966
967           for (i = 0; i < vec_len (m->locals); i++)
968             {
969               if (m->locals[i].vrf_id == vrf_id)
970                 {
971                   find = 1;
972                   break;
973                 }
974             }
975           if (!find)
976             return VNET_API_ERROR_NO_SUCH_ENTRY;
977
978           fib_index = m->locals[i].fib_index;
979           vec_del1 (m->locals, i);
980         }
981       else
982         fib_index = m->fib_index;
983
984       /* Free external address port */
985       if (!(addr_only || sm->static_mapping_only || out2in_only))
986         {
987           for (i = 0; i < vec_len (sm->addresses); i++)
988             {
989               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
990                 {
991                   a = sm->addresses + i;
992                   switch (proto)
993                     {
994 #define _(N, j, n, s) \
995                     case SNAT_PROTOCOL_##N: \
996                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
997                       if (e_port > 1024) \
998                         { \
999                           a->busy_##n##_ports--; \
1000                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1001                         } \
1002                       break;
1003                       foreach_snat_protocol
1004 #undef _
1005                     default:
1006                       nat_log_info ("unknown protocol");
1007                       return VNET_API_ERROR_INVALID_VALUE_2;
1008                     }
1009                   break;
1010                 }
1011             }
1012         }
1013
1014       if (sm->num_workers > 1)
1015         tsm = vec_elt_at_index (sm->per_thread_data, m->workers[0]);
1016       else
1017         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1018
1019       m_key.addr = m->local_addr;
1020       m_key.port = m->local_port;
1021       m_key.protocol = m->proto;
1022       m_key.fib_index = fib_index;
1023       kv.key = m_key.as_u64;
1024       if (!out2in_only)
1025         clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 0);
1026
1027       /* Delete session(s) for static mapping if exist */
1028       if (!(sm->static_mapping_only) ||
1029           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1030         {
1031           u_key.addr = m->local_addr;
1032           u_key.fib_index = fib_index;
1033           kv.key = u_key.as_u64;
1034           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1035             {
1036               user_index = value.value;
1037               u = pool_elt_at_index (tsm->users, user_index);
1038               if (u->nstaticsessions)
1039                 {
1040                   head_index = u->sessions_per_user_list_head_index;
1041                   head = pool_elt_at_index (tsm->list_pool, head_index);
1042                   elt_index = head->next;
1043                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1044                   ses_index = elt->value;
1045                   while (ses_index != ~0)
1046                     {
1047                       s = pool_elt_at_index (tsm->sessions, ses_index);
1048                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1049                       ses_index = elt->value;
1050
1051                       if (!addr_only)
1052                         {
1053                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) ||
1054                               (clib_net_to_host_u16 (s->out2in.port) !=
1055                                e_port))
1056                             continue;
1057                         }
1058
1059                       if (is_lb_session (s))
1060                         continue;
1061
1062                       if (!snat_is_session_static (s))
1063                         continue;
1064
1065                       nat_free_session_data (sm, s,
1066                                              tsm - sm->per_thread_data);
1067                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1068
1069                       if (!addr_only && !sm->endpoint_dependent)
1070                         break;
1071                     }
1072                 }
1073             }
1074         }
1075
1076       fib_table_unlock (fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
1077       if (vec_len (m->locals))
1078         return 0;
1079
1080       m_key.addr = m->external_addr;
1081       m_key.port = m->external_port;
1082       m_key.fib_index = 0;
1083       kv.key = m_key.as_u64;
1084       clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0);
1085
1086       vec_free (m->tag);
1087       vec_free (m->workers);
1088       /* Delete static mapping from pool */
1089       pool_put (sm->static_mappings, m);
1090     }
1091
1092   if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1093     return 0;
1094
1095   /* Add/delete external address to FIB */
1096   /* *INDENT-OFF* */
1097   pool_foreach (interface, sm->interfaces,
1098   ({
1099     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1100       continue;
1101
1102     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1103     break;
1104   }));
1105   pool_foreach (interface, sm->output_feature_interfaces,
1106   ({
1107     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1108       continue;
1109
1110     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1111     break;
1112   }));
1113   /* *INDENT-ON* */
1114
1115   return 0;
1116 }
1117
1118 int
1119 nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1120                                  snat_protocol_t proto,
1121                                  nat44_lb_addr_port_t * locals, u8 is_add,
1122                                  twice_nat_type_t twice_nat, u8 out2in_only,
1123                                  u8 * tag, u32 affinity)
1124 {
1125   snat_main_t *sm = &snat_main;
1126   snat_static_mapping_t *m;
1127   snat_session_key_t m_key;
1128   clib_bihash_kv_8_8_t kv, value;
1129   snat_address_t *a = 0;
1130   int i;
1131   nat44_lb_addr_port_t *local;
1132   u32 elt_index, head_index, ses_index;
1133   snat_main_per_thread_data_t *tsm;
1134   snat_user_key_t u_key;
1135   snat_user_t *u;
1136   snat_session_t *s;
1137   dlist_elt_t *head, *elt;
1138   uword *bitmap = 0;
1139
1140   if (!sm->endpoint_dependent)
1141     return VNET_API_ERROR_FEATURE_DISABLED;
1142
1143   m_key.addr = e_addr;
1144   m_key.port = e_port;
1145   m_key.protocol = proto;
1146   m_key.fib_index = 0;
1147   kv.key = m_key.as_u64;
1148   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1149     m = 0;
1150   else
1151     m = pool_elt_at_index (sm->static_mappings, value.value);
1152
1153   if (is_add)
1154     {
1155       if (m)
1156         return VNET_API_ERROR_VALUE_EXIST;
1157
1158       if (vec_len (locals) < 2)
1159         return VNET_API_ERROR_INVALID_VALUE;
1160
1161       /* Find external address in allocated addresses and reserve port for
1162          address and port pair mapping when dynamic translations enabled */
1163       if (!(sm->static_mapping_only || out2in_only))
1164         {
1165           for (i = 0; i < vec_len (sm->addresses); i++)
1166             {
1167               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1168                 {
1169                   a = sm->addresses + i;
1170                   /* External port must be unused */
1171                   switch (proto)
1172                     {
1173 #define _(N, j, n, s) \
1174                     case SNAT_PROTOCOL_##N: \
1175                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1176                         return VNET_API_ERROR_INVALID_VALUE; \
1177                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1178                       if (e_port > 1024) \
1179                         { \
1180                           a->busy_##n##_ports++; \
1181                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]++; \
1182                         } \
1183                       break;
1184                       foreach_snat_protocol
1185 #undef _
1186                     default:
1187                       nat_log_info ("unknown protocol");
1188                       return VNET_API_ERROR_INVALID_VALUE_2;
1189                     }
1190                   break;
1191                 }
1192             }
1193           /* External address must be allocated */
1194           if (!a)
1195             return VNET_API_ERROR_NO_SUCH_ENTRY;
1196         }
1197
1198       pool_get (sm->static_mappings, m);
1199       clib_memset (m, 0, sizeof (*m));
1200       m->tag = vec_dup (tag);
1201       m->external_addr = e_addr;
1202       m->external_port = e_port;
1203       m->proto = proto;
1204       m->twice_nat = twice_nat;
1205       m->flags |= NAT_STATIC_MAPPING_FLAG_LB;
1206       if (out2in_only)
1207         m->flags |= NAT_STATIC_MAPPING_FLAG_OUT2IN_ONLY;
1208       m->affinity = affinity;
1209
1210       if (affinity)
1211         m->affinity_per_service_list_head_index =
1212           nat_affinity_get_per_service_list_head_index ();
1213       else
1214         m->affinity_per_service_list_head_index = ~0;
1215
1216       m_key.addr = m->external_addr;
1217       m_key.port = m->external_port;
1218       m_key.protocol = m->proto;
1219       m_key.fib_index = 0;
1220       kv.key = m_key.as_u64;
1221       kv.value = m - sm->static_mappings;
1222       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 1))
1223         {
1224           nat_log_err ("static_mapping_by_external key add failed");
1225           return VNET_API_ERROR_UNSPECIFIED;
1226         }
1227
1228       m_key.fib_index = m->fib_index;
1229       for (i = 0; i < vec_len (locals); i++)
1230         {
1231           locals[i].fib_index =
1232             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1233                                                locals[i].vrf_id,
1234                                                FIB_SOURCE_PLUGIN_LOW);
1235           m_key.addr = locals[i].addr;
1236           m_key.fib_index = locals[i].fib_index;
1237           if (!out2in_only)
1238             {
1239               m_key.port = locals[i].port;
1240               kv.key = m_key.as_u64;
1241               kv.value = m - sm->static_mappings;
1242               clib_bihash_add_del_8_8 (&sm->static_mapping_by_local, &kv, 1);
1243             }
1244           locals[i].prefix = (i == 0) ? locals[i].probability :
1245             (locals[i - 1].prefix + locals[i].probability);
1246           vec_add1 (m->locals, locals[i]);
1247           if (sm->num_workers > 1)
1248             {
1249               ip4_header_t ip = {
1250                 .src_address = locals[i].addr,
1251               };
1252               bitmap =
1253                 clib_bitmap_set (bitmap,
1254                                  sm->worker_in2out_cb (&ip, m->fib_index), 1);
1255             }
1256         }
1257
1258       /* Assign workers */
1259       if (sm->num_workers > 1)
1260         {
1261           /* *INDENT-OFF* */
1262           clib_bitmap_foreach (i, bitmap,
1263             ({
1264                vec_add1(m->workers, i);
1265             }));
1266           /* *INDENT-ON* */
1267         }
1268     }
1269   else
1270     {
1271       if (!m)
1272         return VNET_API_ERROR_NO_SUCH_ENTRY;
1273
1274       if (!is_lb_static_mapping (m))
1275         return VNET_API_ERROR_INVALID_VALUE;
1276
1277       /* Free external address port */
1278       if (!(sm->static_mapping_only || out2in_only))
1279         {
1280           for (i = 0; i < vec_len (sm->addresses); i++)
1281             {
1282               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1283                 {
1284                   a = sm->addresses + i;
1285                   switch (proto)
1286                     {
1287 #define _(N, j, n, s) \
1288                     case SNAT_PROTOCOL_##N: \
1289                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1290                       if (e_port > 1024) \
1291                         { \
1292                           a->busy_##n##_ports--; \
1293                           a->busy_##n##_ports_per_thread[get_thread_idx_by_port(e_port)]--; \
1294                         } \
1295                       break;
1296                       foreach_snat_protocol
1297 #undef _
1298                     default:
1299                       nat_log_info ("unknown protocol");
1300                       return VNET_API_ERROR_INVALID_VALUE_2;
1301                     }
1302                   break;
1303                 }
1304             }
1305         }
1306
1307       m_key.addr = m->external_addr;
1308       m_key.port = m->external_port;
1309       m_key.protocol = m->proto;
1310       m_key.fib_index = 0;
1311       kv.key = m_key.as_u64;
1312       if (clib_bihash_add_del_8_8 (&sm->static_mapping_by_external, &kv, 0))
1313         {
1314           nat_log_err ("static_mapping_by_external key del failed");
1315           return VNET_API_ERROR_UNSPECIFIED;
1316         }
1317
1318       /* *INDENT-OFF* */
1319       vec_foreach (local, m->locals)
1320         {
1321           fib_table_unlock (local->fib_index, FIB_PROTOCOL_IP4,
1322                             FIB_SOURCE_PLUGIN_LOW);
1323           m_key.addr = local->addr;
1324           if (!out2in_only)
1325             {
1326               m_key.port = local->port;
1327               m_key.fib_index = local->fib_index;
1328               kv.key = m_key.as_u64;
1329               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1330                 {
1331                   nat_log_err ("static_mapping_by_local key del failed");
1332                   return VNET_API_ERROR_UNSPECIFIED;
1333                 }
1334             }
1335
1336           if (sm->num_workers > 1)
1337             {
1338               ip4_header_t ip = {
1339                 .src_address = local->addr,
1340               };
1341               tsm = vec_elt_at_index (sm->per_thread_data,
1342                                       sm->worker_in2out_cb (&ip, m->fib_index));
1343             }
1344           else
1345             tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1346
1347           /* Delete sessions */
1348           u_key.addr = local->addr;
1349           u_key.fib_index = m->fib_index;
1350           kv.key = u_key.as_u64;
1351           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1352             {
1353               u = pool_elt_at_index (tsm->users, value.value);
1354               if (u->nstaticsessions)
1355                 {
1356                   head_index = u->sessions_per_user_list_head_index;
1357                   head = pool_elt_at_index (tsm->list_pool, head_index);
1358                   elt_index = head->next;
1359                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1360                   ses_index = elt->value;
1361                   while (ses_index != ~0)
1362                     {
1363                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1364                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1365                       ses_index = elt->value;
1366
1367                       if (!(is_lb_session (s)))
1368                         continue;
1369
1370                       if ((s->in2out.addr.as_u32 != local->addr.as_u32) ||
1371                           (clib_net_to_host_u16 (s->in2out.port) != local->port))
1372                         continue;
1373
1374                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1375                       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
1376                     }
1377                 }
1378             }
1379         }
1380       /* *INDENT-ON* */
1381       if (m->affinity)
1382         nat_affinity_flush_service (m->affinity_per_service_list_head_index);
1383       vec_free (m->locals);
1384       vec_free (m->tag);
1385       vec_free (m->workers);
1386
1387       pool_put (sm->static_mappings, m);
1388     }
1389
1390   return 0;
1391 }
1392
1393 int
1394 snat_del_address (snat_main_t * sm, ip4_address_t addr, u8 delete_sm,
1395                   u8 twice_nat)
1396 {
1397   snat_address_t *a = 0;
1398   snat_session_t *ses;
1399   u32 *ses_to_be_removed = 0, *ses_index;
1400   snat_main_per_thread_data_t *tsm;
1401   snat_static_mapping_t *m;
1402   snat_interface_t *interface;
1403   int i;
1404   snat_address_t *addresses =
1405     twice_nat ? sm->twice_nat_addresses : sm->addresses;
1406
1407   /* Find SNAT address */
1408   for (i = 0; i < vec_len (addresses); i++)
1409     {
1410       if (addresses[i].addr.as_u32 == addr.as_u32)
1411         {
1412           a = addresses + i;
1413           break;
1414         }
1415     }
1416   if (!a)
1417     return VNET_API_ERROR_NO_SUCH_ENTRY;
1418
1419   if (delete_sm)
1420     {
1421       /* *INDENT-OFF* */
1422       pool_foreach (m, sm->static_mappings,
1423       ({
1424           if (m->external_addr.as_u32 == addr.as_u32)
1425             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1426                                             m->local_port, m->external_port,
1427                                             m->vrf_id, is_addr_only_static_mapping(m), ~0,
1428                                             m->proto, 0, m->twice_nat,
1429                                             is_out2in_only_static_mapping(m), m->tag, is_identity_static_mapping(m));
1430       }));
1431       /* *INDENT-ON* */
1432     }
1433   else
1434     {
1435       /* Check if address is used in some static mapping */
1436       if (is_snat_address_used_in_static_mapping (sm, addr))
1437         {
1438           nat_log_notice ("address used in static mapping");
1439           return VNET_API_ERROR_UNSPECIFIED;
1440         }
1441     }
1442
1443   if (a->fib_index != ~0)
1444     fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_LOW);
1445
1446   /* Delete sessions using address */
1447   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1448     {
1449       /* *INDENT-OFF* */
1450       vec_foreach (tsm, sm->per_thread_data)
1451         {
1452           pool_foreach (ses, tsm->sessions, ({
1453             if (ses->out2in.addr.as_u32 == addr.as_u32)
1454               {
1455                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1456                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1457               }
1458           }));
1459
1460           vec_foreach (ses_index, ses_to_be_removed)
1461             {
1462               ses = pool_elt_at_index (tsm->sessions, ses_index[0]);
1463               nat44_delete_session (sm, ses, tsm - sm->per_thread_data);
1464             }
1465
1466           vec_free (ses_to_be_removed);
1467         }
1468       /* *INDENT-ON* */
1469     }
1470
1471 #define _(N, i, n, s) \
1472   clib_bitmap_free (a->busy_##n##_port_bitmap); \
1473   vec_free (a->busy_##n##_ports_per_thread);
1474   foreach_snat_protocol
1475 #undef _
1476     if (twice_nat)
1477     {
1478       vec_del1 (sm->twice_nat_addresses, i);
1479       return 0;
1480     }
1481   else
1482     vec_del1 (sm->addresses, i);
1483
1484   /* Delete external address from FIB */
1485   /* *INDENT-OFF* */
1486   pool_foreach (interface, sm->interfaces,
1487   ({
1488     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1489       continue;
1490
1491     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1492     break;
1493   }));
1494   pool_foreach (interface, sm->output_feature_interfaces,
1495   ({
1496     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1497       continue;
1498
1499     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1500     break;
1501   }));
1502   /* *INDENT-ON* */
1503
1504   return 0;
1505 }
1506
1507 int
1508 snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1509 {
1510   snat_main_t *sm = &snat_main;
1511   snat_interface_t *i;
1512   const char *feature_name, *del_feature_name;
1513   snat_address_t *ap;
1514   snat_static_mapping_t *m;
1515   snat_det_map_t *dm;
1516   nat_outside_fib_t *outside_fib;
1517   u32 fib_index = fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4,
1518                                                        sw_if_index);
1519
1520   if (sm->out2in_dpo && !is_inside)
1521     return VNET_API_ERROR_UNSUPPORTED;
1522
1523   /* *INDENT-OFF* */
1524   pool_foreach (i, sm->output_feature_interfaces,
1525   ({
1526     if (i->sw_if_index == sw_if_index)
1527       return VNET_API_ERROR_VALUE_EXIST;
1528   }));
1529   /* *INDENT-ON* */
1530
1531   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1532     feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast";
1533   else
1534     {
1535       if (sm->num_workers > 1 && !sm->deterministic)
1536         feature_name =
1537           is_inside ? "nat44-in2out-worker-handoff" :
1538           "nat44-out2in-worker-handoff";
1539       else if (sm->deterministic)
1540         feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in";
1541       else if (sm->endpoint_dependent)
1542         feature_name = is_inside ? "nat44-ed-in2out" : "nat44-ed-out2in";
1543       else
1544         feature_name = is_inside ? "nat44-in2out" : "nat44-out2in";
1545     }
1546
1547   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1548     sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index,
1549                                                       NAT_FQ_NELTS);
1550
1551   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1552     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index,
1553                                                       NAT_FQ_NELTS);
1554
1555   if (!is_inside)
1556     {
1557       /* *INDENT-OFF* */
1558       vec_foreach (outside_fib, sm->outside_fibs)
1559         {
1560           if (outside_fib->fib_index == fib_index)
1561             {
1562               if (is_del)
1563                 {
1564                   outside_fib->refcount--;
1565                   if (!outside_fib->refcount)
1566                     vec_del1 (sm->outside_fibs, outside_fib - sm->outside_fibs);
1567                 }
1568               else
1569                 outside_fib->refcount++;
1570               goto feature_set;
1571             }
1572         }
1573       /* *INDENT-ON* */
1574       if (!is_del)
1575         {
1576           vec_add2 (sm->outside_fibs, outside_fib, 1);
1577           outside_fib->refcount = 1;
1578           outside_fib->fib_index = fib_index;
1579         }
1580     }
1581 feature_set:
1582   /* *INDENT-OFF* */
1583   pool_foreach (i, sm->interfaces,
1584   ({
1585     if (i->sw_if_index == sw_if_index)
1586       {
1587         if (is_del)
1588           {
1589             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1590               {
1591                 if (is_inside)
1592                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1593                 else
1594                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1595
1596                 if (sm->num_workers > 1 && !sm->deterministic)
1597                   {
1598                     del_feature_name = "nat44-handoff-classify";
1599                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1600                                                  "nat44-out2in-worker-handoff";
1601                   }
1602                 else if (sm->deterministic)
1603                   {
1604                     del_feature_name = "nat44-det-classify";
1605                     feature_name = !is_inside ?  "nat44-det-in2out" :
1606                                                  "nat44-det-out2in";
1607                   }
1608                 else if (sm->endpoint_dependent)
1609                   {
1610                     del_feature_name = "nat44-ed-classify";
1611                     feature_name = !is_inside ?  "nat44-ed-in2out" :
1612                                                  "nat44-ed-out2in";
1613                   }
1614                 else
1615                   {
1616                     del_feature_name = "nat44-classify";
1617                     feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1618                   }
1619
1620                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1621                                              sw_if_index, 0, 0, 0);
1622                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1623                                              sw_if_index, 1, 0, 0);
1624                 if (!is_inside)
1625                   {
1626                     if (sm->endpoint_dependent)
1627                       vnet_feature_enable_disable ("ip4-local",
1628                                                    "nat44-ed-hairpinning",
1629                                                    sw_if_index, 1, 0, 0);
1630                     else if (!sm->deterministic)
1631                       vnet_feature_enable_disable ("ip4-local",
1632                                                    "nat44-hairpinning",
1633                                                    sw_if_index, 1, 0, 0);
1634                   }
1635               }
1636             else
1637               {
1638                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1639                                              sw_if_index, 0, 0, 0);
1640                 pool_put (sm->interfaces, i);
1641                 if (is_inside)
1642                   {
1643                     if (sm->endpoint_dependent)
1644                       vnet_feature_enable_disable ("ip4-local",
1645                                                    "nat44-ed-hairpinning",
1646                                                    sw_if_index, 0, 0, 0);
1647                     else if (!sm->deterministic)
1648                       vnet_feature_enable_disable ("ip4-local",
1649                                                    "nat44-hairpinning",
1650                                                    sw_if_index, 0, 0, 0);
1651                   }
1652               }
1653           }
1654         else
1655           {
1656             if ((nat_interface_is_inside(i) && is_inside) ||
1657                 (nat_interface_is_outside(i) && !is_inside))
1658               return 0;
1659
1660             if (sm->num_workers > 1 && !sm->deterministic)
1661               {
1662                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1663                                                  "nat44-out2in-worker-handoff";
1664                 feature_name = "nat44-handoff-classify";
1665               }
1666             else if (sm->deterministic)
1667               {
1668                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1669                                                  "nat44-det-out2in";
1670                 feature_name = "nat44-det-classify";
1671               }
1672             else if (sm->endpoint_dependent)
1673               {
1674                 del_feature_name = !is_inside ?  "nat44-ed-in2out" :
1675                                                  "nat44-ed-out2in";
1676                 feature_name = "nat44-ed-classify";
1677               }
1678             else
1679               {
1680                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1681                 feature_name = "nat44-classify";
1682               }
1683
1684             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1685                                          sw_if_index, 0, 0, 0);
1686             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1687                                          sw_if_index, 1, 0, 0);
1688             if (!is_inside)
1689               {
1690                 if (sm->endpoint_dependent)
1691                   vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1692                                                sw_if_index, 0, 0, 0);
1693                 else if (!sm->deterministic)
1694                   vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1695                                                sw_if_index, 0, 0, 0);
1696               }
1697             goto set_flags;
1698           }
1699
1700         goto fib;
1701       }
1702   }));
1703   /* *INDENT-ON* */
1704
1705   if (is_del)
1706     return VNET_API_ERROR_NO_SUCH_ENTRY;
1707
1708   pool_get (sm->interfaces, i);
1709   i->sw_if_index = sw_if_index;
1710   i->flags = 0;
1711   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0,
1712                                0);
1713
1714   if (is_inside && !sm->out2in_dpo)
1715     {
1716       if (sm->endpoint_dependent)
1717         vnet_feature_enable_disable ("ip4-local", "nat44-ed-hairpinning",
1718                                      sw_if_index, 1, 0, 0);
1719       else if (!sm->deterministic)
1720         vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1721                                      sw_if_index, 1, 0, 0);
1722     }
1723
1724 set_flags:
1725   if (is_inside)
1726     {
1727       i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1728       return 0;
1729     }
1730   else
1731     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1732
1733   /* Add/delete external addresses to FIB */
1734 fib:
1735   /* *INDENT-OFF* */
1736   vec_foreach (ap, sm->addresses)
1737     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1738
1739   pool_foreach (m, sm->static_mappings,
1740   ({
1741     if (!(is_addr_only_static_mapping(m)) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1742       continue;
1743
1744     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1745   }));
1746
1747   pool_foreach (dm, sm->det_maps,
1748   ({
1749     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1750   }));
1751   /* *INDENT-ON* */
1752
1753   return 0;
1754 }
1755
1756 int
1757 snat_interface_add_del_output_feature (u32 sw_if_index,
1758                                        u8 is_inside, int is_del)
1759 {
1760   snat_main_t *sm = &snat_main;
1761   snat_interface_t *i;
1762   snat_address_t *ap;
1763   snat_static_mapping_t *m;
1764
1765   if (sm->deterministic ||
1766       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1767     return VNET_API_ERROR_UNSUPPORTED;
1768
1769   /* *INDENT-OFF* */
1770   pool_foreach (i, sm->interfaces,
1771   ({
1772     if (i->sw_if_index == sw_if_index)
1773       return VNET_API_ERROR_VALUE_EXIST;
1774   }));
1775   /* *INDENT-ON* */
1776
1777   if (is_inside)
1778     {
1779       if (sm->endpoint_dependent)
1780         {
1781           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-hairpin-dst",
1782                                        sw_if_index, !is_del, 0, 0);
1783           vnet_feature_enable_disable ("ip4-output", "nat44-ed-hairpin-src",
1784                                        sw_if_index, !is_del, 0, 0);
1785         }
1786       else
1787         {
1788           vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1789                                        sw_if_index, !is_del, 0, 0);
1790           vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1791                                        sw_if_index, !is_del, 0, 0);
1792         }
1793       goto fq;
1794     }
1795
1796   if (sm->num_workers > 1)
1797     {
1798       vnet_feature_enable_disable ("ip4-unicast",
1799                                    "nat44-out2in-worker-handoff",
1800                                    sw_if_index, !is_del, 0, 0);
1801       vnet_feature_enable_disable ("ip4-output",
1802                                    "nat44-in2out-output-worker-handoff",
1803                                    sw_if_index, !is_del, 0, 0);
1804     }
1805   else
1806     {
1807       if (sm->endpoint_dependent)
1808         {
1809           vnet_feature_enable_disable ("ip4-unicast", "nat44-ed-out2in",
1810                                        sw_if_index, !is_del, 0, 0);
1811           vnet_feature_enable_disable ("ip4-output", "nat44-ed-in2out-output",
1812                                        sw_if_index, !is_del, 0, 0);
1813         }
1814       else
1815         {
1816           vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in",
1817                                        sw_if_index, !is_del, 0, 0);
1818           vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1819                                        sw_if_index, !is_del, 0, 0);
1820         }
1821     }
1822
1823 fq:
1824   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1825     sm->fq_in2out_output_index =
1826       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1827
1828   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1829     sm->fq_out2in_index =
1830       vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1831
1832   /* *INDENT-OFF* */
1833   pool_foreach (i, sm->output_feature_interfaces,
1834   ({
1835     if (i->sw_if_index == sw_if_index)
1836       {
1837         if (is_del)
1838           pool_put (sm->output_feature_interfaces, i);
1839         else
1840           return VNET_API_ERROR_VALUE_EXIST;
1841
1842         goto fib;
1843       }
1844   }));
1845   /* *INDENT-ON* */
1846
1847   if (is_del)
1848     return VNET_API_ERROR_NO_SUCH_ENTRY;
1849
1850   pool_get (sm->output_feature_interfaces, i);
1851   i->sw_if_index = sw_if_index;
1852   i->flags = 0;
1853   if (is_inside)
1854     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1855   else
1856     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1857
1858   /* Add/delete external addresses to FIB */
1859 fib:
1860   if (is_inside)
1861     return 0;
1862
1863   /* *INDENT-OFF* */
1864   vec_foreach (ap, sm->addresses)
1865     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1866
1867   pool_foreach (m, sm->static_mappings,
1868   ({
1869     if (!((is_addr_only_static_mapping(m)))  || (m->local_addr.as_u32 == m->external_addr.as_u32))
1870       continue;
1871
1872     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1873   }));
1874   /* *INDENT-ON* */
1875
1876   return 0;
1877 }
1878
1879 int
1880 snat_set_workers (uword * bitmap)
1881 {
1882   snat_main_t *sm = &snat_main;
1883   int i, j = 0;
1884
1885   if (sm->num_workers < 2)
1886     return VNET_API_ERROR_FEATURE_DISABLED;
1887
1888   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1889     return VNET_API_ERROR_INVALID_WORKER;
1890
1891   vec_free (sm->workers);
1892   /* *INDENT-OFF* */
1893   clib_bitmap_foreach (i, bitmap,
1894     ({
1895       vec_add1(sm->workers, i);
1896       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1897       j++;
1898     }));
1899   /* *INDENT-ON* */
1900
1901   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1902   sm->num_snat_thread = _vec_len (sm->workers);
1903
1904   return 0;
1905 }
1906
1907
1908 static void
1909 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1910                                        uword opaque,
1911                                        u32 sw_if_index,
1912                                        ip4_address_t * address,
1913                                        u32 address_length,
1914                                        u32 if_address_index, u32 is_delete);
1915
1916 static void
1917 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
1918                                  uword opaque,
1919                                  u32 sw_if_index,
1920                                  ip4_address_t * address,
1921                                  u32 address_length,
1922                                  u32 if_address_index, u32 is_delete);
1923
1924 static int
1925 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1926                                  u32 fib_index,
1927                                  u32 thread_index,
1928                                  snat_session_key_t * k,
1929                                  u16 port_per_thread, u32 snat_thread_index);
1930
1931 static clib_error_t *
1932 snat_init (vlib_main_t * vm)
1933 {
1934   snat_main_t *sm = &snat_main;
1935   clib_error_t *error = 0;
1936   ip4_main_t *im = &ip4_main;
1937   ip_lookup_main_t *lm = &im->lookup_main;
1938   uword *p;
1939   vlib_thread_registration_t *tr;
1940   vlib_thread_main_t *tm = vlib_get_thread_main ();
1941   uword *bitmap = 0;
1942   u32 i;
1943   ip4_add_del_interface_address_callback_t cb4;
1944   vlib_node_t *error_drop_node;
1945
1946   sm->vlib_main = vm;
1947   sm->vnet_main = vnet_get_main ();
1948   sm->ip4_main = im;
1949   sm->ip4_lookup_main = lm;
1950   sm->api_main = &api_main;
1951   sm->first_worker_index = 0;
1952   sm->num_workers = 0;
1953   sm->num_snat_thread = 1;
1954   sm->workers = 0;
1955   sm->port_per_thread = 0xffff - 1024;
1956   sm->fq_in2out_index = ~0;
1957   sm->fq_out2in_index = ~0;
1958   sm->udp_timeout = SNAT_UDP_TIMEOUT;
1959   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1960   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1961   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1962   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1963   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
1964   sm->forwarding_enabled = 0;
1965   sm->log_class = vlib_log_register_class ("nat", 0);
1966   error_drop_node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
1967   sm->error_node_index = error_drop_node->index;
1968   sm->mss_clamping = 0;
1969
1970   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1971   if (p)
1972     {
1973       tr = (vlib_thread_registration_t *) p[0];
1974       if (tr)
1975         {
1976           sm->num_workers = tr->count;
1977           sm->first_worker_index = tr->first_index;
1978         }
1979     }
1980
1981   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1982
1983   /* Use all available workers by default */
1984   if (sm->num_workers > 1)
1985     {
1986       for (i = 0; i < sm->num_workers; i++)
1987         bitmap = clib_bitmap_set (bitmap, i, 1);
1988       snat_set_workers (bitmap);
1989       clib_bitmap_free (bitmap);
1990     }
1991   else
1992     {
1993       sm->per_thread_data[0].snat_thread_index = 0;
1994     }
1995
1996   error = snat_api_init (vm, sm);
1997   if (error)
1998     return error;
1999
2000   /* Set up the interface address add/del callback */
2001   cb4.function = snat_ip4_add_del_interface_address_cb;
2002   cb4.function_opaque = 0;
2003
2004   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2005
2006   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
2007   cb4.function_opaque = 0;
2008
2009   vec_add1 (im->add_del_interface_address_callbacks, cb4);
2010
2011   nat_dpo_module_init ();
2012
2013   /* Init IPFIX logging */
2014   snat_ipfix_logging_init (vm);
2015
2016   /* Init NAT64 */
2017   error = nat64_init (vm);
2018   if (error)
2019     return error;
2020
2021   dslite_init (vm);
2022
2023   nat66_init ();
2024
2025   /* Init virtual fragmenentation reassembly */
2026   return nat_reass_init (vm);
2027 }
2028
2029 VLIB_INIT_FUNCTION (snat_init);
2030
2031 void
2032 snat_free_outside_address_and_port (snat_address_t * addresses,
2033                                     u32 thread_index, snat_session_key_t * k)
2034 {
2035   snat_address_t *a;
2036   u32 address_index;
2037   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
2038
2039   for (address_index = 0; address_index < vec_len (addresses);
2040        address_index++)
2041     {
2042       if (addresses[address_index].addr.as_u32 == k->addr.as_u32)
2043         break;
2044     }
2045
2046   ASSERT (address_index < vec_len (addresses));
2047
2048   a = addresses + address_index;
2049
2050   switch (k->protocol)
2051     {
2052 #define _(N, i, n, s) \
2053     case SNAT_PROTOCOL_##N: \
2054       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
2055         port_host_byte_order) == 1); \
2056       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
2057         port_host_byte_order, 0); \
2058       a->busy_##n##_ports--; \
2059       a->busy_##n##_ports_per_thread[thread_index]--; \
2060       break;
2061       foreach_snat_protocol
2062 #undef _
2063     default:
2064       nat_log_info ("unknown protocol");
2065       return;
2066     }
2067 }
2068
2069 int
2070 snat_static_mapping_match (snat_main_t * sm,
2071                            snat_session_key_t match,
2072                            snat_session_key_t * mapping,
2073                            u8 by_external,
2074                            u8 * is_addr_only,
2075                            twice_nat_type_t * twice_nat,
2076                            lb_nat_type_t * lb, ip4_address_t * ext_host_addr,
2077                            u8 * is_identity_nat)
2078 {
2079   clib_bihash_kv_8_8_t kv, value;
2080   snat_static_mapping_t *m;
2081   snat_session_key_t m_key;
2082   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
2083   u32 rand, lo = 0, hi, mid;
2084   u8 backend_index;
2085
2086   m_key.fib_index = match.fib_index;
2087   if (by_external)
2088     {
2089       mapping_hash = &sm->static_mapping_by_external;
2090       m_key.fib_index = 0;
2091     }
2092
2093   m_key.addr = match.addr;
2094   m_key.port = clib_net_to_host_u16 (match.port);
2095   m_key.protocol = match.protocol;
2096
2097   kv.key = m_key.as_u64;
2098
2099   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2100     {
2101       /* Try address only mapping */
2102       m_key.port = 0;
2103       m_key.protocol = 0;
2104       kv.key = m_key.as_u64;
2105       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
2106         return 1;
2107     }
2108
2109   m = pool_elt_at_index (sm->static_mappings, value.value);
2110
2111   if (by_external)
2112     {
2113       if (is_lb_static_mapping (m))
2114         {
2115           if (PREDICT_FALSE (lb != 0))
2116             *lb = m->affinity ? AFFINITY_LB_NAT : LB_NAT;
2117           if (m->affinity)
2118             {
2119               if (nat_affinity_find_and_lock (ext_host_addr[0], match.addr,
2120                                               match.protocol, match.port,
2121                                               &backend_index))
2122                 goto get_local;
2123
2124               mapping->addr = m->locals[backend_index].addr;
2125               mapping->port =
2126                 clib_host_to_net_u16 (m->locals[backend_index].port);
2127               mapping->fib_index = m->locals[backend_index].fib_index;
2128               goto end;
2129             }
2130         get_local:
2131           hi = vec_len (m->locals) - 1;
2132           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
2133           while (lo < hi)
2134             {
2135               mid = ((hi - lo) >> 1) + lo;
2136               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
2137             }
2138           if (!(m->locals[lo].prefix >= rand))
2139             return 1;
2140           if (PREDICT_FALSE (sm->num_workers > 1))
2141             {
2142               ip4_header_t ip = {
2143                 .src_address = m->locals[lo].addr,
2144               };
2145               if (sm->worker_in2out_cb (&ip, m->fib_index) !=
2146                   vlib_get_thread_index ())
2147                 goto get_local;
2148             }
2149           mapping->addr = m->locals[lo].addr;
2150           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
2151           mapping->fib_index = m->locals[lo].fib_index;
2152           if (m->affinity)
2153             {
2154               if (nat_affinity_create_and_lock (ext_host_addr[0], match.addr,
2155                                                 match.protocol, match.port,
2156                                                 lo, m->affinity,
2157                                                 m->affinity_per_service_list_head_index))
2158                 nat_log_info ("create affinity record failed");
2159             }
2160         }
2161       else
2162         {
2163           if (PREDICT_FALSE (lb != 0))
2164             *lb = NO_LB_NAT;
2165           mapping->fib_index = m->fib_index;
2166           mapping->addr = m->local_addr;
2167           /* Address only mapping doesn't change port */
2168           mapping->port = is_addr_only_static_mapping (m) ? match.port
2169             : clib_host_to_net_u16 (m->local_port);
2170         }
2171       mapping->protocol = m->proto;
2172     }
2173   else
2174     {
2175       mapping->addr = m->external_addr;
2176       /* Address only mapping doesn't change port */
2177       mapping->port = is_addr_only_static_mapping (m) ? match.port
2178         : clib_host_to_net_u16 (m->external_port);
2179       mapping->fib_index = sm->outside_fib_index;
2180     }
2181
2182 end:
2183   if (PREDICT_FALSE (is_addr_only != 0))
2184     *is_addr_only = is_addr_only_static_mapping (m);
2185
2186   if (PREDICT_FALSE (twice_nat != 0))
2187     *twice_nat = m->twice_nat;
2188
2189   if (PREDICT_FALSE (is_identity_nat != 0))
2190     *is_identity_nat = is_identity_static_mapping (m);
2191
2192   return 0;
2193 }
2194
2195 static_always_inline u16
2196 snat_random_port (u16 min, u16 max)
2197 {
2198   snat_main_t *sm = &snat_main;
2199   return min + random_u32 (&sm->random_seed) /
2200     (random_u32_max () / (max - min + 1) + 1);
2201 }
2202
2203 int
2204 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2205                                      u32 fib_index,
2206                                      u32 thread_index,
2207                                      snat_session_key_t * k,
2208                                      u16 port_per_thread,
2209                                      u32 snat_thread_index)
2210 {
2211   snat_main_t *sm = &snat_main;
2212
2213   return sm->alloc_addr_and_port (addresses, fib_index, thread_index, k,
2214                                   port_per_thread, snat_thread_index);
2215 }
2216
2217 static int
2218 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2219                                  u32 fib_index,
2220                                  u32 thread_index,
2221                                  snat_session_key_t * k,
2222                                  u16 port_per_thread, u32 snat_thread_index)
2223 {
2224   int i;
2225   snat_address_t *a, *ga = 0;
2226   u32 portnum;
2227
2228   for (i = 0; i < vec_len (addresses); i++)
2229     {
2230       a = addresses + i;
2231       switch (k->protocol)
2232         {
2233 #define _(N, j, n, s) \
2234         case SNAT_PROTOCOL_##N: \
2235           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2236             { \
2237               if (a->fib_index == fib_index) \
2238                 { \
2239                   while (1) \
2240                     { \
2241                       portnum = (port_per_thread * \
2242                         snat_thread_index) + \
2243                         snat_random_port(1, port_per_thread) + 1024; \
2244                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2245                         continue; \
2246                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2247                       a->busy_##n##_ports_per_thread[thread_index]++; \
2248                       a->busy_##n##_ports++; \
2249                       k->addr = a->addr; \
2250                       k->port = clib_host_to_net_u16(portnum); \
2251                       return 0; \
2252                     } \
2253                 } \
2254               else if (a->fib_index == ~0) \
2255                 { \
2256                   ga = a; \
2257                 } \
2258             } \
2259           break;
2260           foreach_snat_protocol
2261 #undef _
2262         default:
2263           nat_log_info ("unknown protocol");
2264           return 1;
2265         }
2266
2267     }
2268
2269   if (ga)
2270     {
2271       a = ga;
2272       switch (k->protocol)
2273         {
2274 #define _(N, j, n, s) \
2275         case SNAT_PROTOCOL_##N: \
2276           while (1) \
2277             { \
2278               portnum = (port_per_thread * \
2279                 snat_thread_index) + \
2280                 snat_random_port(1, port_per_thread) + 1024; \
2281               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2282                 continue; \
2283               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2284               a->busy_##n##_ports_per_thread[thread_index]++; \
2285               a->busy_##n##_ports++; \
2286               k->addr = a->addr; \
2287               k->port = clib_host_to_net_u16(portnum); \
2288               return 0; \
2289             }
2290           break;
2291           foreach_snat_protocol
2292 #undef _
2293         default:
2294           nat_log_info ("unknown protocol");
2295           return 1;
2296         }
2297     }
2298
2299   /* Totally out of translations to use... */
2300   snat_ipfix_logging_addresses_exhausted (0);
2301   return 1;
2302 }
2303
2304 static int
2305 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2306                               u32 fib_index,
2307                               u32 thread_index,
2308                               snat_session_key_t * k,
2309                               u16 port_per_thread, u32 snat_thread_index)
2310 {
2311   snat_main_t *sm = &snat_main;
2312   snat_address_t *a = addresses;
2313   u16 m, ports, portnum, A, j;
2314   m = 16 - (sm->psid_offset + sm->psid_length);
2315   ports = (1 << (16 - sm->psid_length)) - (1 << m);
2316
2317   if (!vec_len (addresses))
2318     goto exhausted;
2319
2320   switch (k->protocol)
2321     {
2322 #define _(N, i, n, s) \
2323     case SNAT_PROTOCOL_##N: \
2324       if (a->busy_##n##_ports < ports) \
2325         { \
2326           while (1) \
2327             { \
2328               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2329               j = snat_random_port(0, pow2_mask(m)); \
2330               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2331               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2332                 continue; \
2333               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2334               a->busy_##n##_ports++; \
2335               k->addr = a->addr; \
2336               k->port = clib_host_to_net_u16 (portnum); \
2337               return 0; \
2338             } \
2339         } \
2340       break;
2341       foreach_snat_protocol
2342 #undef _
2343     default:
2344       nat_log_info ("unknown protocol");
2345       return 1;
2346     }
2347
2348 exhausted:
2349   /* Totally out of translations to use... */
2350   snat_ipfix_logging_addresses_exhausted (0);
2351   return 1;
2352 }
2353
2354 static int
2355 nat_alloc_addr_and_port_range (snat_address_t * addresses,
2356                                u32 fib_index,
2357                                u32 thread_index,
2358                                snat_session_key_t * k,
2359                                u16 port_per_thread, u32 snat_thread_index)
2360 {
2361   snat_main_t *sm = &snat_main;
2362   snat_address_t *a = addresses;
2363   u16 portnum, ports;
2364
2365   ports = sm->end_port - sm->start_port + 1;
2366
2367   if (!vec_len (addresses))
2368     goto exhausted;
2369
2370   switch (k->protocol)
2371     {
2372 #define _(N, i, n, s) \
2373     case SNAT_PROTOCOL_##N: \
2374       if (a->busy_##n##_ports < ports) \
2375         { \
2376           while (1) \
2377             { \
2378               portnum = snat_random_port(sm->start_port, sm->end_port); \
2379               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2380                 continue; \
2381               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2382               a->busy_##n##_ports++; \
2383               k->addr = a->addr; \
2384               k->port = clib_host_to_net_u16 (portnum); \
2385               return 0; \
2386             } \
2387         } \
2388       break;
2389       foreach_snat_protocol
2390 #undef _
2391     default:
2392       nat_log_info ("unknown protocol");
2393       return 1;
2394     }
2395
2396 exhausted:
2397   /* Totally out of translations to use... */
2398   snat_ipfix_logging_addresses_exhausted (0);
2399   return 1;
2400 }
2401
2402 void
2403 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2404 {
2405   dpo_id_t dpo_v4 = DPO_INVALID;
2406   fib_prefix_t pfx = {
2407     .fp_proto = FIB_PROTOCOL_IP4,
2408     .fp_len = 32,
2409     .fp_addr.ip4.as_u32 = addr.as_u32,
2410   };
2411
2412   if (is_add)
2413     {
2414       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2415       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2416                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2417       dpo_reset (&dpo_v4);
2418     }
2419   else
2420     {
2421       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2422     }
2423 }
2424
2425 u8 *
2426 format_session_kvp (u8 * s, va_list * args)
2427 {
2428   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2429   snat_session_key_t k;
2430
2431   k.as_u64 = v->key;
2432
2433   s = format (s, "%U session-index %llu", format_snat_key, &k, v->value);
2434
2435   return s;
2436 }
2437
2438 u8 *
2439 format_static_mapping_kvp (u8 * s, va_list * args)
2440 {
2441   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2442   snat_session_key_t k;
2443
2444   k.as_u64 = v->key;
2445
2446   s = format (s, "%U static-mapping-index %llu",
2447               format_static_mapping_key, &k, v->value);
2448
2449   return s;
2450 }
2451
2452 u8 *
2453 format_user_kvp (u8 * s, va_list * args)
2454 {
2455   clib_bihash_kv_8_8_t *v = va_arg (*args, clib_bihash_kv_8_8_t *);
2456   snat_user_key_t k;
2457
2458   k.as_u64 = v->key;
2459
2460   s = format (s, "%U fib %d user-index %llu", format_ip4_address, &k.addr,
2461               k.fib_index, v->value);
2462
2463   return s;
2464 }
2465
2466 u8 *
2467 format_ed_session_kvp (u8 * s, va_list * args)
2468 {
2469   clib_bihash_kv_16_8_t *v = va_arg (*args, clib_bihash_kv_16_8_t *);
2470   nat_ed_ses_key_t k;
2471
2472   k.as_u64[0] = v->key[0];
2473   k.as_u64[1] = v->key[1];
2474
2475   s =
2476     format (s, "local %U:%d remote %U:%d proto %U fib %d session-index %llu",
2477             format_ip4_address, &k.l_addr, clib_net_to_host_u16 (k.l_port),
2478             format_ip4_address, &k.r_addr, clib_net_to_host_u16 (k.r_port),
2479             format_ip_protocol, k.proto, k.fib_index, v->value);
2480
2481   return s;
2482 }
2483
2484 static u32
2485 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2486 {
2487   snat_main_t *sm = &snat_main;
2488   u32 next_worker_index = 0;
2489   u32 hash;
2490
2491   next_worker_index = sm->first_worker_index;
2492   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2493     (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >> 24);
2494
2495   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2496     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2497   else
2498     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2499
2500   return next_worker_index;
2501 }
2502
2503 static u32
2504 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2505 {
2506   snat_main_t *sm = &snat_main;
2507   udp_header_t *udp;
2508   u16 port;
2509   snat_session_key_t m_key;
2510   clib_bihash_kv_8_8_t kv, value;
2511   snat_static_mapping_t *m;
2512   u32 proto;
2513   u32 next_worker_index = 0;
2514
2515   /* first try static mappings without port */
2516   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2517     {
2518       m_key.addr = ip0->dst_address;
2519       m_key.port = 0;
2520       m_key.protocol = 0;
2521       m_key.fib_index = rx_fib_index0;
2522       kv.key = m_key.as_u64;
2523       if (!clib_bihash_search_8_8
2524           (&sm->static_mapping_by_external, &kv, &value))
2525         {
2526           m = pool_elt_at_index (sm->static_mappings, value.value);
2527           return m->workers[0];
2528         }
2529     }
2530
2531   proto = ip_proto_to_snat_proto (ip0->protocol);
2532   udp = ip4_next_header (ip0);
2533   port = udp->dst_port;
2534
2535   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2536     {
2537       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2538         return vlib_get_thread_index ();
2539
2540       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2541         {
2542           nat_reass_ip4_t *reass;
2543
2544           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2545                                       ip0->fragment_id, ip0->protocol);
2546
2547           if (reass && (reass->thread_index != (u32) ~ 0))
2548             return reass->thread_index;
2549           else
2550             return vlib_get_thread_index ();
2551         }
2552     }
2553
2554   /* unknown protocol */
2555   if (PREDICT_FALSE (proto == ~0))
2556     {
2557       /* use current thread */
2558       return vlib_get_thread_index ();
2559     }
2560
2561   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2562     {
2563       icmp46_header_t *icmp = (icmp46_header_t *) udp;
2564       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
2565       if (!icmp_is_error_message (icmp))
2566         port = echo->identifier;
2567       else
2568         {
2569           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2570           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2571           void *l4_header = ip4_next_header (inner_ip);
2572           switch (proto)
2573             {
2574             case SNAT_PROTOCOL_ICMP:
2575               icmp = (icmp46_header_t *) l4_header;
2576               echo = (icmp_echo_header_t *) (icmp + 1);
2577               port = echo->identifier;
2578               break;
2579             case SNAT_PROTOCOL_UDP:
2580             case SNAT_PROTOCOL_TCP:
2581               port = ((tcp_udp_header_t *) l4_header)->src_port;
2582               break;
2583             default:
2584               return vlib_get_thread_index ();
2585             }
2586         }
2587     }
2588
2589   /* try static mappings with port */
2590   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2591     {
2592       m_key.addr = ip0->dst_address;
2593       m_key.port = clib_net_to_host_u16 (port);
2594       m_key.protocol = proto;
2595       m_key.fib_index = rx_fib_index0;
2596       kv.key = m_key.as_u64;
2597       if (!clib_bihash_search_8_8
2598           (&sm->static_mapping_by_external, &kv, &value))
2599         {
2600           m = pool_elt_at_index (sm->static_mappings, value.value);
2601           return m->workers[0];
2602         }
2603     }
2604
2605   /* worker by outside port */
2606   next_worker_index = sm->first_worker_index;
2607   next_worker_index +=
2608     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2609   return next_worker_index;
2610 }
2611
2612 static u32
2613 nat44_ed_get_worker_out2in_cb (ip4_header_t * ip, u32 rx_fib_index)
2614 {
2615   snat_main_t *sm = &snat_main;
2616   clib_bihash_kv_8_8_t kv, value;
2617   u32 proto, next_worker_index = 0;
2618   udp_header_t *udp;
2619   u16 port;
2620   snat_static_mapping_t *m;
2621   u32 hash;
2622
2623   /* first try static mappings without port */
2624   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2625     {
2626       make_sm_kv (&kv, &ip->dst_address, 0, rx_fib_index, 0);
2627       if (!clib_bihash_search_8_8
2628           (&sm->static_mapping_by_external, &kv, &value))
2629         {
2630           m = pool_elt_at_index (sm->static_mappings, value.value);
2631           return m->workers[0];
2632         }
2633     }
2634
2635   proto = ip_proto_to_snat_proto (ip->protocol);
2636
2637   /* unknown protocol */
2638   if (PREDICT_FALSE (proto == ~0))
2639     {
2640       /* use current thread */
2641       return vlib_get_thread_index ();
2642     }
2643
2644   udp = ip4_next_header (ip);
2645   port = udp->dst_port;
2646
2647   if (PREDICT_FALSE (ip->protocol == IP_PROTOCOL_ICMP))
2648     {
2649       icmp46_header_t *icmp = (icmp46_header_t *) udp;
2650       icmp_echo_header_t *echo = (icmp_echo_header_t *) (icmp + 1);
2651       if (!icmp_is_error_message (icmp))
2652         port = echo->identifier;
2653       else
2654         {
2655           ip4_header_t *inner_ip = (ip4_header_t *) (echo + 1);
2656           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2657           void *l4_header = ip4_next_header (inner_ip);
2658           switch (proto)
2659             {
2660             case SNAT_PROTOCOL_ICMP:
2661               icmp = (icmp46_header_t *) l4_header;
2662               echo = (icmp_echo_header_t *) (icmp + 1);
2663               port = echo->identifier;
2664               break;
2665             case SNAT_PROTOCOL_UDP:
2666             case SNAT_PROTOCOL_TCP:
2667               port = ((tcp_udp_header_t *) l4_header)->src_port;
2668               break;
2669             default:
2670               return vlib_get_thread_index ();
2671             }
2672         }
2673     }
2674
2675   /* try static mappings with port */
2676   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2677     {
2678       make_sm_kv (&kv, &ip->dst_address, proto, rx_fib_index,
2679                   clib_net_to_host_u16 (port));
2680       if (!clib_bihash_search_8_8
2681           (&sm->static_mapping_by_external, &kv, &value))
2682         {
2683           m = pool_elt_at_index (sm->static_mappings, value.value);
2684           if (!is_lb_static_mapping (m))
2685             return m->workers[0];
2686
2687           hash = ip->src_address.as_u32 + (ip->src_address.as_u32 >> 8) +
2688             (ip->src_address.as_u32 >> 16) + (ip->src_address.as_u32 >> 24);
2689
2690           if (PREDICT_TRUE (is_pow2 (_vec_len (m->workers))))
2691             return m->workers[hash & (_vec_len (m->workers) - 1)];
2692           else
2693             return m->workers[hash % _vec_len (m->workers)];
2694         }
2695     }
2696
2697   /* worker by outside port */
2698   next_worker_index = sm->first_worker_index;
2699   next_worker_index +=
2700     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2701
2702   return next_worker_index;
2703 }
2704
2705 static clib_error_t *
2706 snat_config (vlib_main_t * vm, unformat_input_t * input)
2707 {
2708   snat_main_t *sm = &snat_main;
2709   nat66_main_t *nm = &nat66_main;
2710   u32 translation_buckets = 1024;
2711   u32 translation_memory_size = 128 << 20;
2712   u32 user_buckets = 128;
2713   u32 user_memory_size = 64 << 20;
2714   u32 max_translations_per_user = 100;
2715   u32 outside_vrf_id = 0;
2716   u32 outside_ip6_vrf_id = 0;
2717   u32 inside_vrf_id = 0;
2718   u32 static_mapping_buckets = 1024;
2719   u32 static_mapping_memory_size = 64 << 20;
2720   u32 nat64_bib_buckets = 1024;
2721   u32 nat64_bib_memory_size = 128 << 20;
2722   u32 nat64_st_buckets = 2048;
2723   u32 nat64_st_memory_size = 256 << 20;
2724   u8 static_mapping_only = 0;
2725   u8 static_mapping_connection_tracking = 0;
2726   snat_main_per_thread_data_t *tsm;
2727   dslite_main_t *dm = &dslite_main;
2728
2729   sm->deterministic = 0;
2730   sm->out2in_dpo = 0;
2731   sm->endpoint_dependent = 0;
2732
2733   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2734     {
2735       if (unformat
2736           (input, "translation hash buckets %d", &translation_buckets))
2737         ;
2738       else if (unformat (input, "translation hash memory %d",
2739                          &translation_memory_size));
2740       else if (unformat (input, "user hash buckets %d", &user_buckets))
2741         ;
2742       else if (unformat (input, "user hash memory %d", &user_memory_size))
2743         ;
2744       else if (unformat (input, "max translations per user %d",
2745                          &max_translations_per_user))
2746         ;
2747       else if (unformat (input, "outside VRF id %d", &outside_vrf_id))
2748         ;
2749       else if (unformat (input, "outside ip6 VRF id %d", &outside_ip6_vrf_id))
2750         ;
2751       else if (unformat (input, "inside VRF id %d", &inside_vrf_id))
2752         ;
2753       else if (unformat (input, "static mapping only"))
2754         {
2755           static_mapping_only = 1;
2756           if (unformat (input, "connection tracking"))
2757             static_mapping_connection_tracking = 1;
2758         }
2759       else if (unformat (input, "deterministic"))
2760         sm->deterministic = 1;
2761       else if (unformat (input, "nat64 bib hash buckets %d",
2762                          &nat64_bib_buckets))
2763         ;
2764       else if (unformat (input, "nat64 bib hash memory %d",
2765                          &nat64_bib_memory_size))
2766         ;
2767       else
2768         if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2769         ;
2770       else if (unformat (input, "nat64 st hash memory %d",
2771                          &nat64_st_memory_size))
2772         ;
2773       else if (unformat (input, "out2in dpo"))
2774         sm->out2in_dpo = 1;
2775       else if (unformat (input, "dslite ce"))
2776         dslite_set_ce (dm, 1);
2777       else if (unformat (input, "endpoint-dependent"))
2778         sm->endpoint_dependent = 1;
2779       else
2780         return clib_error_return (0, "unknown input '%U'",
2781                                   format_unformat_error, input);
2782     }
2783
2784   if (sm->deterministic && sm->endpoint_dependent)
2785     return clib_error_return (0,
2786                               "deterministic and endpoint-dependent modes are mutually exclusive");
2787
2788   if (static_mapping_only && (sm->deterministic || sm->endpoint_dependent))
2789     return clib_error_return (0,
2790                               "static mapping only mode available only for simple nat");
2791
2792   if (sm->out2in_dpo && (sm->deterministic || sm->endpoint_dependent))
2793     return clib_error_return (0,
2794                               "out2in dpo mode available only for simple nat");
2795
2796   /* for show commands, etc. */
2797   sm->translation_buckets = translation_buckets;
2798   sm->translation_memory_size = translation_memory_size;
2799   /* do not exceed load factor 10 */
2800   sm->max_translations = 10 * translation_buckets;
2801   sm->user_buckets = user_buckets;
2802   sm->user_memory_size = user_memory_size;
2803   sm->max_translations_per_user = max_translations_per_user;
2804   sm->outside_vrf_id = outside_vrf_id;
2805   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2806                                                              outside_vrf_id,
2807                                                              FIB_SOURCE_PLUGIN_HI);
2808   nm->outside_vrf_id = outside_ip6_vrf_id;
2809   nm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
2810                                                              outside_ip6_vrf_id,
2811                                                              FIB_SOURCE_PLUGIN_HI);
2812   sm->inside_vrf_id = inside_vrf_id;
2813   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2814                                                             inside_vrf_id,
2815                                                             FIB_SOURCE_PLUGIN_HI);
2816   sm->static_mapping_only = static_mapping_only;
2817   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2818
2819   nat64_set_hash (nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2820                   nat64_st_memory_size);
2821
2822   if (sm->deterministic)
2823     {
2824       sm->in2out_node_index = snat_det_in2out_node.index;
2825       sm->in2out_output_node_index = ~0;
2826       sm->out2in_node_index = snat_det_out2in_node.index;
2827       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2828       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2829     }
2830   else
2831     {
2832       if (sm->endpoint_dependent)
2833         {
2834           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2835           sm->worker_out2in_cb = nat44_ed_get_worker_out2in_cb;
2836           sm->in2out_node_index = nat44_ed_in2out_node.index;
2837           sm->in2out_output_node_index = nat44_ed_in2out_output_node.index;
2838           sm->out2in_node_index = nat44_ed_out2in_node.index;
2839           sm->icmp_match_in2out_cb = icmp_match_in2out_ed;
2840           sm->icmp_match_out2in_cb = icmp_match_out2in_ed;
2841           nat_affinity_init (vm);
2842         }
2843       else
2844         {
2845           sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2846           sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2847           sm->in2out_node_index = snat_in2out_node.index;
2848           sm->in2out_output_node_index = snat_in2out_output_node.index;
2849           sm->out2in_node_index = snat_out2in_node.index;
2850           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2851           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2852         }
2853       if (!static_mapping_only ||
2854           (static_mapping_only && static_mapping_connection_tracking))
2855         {
2856           /* *INDENT-OFF* */
2857           vec_foreach (tsm, sm->per_thread_data)
2858             {
2859               if (sm->endpoint_dependent)
2860                 {
2861                   clib_bihash_init_16_8 (&tsm->in2out_ed, "in2out-ed",
2862                                          translation_buckets,
2863                                          translation_memory_size);
2864                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->in2out_ed,
2865                                                       format_ed_session_kvp);
2866
2867                   clib_bihash_init_16_8 (&tsm->out2in_ed, "out2in-ed",
2868                                          translation_buckets,
2869                                          translation_memory_size);
2870                   clib_bihash_set_kvp_format_fn_16_8 (&tsm->out2in_ed,
2871                                                       format_ed_session_kvp);
2872                 }
2873               else
2874                 {
2875                   clib_bihash_init_8_8 (&tsm->in2out, "in2out",
2876                                         translation_buckets,
2877                                         translation_memory_size);
2878                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->in2out,
2879                                                      format_session_kvp);
2880
2881                   clib_bihash_init_8_8 (&tsm->out2in, "out2in",
2882                                         translation_buckets,
2883                                         translation_memory_size);
2884                   clib_bihash_set_kvp_format_fn_8_8 (&tsm->out2in,
2885                                                      format_session_kvp);
2886                 }
2887
2888               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2889                                     user_memory_size);
2890               clib_bihash_set_kvp_format_fn_8_8 (&tsm->user_hash,
2891                                                  format_user_kvp);
2892             }
2893           /* *INDENT-ON* */
2894
2895         }
2896       else
2897         {
2898           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2899           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2900         }
2901       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2902                             "static_mapping_by_local", static_mapping_buckets,
2903                             static_mapping_memory_size);
2904       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_local,
2905                                          format_static_mapping_kvp);
2906
2907       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2908                             "static_mapping_by_external",
2909                             static_mapping_buckets,
2910                             static_mapping_memory_size);
2911       clib_bihash_set_kvp_format_fn_8_8 (&sm->static_mapping_by_external,
2912                                          format_static_mapping_kvp);
2913     }
2914
2915   return 0;
2916 }
2917
2918 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2919
2920 static void
2921 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2922                                  uword opaque,
2923                                  u32 sw_if_index,
2924                                  ip4_address_t * address,
2925                                  u32 address_length,
2926                                  u32 if_address_index, u32 is_delete)
2927 {
2928   snat_main_t *sm = &snat_main;
2929   snat_static_map_resolve_t *rp;
2930   snat_static_mapping_t *m;
2931   snat_session_key_t m_key;
2932   clib_bihash_kv_8_8_t kv, value;
2933   int i, rv;
2934   ip4_address_t l_addr;
2935
2936   for (i = 0; i < vec_len (sm->to_resolve); i++)
2937     {
2938       rp = sm->to_resolve + i;
2939       if (rp->addr_only == 0)
2940         continue;
2941       if (rp->sw_if_index == sw_if_index)
2942         goto match;
2943     }
2944
2945   return;
2946
2947 match:
2948   m_key.addr.as_u32 = address->as_u32;
2949   m_key.port = rp->addr_only ? 0 : rp->e_port;
2950   m_key.protocol = rp->addr_only ? 0 : rp->proto;
2951   m_key.fib_index = sm->outside_fib_index;
2952   kv.key = m_key.as_u64;
2953   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2954     m = 0;
2955   else
2956     m = pool_elt_at_index (sm->static_mappings, value.value);
2957
2958   if (!is_delete)
2959     {
2960       /* Don't trip over lease renewal, static config */
2961       if (m)
2962         return;
2963     }
2964   else
2965     {
2966       if (!m)
2967         return;
2968     }
2969
2970   /* Indetity mapping? */
2971   if (rp->l_addr.as_u32 == 0)
2972     l_addr.as_u32 = address[0].as_u32;
2973   else
2974     l_addr.as_u32 = rp->l_addr.as_u32;
2975   /* Add the static mapping */
2976   rv = snat_add_static_mapping (l_addr,
2977                                 address[0],
2978                                 rp->l_port,
2979                                 rp->e_port,
2980                                 rp->vrf_id,
2981                                 rp->addr_only, ~0 /* sw_if_index */ ,
2982                                 rp->proto, !is_delete, rp->twice_nat,
2983                                 rp->out2in_only, rp->tag, rp->identity_nat);
2984   if (rv)
2985     nat_log_notice ("snat_add_static_mapping returned %d", rv);
2986 }
2987
2988 static void
2989 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2990                                        uword opaque,
2991                                        u32 sw_if_index,
2992                                        ip4_address_t * address,
2993                                        u32 address_length,
2994                                        u32 if_address_index, u32 is_delete)
2995 {
2996   snat_main_t *sm = &snat_main;
2997   snat_static_map_resolve_t *rp;
2998   ip4_address_t l_addr;
2999   int i, j;
3000   int rv;
3001   u8 twice_nat = 0;
3002   snat_address_t *addresses = sm->addresses;
3003
3004   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices); i++)
3005     {
3006       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3007         goto match;
3008     }
3009
3010   for (i = 0; i < vec_len (sm->auto_add_sw_if_indices_twice_nat); i++)
3011     {
3012       twice_nat = 1;
3013       addresses = sm->twice_nat_addresses;
3014       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3015         goto match;
3016     }
3017
3018   return;
3019
3020 match:
3021   if (!is_delete)
3022     {
3023       /* Don't trip over lease renewal, static config */
3024       for (j = 0; j < vec_len (addresses); j++)
3025         if (addresses[j].addr.as_u32 == address->as_u32)
3026           return;
3027
3028       (void) snat_add_address (sm, address, ~0, twice_nat);
3029       /* Scan static map resolution vector */
3030       for (j = 0; j < vec_len (sm->to_resolve); j++)
3031         {
3032           rp = sm->to_resolve + j;
3033           if (rp->addr_only)
3034             continue;
3035           /* On this interface? */
3036           if (rp->sw_if_index == sw_if_index)
3037             {
3038               /* Indetity mapping? */
3039               if (rp->l_addr.as_u32 == 0)
3040                 l_addr.as_u32 = address[0].as_u32;
3041               else
3042                 l_addr.as_u32 = rp->l_addr.as_u32;
3043               /* Add the static mapping */
3044               rv = snat_add_static_mapping (l_addr,
3045                                             address[0],
3046                                             rp->l_port,
3047                                             rp->e_port,
3048                                             rp->vrf_id,
3049                                             rp->addr_only,
3050                                             ~0 /* sw_if_index */ ,
3051                                             rp->proto,
3052                                             rp->is_add, rp->twice_nat,
3053                                             rp->out2in_only, rp->tag,
3054                                             rp->identity_nat);
3055               if (rv)
3056                 nat_log_notice ("snat_add_static_mapping returned %d", rv);
3057             }
3058         }
3059       return;
3060     }
3061   else
3062     {
3063       (void) snat_del_address (sm, address[0], 1, twice_nat);
3064       return;
3065     }
3066 }
3067
3068
3069 int
3070 snat_add_interface_address (snat_main_t * sm, u32 sw_if_index, int is_del,
3071                             u8 twice_nat)
3072 {
3073   ip4_main_t *ip4_main = sm->ip4_main;
3074   ip4_address_t *first_int_addr;
3075   snat_static_map_resolve_t *rp;
3076   u32 *indices_to_delete = 0;
3077   int i, j;
3078   u32 *auto_add_sw_if_indices =
3079     twice_nat ? sm->
3080     auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3081
3082   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0        /* just want the address */
3083     );
3084
3085   for (i = 0; i < vec_len (auto_add_sw_if_indices); i++)
3086     {
3087       if (auto_add_sw_if_indices[i] == sw_if_index)
3088         {
3089           if (is_del)
3090             {
3091               /* if have address remove it */
3092               if (first_int_addr)
3093                 (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3094               else
3095                 {
3096                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3097                     {
3098                       rp = sm->to_resolve + j;
3099                       if (rp->sw_if_index == sw_if_index)
3100                         vec_add1 (indices_to_delete, j);
3101                     }
3102                   if (vec_len (indices_to_delete))
3103                     {
3104                       for (j = vec_len (indices_to_delete) - 1; j >= 0; j--)
3105                         vec_del1 (sm->to_resolve, j);
3106                       vec_free (indices_to_delete);
3107                     }
3108                 }
3109               if (twice_nat)
3110                 vec_del1 (sm->auto_add_sw_if_indices_twice_nat, i);
3111               else
3112                 vec_del1 (sm->auto_add_sw_if_indices, i);
3113             }
3114           else
3115             return VNET_API_ERROR_VALUE_EXIST;
3116
3117           return 0;
3118         }
3119     }
3120
3121   if (is_del)
3122     return VNET_API_ERROR_NO_SUCH_ENTRY;
3123
3124   /* add to the auto-address list */
3125   if (twice_nat)
3126     vec_add1 (sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3127   else
3128     vec_add1 (sm->auto_add_sw_if_indices, sw_if_index);
3129
3130   /* If the address is already bound - or static - add it now */
3131   if (first_int_addr)
3132     (void) snat_add_address (sm, first_int_addr, ~0, twice_nat);
3133
3134   return 0;
3135 }
3136
3137 int
3138 nat44_del_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3139                    snat_protocol_t proto, u32 vrf_id, int is_in)
3140 {
3141   snat_main_per_thread_data_t *tsm;
3142   clib_bihash_kv_8_8_t kv, value;
3143   ip4_header_t ip;
3144   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3145   snat_session_key_t key;
3146   snat_session_t *s;
3147   clib_bihash_8_8_t *t;
3148
3149   if (sm->endpoint_dependent)
3150     return VNET_API_ERROR_UNSUPPORTED;
3151
3152   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3153   if (sm->num_workers > 1)
3154     tsm =
3155       vec_elt_at_index (sm->per_thread_data,
3156                         sm->worker_in2out_cb (&ip, fib_index));
3157   else
3158     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3159
3160   key.addr.as_u32 = addr->as_u32;
3161   key.port = clib_host_to_net_u16 (port);
3162   key.protocol = proto;
3163   key.fib_index = fib_index;
3164   kv.key = key.as_u64;
3165   t = is_in ? &tsm->in2out : &tsm->out2in;
3166   if (!clib_bihash_search_8_8 (t, &kv, &value))
3167     {
3168       if (pool_is_free_index (tsm->sessions, value.value))
3169         return VNET_API_ERROR_UNSPECIFIED;
3170
3171       s = pool_elt_at_index (tsm->sessions, value.value);
3172       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3173       nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3174       return 0;
3175     }
3176
3177   return VNET_API_ERROR_NO_SUCH_ENTRY;
3178 }
3179
3180 int
3181 nat44_del_ed_session (snat_main_t * sm, ip4_address_t * addr, u16 port,
3182                       ip4_address_t * eh_addr, u16 eh_port, u8 proto,
3183                       u32 vrf_id, int is_in)
3184 {
3185   ip4_header_t ip;
3186   clib_bihash_16_8_t *t;
3187   nat_ed_ses_key_t key;
3188   clib_bihash_kv_16_8_t kv, value;
3189   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3190   snat_session_t *s;
3191   snat_main_per_thread_data_t *tsm;
3192
3193   if (!sm->endpoint_dependent)
3194     return VNET_API_ERROR_FEATURE_DISABLED;
3195
3196   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3197   if (sm->num_workers > 1)
3198     tsm =
3199       vec_elt_at_index (sm->per_thread_data,
3200                         sm->worker_in2out_cb (&ip, fib_index));
3201   else
3202     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3203
3204   t = is_in ? &tsm->in2out_ed : &tsm->out2in_ed;
3205   key.l_addr.as_u32 = addr->as_u32;
3206   key.r_addr.as_u32 = eh_addr->as_u32;
3207   key.l_port = clib_host_to_net_u16 (port);
3208   key.r_port = clib_host_to_net_u16 (eh_port);
3209   key.proto = proto;
3210   key.fib_index = fib_index;
3211   kv.key[0] = key.as_u64[0];
3212   kv.key[1] = key.as_u64[1];
3213   if (clib_bihash_search_16_8 (t, &kv, &value))
3214     return VNET_API_ERROR_NO_SUCH_ENTRY;
3215
3216   if (pool_is_free_index (tsm->sessions, value.value))
3217     return VNET_API_ERROR_UNSPECIFIED;
3218   s = pool_elt_at_index (tsm->sessions, value.value);
3219   nat_free_session_data (sm, s, tsm - sm->per_thread_data);
3220   nat44_delete_session (sm, s, tsm - sm->per_thread_data);
3221   return 0;
3222 }
3223
3224 void
3225 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3226 {
3227   snat_main_t *sm = &snat_main;
3228
3229   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE;
3230   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3231   sm->psid = psid;
3232   sm->psid_offset = psid_offset;
3233   sm->psid_length = psid_length;
3234 }
3235
3236 void
3237 nat_set_alloc_addr_and_port_range (u16 start_port, u16 end_port)
3238 {
3239   snat_main_t *sm = &snat_main;
3240
3241   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE;
3242   sm->alloc_addr_and_port = nat_alloc_addr_and_port_range;
3243   sm->start_port = start_port;
3244   sm->end_port = end_port;
3245 }
3246
3247 void
3248 nat_set_alloc_addr_and_port_default (void)
3249 {
3250   snat_main_t *sm = &snat_main;
3251
3252   sm->addr_and_port_alloc_alg = NAT_ADDR_AND_PORT_ALLOC_ALG_DEFAULT;
3253   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3254 }
3255
3256 /*
3257  * fd.io coding-style-patch-verification: ON
3258  *
3259  * Local Variables:
3260  * eval: (c-set-style "gnu")
3261  * End:
3262  */