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