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