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