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