NAT44: prohibit multiple static mappings for a single local address (VPP-1224)
[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_HI,
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_HI);
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_HI);
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
686   /* If the external address is a specific interface address */
687   if (sw_if_index != ~0)
688     {
689       ip4_address_t * first_int_addr;
690       snat_static_map_resolve_t *rp, *rp_match = 0;
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             return VNET_API_ERROR_NO_SUCH_ENTRY;
834         }
835
836       pool_get (sm->static_mappings, m);
837       memset (m, 0, sizeof (*m));
838       m->tag = vec_dup (tag);
839       m->local_addr = l_addr;
840       m->external_addr = e_addr;
841       m->addr_only = addr_only;
842       m->vrf_id = vrf_id;
843       m->fib_index = fib_index;
844       m->twice_nat = twice_nat;
845       m->out2in_only = out2in_only;
846       if (!addr_only)
847         {
848           m->local_port = l_port;
849           m->external_port = e_port;
850           m->proto = proto;
851         }
852
853       if (sm->workers)
854         {
855           ip4_header_t ip = {
856             .src_address = m->local_addr,
857           };
858           m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index);
859           tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
860         }
861       else
862         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
863
864       m_key.addr = m->local_addr;
865       m_key.port = m->local_port;
866       m_key.protocol = m->proto;
867       m_key.fib_index = m->fib_index;
868       kv.key = m_key.as_u64;
869       kv.value = m - sm->static_mappings;
870       if (!out2in_only)
871         clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
872       if (twice_nat || out2in_only)
873         {
874           m_key.port = clib_host_to_net_u16 (l_port);
875           kv.key = m_key.as_u64;
876           kv.value = ~0ULL;
877           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
878             clib_warning ("in2out key add failed");
879         }
880
881       m_key.addr = m->external_addr;
882       m_key.port = m->external_port;
883       m_key.fib_index = sm->outside_fib_index;
884       kv.key = m_key.as_u64;
885       kv.value = m - sm->static_mappings;
886       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
887       if (twice_nat || out2in_only)
888         {
889           m_key.port = clib_host_to_net_u16 (e_port);
890           kv.key = m_key.as_u64;
891           kv.value = ~0ULL;
892           if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
893             clib_warning ("out2in key add failed");
894         }
895
896       /* Delete dynamic sessions matching local address (+ local port) */
897       if (!(sm->static_mapping_only))
898         {
899           u_key.addr = m->local_addr;
900           u_key.fib_index = m->fib_index;
901           kv.key = u_key.as_u64;
902           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
903             {
904               user_index = value.value;
905               u = pool_elt_at_index (tsm->users, user_index);
906               if (u->nsessions)
907                 {
908                   head_index = u->sessions_per_user_list_head_index;
909                   head = pool_elt_at_index (tsm->list_pool, head_index);
910                   elt_index = head->next;
911                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
912                   ses_index = elt->value;
913                   while (ses_index != ~0)
914                     {
915                       s =  pool_elt_at_index (tsm->sessions, ses_index);
916                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
917                       ses_index = elt->value;
918
919                       if (snat_is_session_static (s))
920                         continue;
921
922                       if (!addr_only)
923                         {
924                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
925                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
926                             continue;
927                         }
928
929                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
930                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
931                       pool_put_index (tsm->list_pool, s->per_user_index);
932                       pool_put (tsm->sessions, s);
933                       u->nsessions--;
934
935                       if (!addr_only)
936                         break;
937                     }
938                 }
939             }
940         }
941     }
942   else
943     {
944       if (!m)
945         return VNET_API_ERROR_NO_SUCH_ENTRY;
946
947       /* Free external address port */
948       if (!(addr_only || sm->static_mapping_only || out2in_only))
949         {
950           for (i = 0; i < vec_len (sm->addresses); i++)
951             {
952               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
953                 {
954                   a = sm->addresses + i;
955                   switch (proto)
956                     {
957 #define _(N, j, n, s) \
958                     case SNAT_PROTOCOL_##N: \
959                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
960                       if (e_port > 1024) \
961                         { \
962                           a->busy_##n##_ports--; \
963                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
964                         } \
965                       break;
966                       foreach_snat_protocol
967 #undef _
968                     default:
969                       clib_warning("unknown_protocol");
970                       return VNET_API_ERROR_INVALID_VALUE_2;
971                     }
972                   break;
973                 }
974             }
975         }
976
977       if (sm->num_workers > 1)
978         tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
979       else
980         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
981
982       m_key.addr = m->local_addr;
983       m_key.port = m->local_port;
984       m_key.protocol = m->proto;
985       m_key.fib_index = m->fib_index;
986       kv.key = m_key.as_u64;
987       if (!out2in_only)
988         clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
989       if (twice_nat || out2in_only)
990         {
991           m_key.port = clib_host_to_net_u16 (m->local_port);
992           kv.key = m_key.as_u64;
993           kv.value = ~0ULL;
994           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
995             clib_warning ("in2out key del failed");
996         }
997
998       m_key.addr = m->external_addr;
999       m_key.port = m->external_port;
1000       m_key.fib_index = sm->outside_fib_index;
1001       kv.key = m_key.as_u64;
1002       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
1003       if (twice_nat || out2in_only)
1004         {
1005           m_key.port = clib_host_to_net_u16 (m->external_port);
1006           kv.key = m_key.as_u64;
1007           kv.value = ~0ULL;
1008           if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1009             clib_warning ("in2out key del failed");
1010         }
1011
1012       /* Delete session(s) for static mapping if exist */
1013       if (!(sm->static_mapping_only) ||
1014           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
1015         {
1016           u_key.addr = m->local_addr;
1017           u_key.fib_index = m->fib_index;
1018           kv.key = u_key.as_u64;
1019           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1020             {
1021               user_index = value.value;
1022               u = pool_elt_at_index (tsm->users, user_index);
1023               if (u->nstaticsessions)
1024                 {
1025                   head_index = u->sessions_per_user_list_head_index;
1026                   head = pool_elt_at_index (tsm->list_pool, head_index);
1027                   elt_index = head->next;
1028                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1029                   ses_index = elt->value;
1030                   while (ses_index != ~0)
1031                     {
1032                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1033                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1034                       ses_index = elt->value;
1035
1036                       if (!addr_only)
1037                         {
1038                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
1039                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
1040                             continue;
1041                         }
1042
1043                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1044                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
1045                       pool_put_index (tsm->list_pool, s->per_user_index);
1046                       pool_put (tsm->sessions, s);
1047                       u->nstaticsessions--;
1048
1049                       if (!addr_only)
1050                         break;
1051                     }
1052                   if (addr_only)
1053                     {
1054                       pool_put (tsm->users, u);
1055                       clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
1056                     }
1057                 }
1058             }
1059         }
1060
1061       vec_free (m->tag);
1062       /* Delete static mapping from pool */
1063       pool_put (sm->static_mappings, m);
1064     }
1065
1066   if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
1067     return 0;
1068
1069   /* Add/delete external address to FIB */
1070   pool_foreach (interface, sm->interfaces,
1071   ({
1072     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1073       continue;
1074
1075     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1076     break;
1077   }));
1078   pool_foreach (interface, sm->output_feature_interfaces,
1079   ({
1080     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1081       continue;
1082
1083     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
1084     break;
1085   }));
1086
1087   return 0;
1088 }
1089
1090 static int lb_local_exists (nat44_lb_addr_port_t * local,
1091                             ip4_address_t * e_addr, u16 e_port)
1092 {
1093   snat_main_t *sm = &snat_main;
1094   snat_static_mapping_t *m;
1095   nat44_lb_addr_port_t *ap;
1096
1097   /* *INDENT-OFF* */
1098   pool_foreach (m, sm->static_mappings,
1099   ({
1100       if (vec_len(m->locals))
1101         {
1102           if (m->external_port == e_port && m->external_addr.as_u32 == e_addr->as_u32)
1103             continue;
1104
1105           vec_foreach (ap, m->locals)
1106           {
1107             if (ap->port == local->port && ap->addr.as_u32 == local->addr.as_u32)
1108               return 1;
1109           }
1110         }
1111   }));
1112   /* *INDENT-ON* */
1113
1114   return 0;
1115 }
1116
1117 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
1118                                      snat_protocol_t proto, u32 vrf_id,
1119                                      nat44_lb_addr_port_t *locals, u8 is_add,
1120                                      u8 twice_nat, u8 out2in_only, u8 *tag)
1121 {
1122   snat_main_t * sm = &snat_main;
1123   snat_static_mapping_t *m;
1124   snat_session_key_t m_key;
1125   clib_bihash_kv_8_8_t kv, value;
1126   u32 fib_index;
1127   snat_address_t *a = 0;
1128   int i;
1129   nat44_lb_addr_port_t *local;
1130   u32 worker_index = 0, elt_index, head_index, ses_index;
1131   snat_main_per_thread_data_t *tsm;
1132   snat_user_key_t u_key;
1133   snat_user_t *u;
1134   snat_session_t * s;
1135   dlist_elt_t * head, * elt;
1136
1137   m_key.addr = e_addr;
1138   m_key.port = e_port;
1139   m_key.protocol = proto;
1140   m_key.fib_index = sm->outside_fib_index;
1141   kv.key = m_key.as_u64;
1142   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
1143     m = 0;
1144   else
1145     m = pool_elt_at_index (sm->static_mappings, value.value);
1146
1147   if (is_add)
1148     {
1149       if (m)
1150         return VNET_API_ERROR_VALUE_EXIST;
1151
1152       if (vec_len (locals) < 2)
1153         return VNET_API_ERROR_INVALID_VALUE;
1154
1155       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1156                                                      vrf_id,
1157                                                      FIB_SOURCE_PLUGIN_HI);
1158
1159       /* Find external address in allocated addresses and reserve port for
1160          address and port pair mapping when dynamic translations enabled */
1161       if (!(sm->static_mapping_only || out2in_only))
1162         {
1163           for (i = 0; i < vec_len (sm->addresses); i++)
1164             {
1165               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1166                 {
1167                   a = sm->addresses + i;
1168                   /* External port must be unused */
1169                   switch (proto)
1170                     {
1171 #define _(N, j, n, s) \
1172                     case SNAT_PROTOCOL_##N: \
1173                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1174                         return VNET_API_ERROR_INVALID_VALUE; \
1175                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1176                       if (e_port > 1024) \
1177                         { \
1178                           a->busy_##n##_ports++; \
1179                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1180                         } \
1181                       break;
1182                       foreach_snat_protocol
1183 #undef _
1184                     default:
1185                       clib_warning("unknown_protocol");
1186                       return VNET_API_ERROR_INVALID_VALUE_2;
1187                     }
1188                   break;
1189                 }
1190             }
1191           /* External address must be allocated */
1192           if (!a)
1193             return VNET_API_ERROR_NO_SUCH_ENTRY;
1194         }
1195
1196       pool_get (sm->static_mappings, m);
1197       memset (m, 0, sizeof (*m));
1198       m->tag = vec_dup (tag);
1199       m->external_addr = e_addr;
1200       m->addr_only = 0;
1201       m->vrf_id = vrf_id;
1202       m->fib_index = fib_index;
1203       m->external_port = e_port;
1204       m->proto = proto;
1205       m->twice_nat = twice_nat;
1206       m->out2in_only = out2in_only;
1207
1208       m_key.addr = m->external_addr;
1209       m_key.port = m->external_port;
1210       m_key.protocol = m->proto;
1211       m_key.fib_index = sm->outside_fib_index;
1212       kv.key = m_key.as_u64;
1213       kv.value = m - sm->static_mappings;
1214       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1215         {
1216           clib_warning ("static_mapping_by_external key add failed");
1217           return VNET_API_ERROR_UNSPECIFIED;
1218         }
1219
1220       /* Assign worker */
1221       if (sm->workers)
1222         {
1223           worker_index = sm->first_worker_index +
1224             sm->workers[sm->next_worker++ % vec_len (sm->workers)];
1225           tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
1226           m->worker_index = worker_index;
1227         }
1228       else
1229         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1230
1231       m_key.port = clib_host_to_net_u16 (m->external_port);
1232       kv.key = m_key.as_u64;
1233       kv.value = ~0ULL;
1234       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
1235         {
1236           clib_warning ("out2in key add failed");
1237           return VNET_API_ERROR_UNSPECIFIED;
1238         }
1239
1240       m_key.fib_index = m->fib_index;
1241       for (i = 0; i < vec_len (locals); i++)
1242         {
1243           m_key.addr = locals[i].addr;
1244           if (!out2in_only)
1245             {
1246               m_key.port = locals[i].port;
1247               kv.key = m_key.as_u64;
1248               kv.value = m - sm->static_mappings;
1249               clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1250             }
1251           locals[i].prefix = (i == 0) ? locals[i].probability :\
1252             (locals[i - 1].prefix + locals[i].probability);
1253           vec_add1 (m->locals, locals[i]);
1254
1255           m_key.port = clib_host_to_net_u16 (locals[i].port);
1256           kv.key = m_key.as_u64;
1257           kv.value = ~0ULL;
1258           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
1259             {
1260               clib_warning ("in2out key add failed");
1261               return VNET_API_ERROR_UNSPECIFIED;
1262             }
1263         }
1264     }
1265   else
1266     {
1267       if (!m)
1268         return VNET_API_ERROR_NO_SUCH_ENTRY;
1269
1270       fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
1271
1272       /* Free external address port */
1273       if (!(sm->static_mapping_only || out2in_only))
1274         {
1275           for (i = 0; i < vec_len (sm->addresses); i++)
1276             {
1277               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1278                 {
1279                   a = sm->addresses + i;
1280                   switch (proto)
1281                     {
1282 #define _(N, j, n, s) \
1283                     case SNAT_PROTOCOL_##N: \
1284                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1285                       if (e_port > 1024) \
1286                         { \
1287                           a->busy_##n##_ports--; \
1288                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1289                         } \
1290                       break;
1291                       foreach_snat_protocol
1292 #undef _
1293                     default:
1294                       clib_warning("unknown_protocol");
1295                       return VNET_API_ERROR_INVALID_VALUE_2;
1296                     }
1297                   break;
1298                 }
1299             }
1300         }
1301
1302       tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
1303       m_key.addr = m->external_addr;
1304       m_key.port = m->external_port;
1305       m_key.protocol = m->proto;
1306       m_key.fib_index = sm->outside_fib_index;
1307       kv.key = m_key.as_u64;
1308       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1309         {
1310           clib_warning ("static_mapping_by_external key del failed");
1311           return VNET_API_ERROR_UNSPECIFIED;
1312         }
1313
1314       m_key.port = clib_host_to_net_u16 (m->external_port);
1315       kv.key = m_key.as_u64;
1316       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1317         {
1318           clib_warning ("outi2in key del failed");
1319           return VNET_API_ERROR_UNSPECIFIED;
1320         }
1321
1322       vec_foreach (local, m->locals)
1323         {
1324           m_key.addr = local->addr;
1325           if (!out2in_only)
1326             {
1327               m_key.port = local->port;
1328               m_key.fib_index = m->fib_index;
1329               kv.key = m_key.as_u64;
1330               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1331                 {
1332                   clib_warning ("static_mapping_by_local key del failed");
1333                   return VNET_API_ERROR_UNSPECIFIED;
1334                 }
1335             }
1336
1337           if (!lb_local_exists(local, &e_addr, e_port))
1338             {
1339               m_key.port = clib_host_to_net_u16 (local->port);
1340               kv.key = m_key.as_u64;
1341               if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1342                 {
1343                   clib_warning ("in2out key del failed");
1344                   return VNET_API_ERROR_UNSPECIFIED;
1345                 }
1346             }
1347           /* Delete sessions */
1348           u_key.addr = local->addr;
1349           u_key.fib_index = m->fib_index;
1350           kv.key = u_key.as_u64;
1351           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1352             {
1353               u = pool_elt_at_index (tsm->users, value.value);
1354               if (u->nstaticsessions)
1355                 {
1356                   head_index = u->sessions_per_user_list_head_index;
1357                   head = pool_elt_at_index (tsm->list_pool, head_index);
1358                   elt_index = head->next;
1359                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1360                   ses_index = elt->value;
1361                   while (ses_index != ~0)
1362                     {
1363                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1364                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1365                       ses_index = elt->value;
1366
1367                       if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
1368                           (clib_net_to_host_u16 (s->in2out.port) != local->port))
1369                         continue;
1370
1371                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1372                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
1373                       pool_put_index (tsm->list_pool, s->per_user_index);
1374                       pool_put (tsm->sessions, s);
1375                       u->nstaticsessions--;
1376                     }
1377                 }
1378             }
1379         }
1380       vec_free(m->locals);
1381       vec_free(m->tag);
1382
1383       pool_put (sm->static_mappings, m);
1384     }
1385
1386   return 0;
1387 }
1388
1389 int
1390 snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
1391                   u8 twice_nat)
1392 {
1393   snat_address_t *a = 0;
1394   snat_session_t *ses;
1395   u32 *ses_to_be_removed = 0, *ses_index;
1396   clib_bihash_kv_8_8_t kv, value;
1397   snat_user_key_t user_key;
1398   snat_user_t *u;
1399   snat_main_per_thread_data_t *tsm;
1400   snat_static_mapping_t *m;
1401   snat_interface_t *interface;
1402   int i;
1403   snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1404
1405   /* Find SNAT address */
1406   for (i=0; i < vec_len (addresses); i++)
1407     {
1408       if (addresses[i].addr.as_u32 == addr.as_u32)
1409         {
1410           a = addresses + i;
1411           break;
1412         }
1413     }
1414   if (!a)
1415     return VNET_API_ERROR_NO_SUCH_ENTRY;
1416
1417   if (delete_sm)
1418     {
1419       pool_foreach (m, sm->static_mappings,
1420       ({
1421           if (m->external_addr.as_u32 == addr.as_u32)
1422             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1423                                             m->local_port, m->external_port,
1424                                             m->vrf_id, m->addr_only, ~0,
1425                                             m->proto, 0, m->twice_nat,
1426                                             m->out2in_only, m->tag);
1427       }));
1428     }
1429   else
1430     {
1431       /* Check if address is used in some static mapping */
1432       if (is_snat_address_used_in_static_mapping(sm, addr))
1433         {
1434           clib_warning ("address used in static mapping");
1435           return VNET_API_ERROR_UNSPECIFIED;
1436         }
1437     }
1438
1439   if (a->fib_index != ~0)
1440     fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
1441                      FIB_SOURCE_PLUGIN_HI);
1442
1443   /* Delete sessions using address */
1444   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1445     {
1446       vec_foreach (tsm, sm->per_thread_data)
1447         {
1448           pool_foreach (ses, tsm->sessions, ({
1449             if (ses->out2in.addr.as_u32 == addr.as_u32)
1450               {
1451                 ses->outside_address_index = ~0;
1452                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1453                 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1454                 pool_put_index (tsm->list_pool, ses->per_user_index);
1455                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1456                 user_key.addr = ses->in2out.addr;
1457                 user_key.fib_index = ses->in2out.fib_index;
1458                 kv.key = user_key.as_u64;
1459                 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1460                   {
1461                     u = pool_elt_at_index (tsm->users, value.value);
1462                     u->nsessions--;
1463                   }
1464               }
1465           }));
1466
1467           vec_foreach (ses_index, ses_to_be_removed)
1468             pool_put_index (tsm->sessions, ses_index[0]);
1469
1470           vec_free (ses_to_be_removed);
1471        }
1472     }
1473
1474   if (twice_nat)
1475     {
1476       vec_del1 (sm->twice_nat_addresses, i);
1477       return 0;
1478     }
1479   else
1480     vec_del1 (sm->addresses, i);
1481
1482   /* Delete external address from FIB */
1483   pool_foreach (interface, sm->interfaces,
1484   ({
1485     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1486       continue;
1487
1488     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1489     break;
1490   }));
1491   pool_foreach (interface, sm->output_feature_interfaces,
1492   ({
1493     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1494       continue;
1495
1496     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1497     break;
1498   }));
1499
1500   return 0;
1501 }
1502
1503 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1504 {
1505   snat_main_t *sm = &snat_main;
1506   snat_interface_t *i;
1507   const char * feature_name, *del_feature_name;
1508   snat_address_t * ap;
1509   snat_static_mapping_t * m;
1510   snat_det_map_t * dm;
1511
1512   if (sm->out2in_dpo && !is_inside)
1513     return VNET_API_ERROR_UNSUPPORTED;
1514
1515   pool_foreach (i, sm->output_feature_interfaces,
1516   ({
1517     if (i->sw_if_index == sw_if_index)
1518       return VNET_API_ERROR_VALUE_EXIST;
1519   }));
1520
1521   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1522     feature_name = is_inside ?  "nat44-in2out-fast" : "nat44-out2in-fast";
1523   else
1524     {
1525       if (sm->num_workers > 1 && !sm->deterministic)
1526         feature_name = is_inside ?  "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1527       else if (sm->deterministic)
1528         feature_name = is_inside ?  "nat44-det-in2out" : "nat44-det-out2in";
1529       else
1530         feature_name = is_inside ?  "nat44-in2out" : "nat44-out2in";
1531     }
1532
1533   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1534     sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
1535
1536   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1537     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1538
1539   pool_foreach (i, sm->interfaces,
1540   ({
1541     if (i->sw_if_index == sw_if_index)
1542       {
1543         if (is_del)
1544           {
1545             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1546               {
1547                 if (is_inside)
1548                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1549                 else
1550                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1551
1552                 if (sm->num_workers > 1 && !sm->deterministic)
1553                   {
1554                     del_feature_name = "nat44-handoff-classify";
1555                     feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1556                                                  "nat44-out2in-worker-handoff";
1557                   }
1558                 else if (sm->deterministic)
1559                   {
1560                     del_feature_name = "nat44-det-classify";
1561                     feature_name = !is_inside ?  "nat44-det-in2out" :
1562                                                  "nat44-det-out2in";
1563                   }
1564                 else
1565                   {
1566                     del_feature_name = "nat44-classify";
1567                     feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1568                   }
1569
1570                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1571                                              sw_if_index, 0, 0, 0);
1572                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1573                                              sw_if_index, 1, 0, 0);
1574               }
1575             else
1576               {
1577                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1578                                              sw_if_index, 0, 0, 0);
1579                 pool_put (sm->interfaces, i);
1580               }
1581           }
1582         else
1583           {
1584             if ((nat_interface_is_inside(i) && is_inside) ||
1585                 (nat_interface_is_outside(i) && !is_inside))
1586               return 0;
1587
1588             if (sm->num_workers > 1 && !sm->deterministic)
1589               {
1590                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1591                                                  "nat44-out2in-worker-handoff";
1592                 feature_name = "nat44-handoff-classify";
1593               }
1594             else if (sm->deterministic)
1595               {
1596                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1597                                                  "nat44-det-out2in";
1598                 feature_name = "nat44-det-classify";
1599               }
1600             else
1601               {
1602                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1603                 feature_name = "nat44-classify";
1604               }
1605
1606             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1607                                          sw_if_index, 0, 0, 0);
1608             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1609                                          sw_if_index, 1, 0, 0);
1610             goto set_flags;
1611           }
1612
1613         goto fib;
1614       }
1615   }));
1616
1617   if (is_del)
1618     return VNET_API_ERROR_NO_SUCH_ENTRY;
1619
1620   pool_get (sm->interfaces, i);
1621   i->sw_if_index = sw_if_index;
1622   i->flags = 0;
1623   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1624
1625 set_flags:
1626   if (is_inside)
1627     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1628   else
1629     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1630
1631   /* Add/delete external addresses to FIB */
1632 fib:
1633   if (is_inside && !sm->out2in_dpo)
1634     {
1635       vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1636                                    sw_if_index, !is_del, 0, 0);
1637       return 0;
1638     }
1639
1640   vec_foreach (ap, sm->addresses)
1641     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1642
1643   pool_foreach (m, sm->static_mappings,
1644   ({
1645     if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1646       continue;
1647
1648     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1649   }));
1650
1651   pool_foreach (dm, sm->det_maps,
1652   ({
1653     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1654   }));
1655
1656   return 0;
1657 }
1658
1659 int snat_interface_add_del_output_feature (u32 sw_if_index,
1660                                            u8 is_inside,
1661                                            int is_del)
1662 {
1663   snat_main_t *sm = &snat_main;
1664   snat_interface_t *i;
1665   snat_address_t * ap;
1666   snat_static_mapping_t * m;
1667
1668   if (sm->deterministic ||
1669       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1670     return VNET_API_ERROR_UNSUPPORTED;
1671
1672   pool_foreach (i, sm->interfaces,
1673   ({
1674     if (i->sw_if_index == sw_if_index)
1675       return VNET_API_ERROR_VALUE_EXIST;
1676   }));
1677
1678   if (is_inside)
1679     {
1680       vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1681                                    sw_if_index, !is_del, 0, 0);
1682       vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1683                                    sw_if_index, !is_del, 0, 0);
1684       goto fq;
1685     }
1686
1687   if (sm->num_workers > 1)
1688     {
1689       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1690                                    sw_if_index, !is_del, 0, 0);
1691       vnet_feature_enable_disable ("ip4-output",
1692                                    "nat44-in2out-output-worker-handoff",
1693                                    sw_if_index, !is_del, 0, 0);
1694     }
1695   else
1696     {
1697       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1698                                    !is_del, 0, 0);
1699       vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1700                                    sw_if_index, !is_del, 0, 0);
1701     }
1702
1703 fq:
1704   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1705     sm->fq_in2out_output_index =
1706       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1707
1708   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1709     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1710
1711   pool_foreach (i, sm->output_feature_interfaces,
1712   ({
1713     if (i->sw_if_index == sw_if_index)
1714       {
1715         if (is_del)
1716           pool_put (sm->output_feature_interfaces, i);
1717         else
1718           return VNET_API_ERROR_VALUE_EXIST;
1719
1720         goto fib;
1721       }
1722   }));
1723
1724   if (is_del)
1725     return VNET_API_ERROR_NO_SUCH_ENTRY;
1726
1727   pool_get (sm->output_feature_interfaces, i);
1728   i->sw_if_index = sw_if_index;
1729   i->flags = 0;
1730   if (is_inside)
1731     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1732   else
1733     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1734
1735   /* Add/delete external addresses to FIB */
1736 fib:
1737   if (is_inside)
1738     return 0;
1739
1740   vec_foreach (ap, sm->addresses)
1741     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1742
1743   pool_foreach (m, sm->static_mappings,
1744   ({
1745     if (!(m->addr_only))
1746       continue;
1747
1748     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1749   }));
1750
1751   return 0;
1752 }
1753
1754 int snat_set_workers (uword * bitmap)
1755 {
1756   snat_main_t *sm = &snat_main;
1757   int i, j = 0;
1758
1759   if (sm->num_workers < 2)
1760     return VNET_API_ERROR_FEATURE_DISABLED;
1761
1762   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1763     return VNET_API_ERROR_INVALID_WORKER;
1764
1765   vec_free (sm->workers);
1766   clib_bitmap_foreach (i, bitmap,
1767     ({
1768       vec_add1(sm->workers, i);
1769       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1770       j++;
1771     }));
1772
1773   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1774   sm->num_snat_thread = _vec_len (sm->workers);
1775
1776   return 0;
1777 }
1778
1779
1780 static void
1781 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1782                                        uword opaque,
1783                                        u32 sw_if_index,
1784                                        ip4_address_t * address,
1785                                        u32 address_length,
1786                                        u32 if_address_index,
1787                                        u32 is_delete);
1788
1789 static void
1790 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
1791                                  uword opaque,
1792                                  u32 sw_if_index,
1793                                  ip4_address_t * address,
1794                                  u32 address_length,
1795                                  u32 if_address_index,
1796                                  u32 is_delete);
1797
1798 static int
1799 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1800                                  u32 fib_index,
1801                                  u32 thread_index,
1802                                  snat_session_key_t * k,
1803                                  u32 * address_indexp,
1804                                  u16 port_per_thread,
1805                                  u32 snat_thread_index);
1806
1807 static clib_error_t * snat_init (vlib_main_t * vm)
1808 {
1809   snat_main_t * sm = &snat_main;
1810   clib_error_t * error = 0;
1811   ip4_main_t * im = &ip4_main;
1812   ip_lookup_main_t * lm = &im->lookup_main;
1813   uword *p;
1814   vlib_thread_registration_t *tr;
1815   vlib_thread_main_t *tm = vlib_get_thread_main ();
1816   uword *bitmap = 0;
1817   u32 i;
1818   ip4_add_del_interface_address_callback_t cb4;
1819
1820   sm->vlib_main = vm;
1821   sm->vnet_main = vnet_get_main();
1822   sm->ip4_main = im;
1823   sm->ip4_lookup_main = lm;
1824   sm->api_main = &api_main;
1825   sm->first_worker_index = 0;
1826   sm->next_worker = 0;
1827   sm->num_workers = 0;
1828   sm->num_snat_thread = 1;
1829   sm->workers = 0;
1830   sm->port_per_thread = 0xffff - 1024;
1831   sm->fq_in2out_index = ~0;
1832   sm->fq_out2in_index = ~0;
1833   sm->udp_timeout = SNAT_UDP_TIMEOUT;
1834   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1835   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1836   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1837   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1838   sm->forwarding_enabled = 0;
1839
1840   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1841   if (p)
1842     {
1843       tr = (vlib_thread_registration_t *) p[0];
1844       if (tr)
1845         {
1846           sm->num_workers = tr->count;
1847           sm->first_worker_index = tr->first_index;
1848         }
1849     }
1850
1851   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1852
1853   /* Use all available workers by default */
1854   if (sm->num_workers > 1)
1855     {
1856       for (i=0; i < sm->num_workers; i++)
1857         bitmap = clib_bitmap_set (bitmap, i, 1);
1858       snat_set_workers(bitmap);
1859       clib_bitmap_free (bitmap);
1860     }
1861   else
1862     {
1863       sm->per_thread_data[0].snat_thread_index = 0;
1864     }
1865
1866   error = snat_api_init(vm, sm);
1867   if (error)
1868     return error;
1869
1870   /* Set up the interface address add/del callback */
1871   cb4.function = snat_ip4_add_del_interface_address_cb;
1872   cb4.function_opaque = 0;
1873
1874   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1875
1876   cb4.function = nat_ip4_add_del_addr_only_sm_cb;
1877   cb4.function_opaque = 0;
1878
1879   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1880
1881   nat_dpo_module_init ();
1882
1883   /* Init IPFIX logging */
1884   snat_ipfix_logging_init(vm);
1885
1886   /* Init NAT64 */
1887   error = nat64_init(vm);
1888   if (error)
1889     return error;
1890
1891   dslite_init(vm);
1892
1893   nat66_init();
1894
1895   /* Init virtual fragmenentation reassembly */
1896   return nat_reass_init(vm);
1897 }
1898
1899 VLIB_INIT_FUNCTION (snat_init);
1900
1901 void snat_free_outside_address_and_port (snat_address_t * addresses,
1902                                          u32 thread_index,
1903                                          snat_session_key_t * k,
1904                                          u32 address_index)
1905 {
1906   snat_address_t *a;
1907   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1908
1909   ASSERT (address_index < vec_len (addresses));
1910
1911   a = addresses + address_index;
1912
1913   switch (k->protocol)
1914     {
1915 #define _(N, i, n, s) \
1916     case SNAT_PROTOCOL_##N: \
1917       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1918         port_host_byte_order) == 1); \
1919       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1920         port_host_byte_order, 0); \
1921       a->busy_##n##_ports--; \
1922       a->busy_##n##_ports_per_thread[thread_index]--; \
1923       break;
1924       foreach_snat_protocol
1925 #undef _
1926     default:
1927       clib_warning("unknown_protocol");
1928       return;
1929     }
1930 }
1931
1932 /**
1933  * @brief Match NAT44 static mapping.
1934  *
1935  * @param sm          NAT main.
1936  * @param match       Address and port to match.
1937  * @param mapping     External or local address and port of the matched mapping.
1938  * @param by_external If 0 match by local address otherwise match by external
1939  *                    address.
1940  * @param is_addr_only If matched mapping is address only
1941  * @param twice_nat If matched mapping is twice NAT.
1942  *
1943  * @returns 0 if match found otherwise 1.
1944  */
1945 int snat_static_mapping_match (snat_main_t * sm,
1946                                snat_session_key_t match,
1947                                snat_session_key_t * mapping,
1948                                u8 by_external,
1949                                u8 *is_addr_only,
1950                                u8 *twice_nat)
1951 {
1952   clib_bihash_kv_8_8_t kv, value;
1953   snat_static_mapping_t *m;
1954   snat_session_key_t m_key;
1955   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1956   u32 rand, lo = 0, hi, mid;
1957
1958   if (by_external)
1959     mapping_hash = &sm->static_mapping_by_external;
1960
1961   m_key.addr = match.addr;
1962   m_key.port = clib_net_to_host_u16 (match.port);
1963   m_key.protocol = match.protocol;
1964   m_key.fib_index = match.fib_index;
1965
1966   kv.key = m_key.as_u64;
1967
1968   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1969     {
1970       /* Try address only mapping */
1971       m_key.port = 0;
1972       m_key.protocol = 0;
1973       kv.key = m_key.as_u64;
1974       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1975         return 1;
1976     }
1977
1978   m = pool_elt_at_index (sm->static_mappings, value.value);
1979
1980   if (by_external)
1981     {
1982       if (vec_len (m->locals))
1983         {
1984           hi = vec_len (m->locals) - 1;
1985           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1986           while (lo < hi)
1987             {
1988               mid = ((hi - lo) >> 1) + lo;
1989               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1990             }
1991           if (!(m->locals[lo].prefix >= rand))
1992             return 1;
1993           mapping->addr = m->locals[lo].addr;
1994           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1995         }
1996       else
1997         {
1998           mapping->addr = m->local_addr;
1999           /* Address only mapping doesn't change port */
2000           mapping->port = m->addr_only ? match.port
2001             : clib_host_to_net_u16 (m->local_port);
2002         }
2003       mapping->fib_index = m->fib_index;
2004       mapping->protocol = m->proto;
2005     }
2006   else
2007     {
2008       mapping->addr = m->external_addr;
2009       /* Address only mapping doesn't change port */
2010       mapping->port = m->addr_only ? match.port
2011         : clib_host_to_net_u16 (m->external_port);
2012       mapping->fib_index = sm->outside_fib_index;
2013     }
2014
2015   if (PREDICT_FALSE(is_addr_only != 0))
2016     *is_addr_only = m->addr_only;
2017
2018   if (PREDICT_FALSE(twice_nat != 0))
2019     *twice_nat = m->twice_nat;
2020
2021   return 0;
2022 }
2023
2024 static_always_inline u16
2025 snat_random_port (u16 min, u16 max)
2026 {
2027   snat_main_t *sm = &snat_main;
2028   return min + random_u32 (&sm->random_seed) /
2029     (random_u32_max() / (max - min + 1) + 1);
2030 }
2031
2032 int
2033 snat_alloc_outside_address_and_port (snat_address_t * addresses,
2034                                      u32 fib_index,
2035                                      u32 thread_index,
2036                                      snat_session_key_t * k,
2037                                      u32 * address_indexp,
2038                                      u16 port_per_thread,
2039                                      u32 snat_thread_index)
2040 {
2041   snat_main_t *sm = &snat_main;
2042
2043   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
2044                                  address_indexp, port_per_thread,
2045                                  snat_thread_index);
2046 }
2047
2048 static int
2049 nat_alloc_addr_and_port_default (snat_address_t * addresses,
2050                                  u32 fib_index,
2051                                  u32 thread_index,
2052                                  snat_session_key_t * k,
2053                                  u32 * address_indexp,
2054                                  u16 port_per_thread,
2055                                  u32 snat_thread_index)
2056 {
2057   int i, gi = 0;
2058   snat_address_t *a, *ga = 0;
2059   u32 portnum;
2060
2061   for (i = 0; i < vec_len (addresses); i++)
2062     {
2063       a = addresses + i;
2064       switch (k->protocol)
2065         {
2066 #define _(N, j, n, s) \
2067         case SNAT_PROTOCOL_##N: \
2068           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
2069             { \
2070               if (a->fib_index == fib_index) \
2071                 { \
2072                   while (1) \
2073                     { \
2074                       portnum = (port_per_thread * \
2075                         snat_thread_index) + \
2076                         snat_random_port(1, port_per_thread) + 1024; \
2077                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2078                         continue; \
2079                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2080                       a->busy_##n##_ports_per_thread[thread_index]++; \
2081                       a->busy_##n##_ports++; \
2082                       k->addr = a->addr; \
2083                       k->port = clib_host_to_net_u16(portnum); \
2084                       *address_indexp = i; \
2085                       return 0; \
2086                     } \
2087                 } \
2088               else if (a->fib_index == ~0) \
2089                 { \
2090                   ga = a; \
2091                   gi = i; \
2092                 } \
2093             } \
2094           break;
2095           foreach_snat_protocol
2096 #undef _
2097         default:
2098           clib_warning("unknown protocol");
2099           return 1;
2100         }
2101
2102     }
2103
2104   if (ga)
2105     {
2106       a = ga;
2107       switch (k->protocol)
2108         {
2109 #define _(N, j, n, s) \
2110         case SNAT_PROTOCOL_##N: \
2111           while (1) \
2112             { \
2113               portnum = (port_per_thread * \
2114                 snat_thread_index) + \
2115                 snat_random_port(1, port_per_thread) + 1024; \
2116               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2117                 continue; \
2118               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2119               a->busy_##n##_ports_per_thread[thread_index]++; \
2120               a->busy_##n##_ports++; \
2121               k->addr = a->addr; \
2122               k->port = clib_host_to_net_u16(portnum); \
2123               *address_indexp = gi; \
2124               return 0; \
2125             }
2126           break;
2127           foreach_snat_protocol
2128 #undef _
2129         default:
2130           clib_warning ("unknown protocol");
2131           return 1;
2132         }
2133     }
2134
2135   /* Totally out of translations to use... */
2136   snat_ipfix_logging_addresses_exhausted(0);
2137   return 1;
2138 }
2139
2140 static int
2141 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
2142                               u32 fib_index,
2143                               u32 thread_index,
2144                               snat_session_key_t * k,
2145                               u32 * address_indexp,
2146                               u16 port_per_thread,
2147                               u32 snat_thread_index)
2148 {
2149   snat_main_t *sm = &snat_main;
2150   snat_address_t *a = addresses;
2151   u16 m, ports, portnum, A, j;
2152   m = 16 - (sm->psid_offset + sm->psid_length);
2153   ports = (1 << (16 - sm->psid_length)) - (1 << m);
2154
2155   if (!vec_len (addresses))
2156     goto exhausted;
2157
2158   switch (k->protocol)
2159     {
2160 #define _(N, i, n, s) \
2161     case SNAT_PROTOCOL_##N: \
2162       if (a->busy_##n##_ports < ports) \
2163         { \
2164           while (1) \
2165             { \
2166               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
2167               j = snat_random_port(0, pow2_mask(m)); \
2168               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
2169               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
2170                 continue; \
2171               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
2172               a->busy_##n##_ports++; \
2173               k->addr = a->addr; \
2174               k->port = clib_host_to_net_u16 (portnum); \
2175               *address_indexp = i; \
2176               return 0; \
2177             } \
2178         } \
2179       break;
2180       foreach_snat_protocol
2181 #undef _
2182     default:
2183       clib_warning("unknown protocol");
2184       return 1;
2185     }
2186
2187 exhausted:
2188   /* Totally out of translations to use... */
2189   snat_ipfix_logging_addresses_exhausted(0);
2190   return 1;
2191 }
2192
2193 void
2194 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2195 {
2196   dpo_id_t dpo_v4 = DPO_INVALID;
2197   fib_prefix_t pfx = {
2198     .fp_proto = FIB_PROTOCOL_IP4,
2199     .fp_len = 32,
2200     .fp_addr.ip4.as_u32 = addr.as_u32,
2201   };
2202
2203   if (is_add)
2204     {
2205       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2206       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2207                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2208       dpo_reset (&dpo_v4);
2209     }
2210   else
2211     {
2212       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2213     }
2214 }
2215
2216 uword
2217 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2218 {
2219   u32 *r = va_arg (*args, u32 *);
2220
2221   if (0);
2222 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2223   foreach_snat_protocol
2224 #undef _
2225   else
2226     return 0;
2227   return 1;
2228 }
2229
2230 u8 *
2231 format_snat_protocol (u8 * s, va_list * args)
2232 {
2233   u32 i = va_arg (*args, u32);
2234   u8 *t = 0;
2235
2236   switch (i)
2237     {
2238 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2239       foreach_snat_protocol
2240 #undef _
2241     default:
2242       s = format (s, "unknown");
2243       return s;
2244     }
2245   s = format (s, "%s", t);
2246   return s;
2247 }
2248
2249 static u32
2250 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2251 {
2252   snat_main_t *sm = &snat_main;
2253   u32 next_worker_index = 0;
2254   u32 hash;
2255
2256   next_worker_index = sm->first_worker_index;
2257   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2258          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2259
2260   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2261     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2262   else
2263     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2264
2265   return next_worker_index;
2266 }
2267
2268 static u32
2269 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2270 {
2271   snat_main_t *sm = &snat_main;
2272   udp_header_t *udp;
2273   u16 port;
2274   snat_session_key_t m_key;
2275   clib_bihash_kv_8_8_t kv, value;
2276   snat_static_mapping_t *m;
2277   nat_ed_ses_key_t key;
2278   clib_bihash_kv_16_8_t s_kv, s_value;
2279   snat_main_per_thread_data_t *tsm;
2280   snat_session_t *s;
2281   int i;
2282   u32 proto;
2283   u32 next_worker_index = 0;
2284
2285   /* first try static mappings without port */
2286   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2287     {
2288       m_key.addr = ip0->dst_address;
2289       m_key.port = 0;
2290       m_key.protocol = 0;
2291       m_key.fib_index = rx_fib_index0;
2292       kv.key = m_key.as_u64;
2293       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2294         {
2295           m = pool_elt_at_index (sm->static_mappings, value.value);
2296           return m->worker_index;
2297         }
2298     }
2299
2300   proto = ip_proto_to_snat_proto (ip0->protocol);
2301   udp = ip4_next_header (ip0);
2302   port = udp->dst_port;
2303
2304   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2305     {
2306       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2307         return vlib_get_thread_index ();
2308
2309       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2310         {
2311           nat_reass_ip4_t *reass;
2312
2313           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2314                                       ip0->fragment_id, ip0->protocol);
2315
2316           if (reass && (reass->thread_index != (u32) ~ 0))
2317             return reass->thread_index;
2318           else
2319             return vlib_get_thread_index ();
2320         }
2321     }
2322
2323   /* unknown protocol */
2324   if (PREDICT_FALSE (proto == ~0))
2325     {
2326       key.l_addr = ip0->dst_address;
2327       key.r_addr = ip0->src_address;
2328       key.fib_index = rx_fib_index0;
2329       key.proto = ip0->protocol;
2330       key.r_port = 0;
2331       key.l_port = 0;
2332       s_kv.key[0] = key.as_u64[0];
2333       s_kv.key[1] = key.as_u64[1];
2334
2335       if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2336         {
2337           for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2338             {
2339               tsm = vec_elt_at_index (sm->per_thread_data, i);
2340               if (!pool_is_free_index(tsm->sessions, s_value.value))
2341                 {
2342                   s = pool_elt_at_index (tsm->sessions, s_value.value);
2343                   if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2344                       s->out2in.port == ip0->protocol &&
2345                       snat_is_unk_proto_session (s))
2346                     return i;
2347                 }
2348             }
2349          }
2350
2351       /* if no session use current thread */
2352       return vlib_get_thread_index ();
2353     }
2354
2355   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2356     {
2357       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2358       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2359       if (!icmp_is_error_message (icmp))
2360         port = echo->identifier;
2361       else
2362         {
2363           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2364           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2365           void *l4_header = ip4_next_header (inner_ip);
2366           switch (proto)
2367             {
2368             case SNAT_PROTOCOL_ICMP:
2369               icmp = (icmp46_header_t*)l4_header;
2370               echo = (icmp_echo_header_t *)(icmp + 1);
2371               port = echo->identifier;
2372               break;
2373             case SNAT_PROTOCOL_UDP:
2374             case SNAT_PROTOCOL_TCP:
2375               port = ((tcp_udp_header_t*)l4_header)->src_port;
2376               break;
2377             default:
2378               return vlib_get_thread_index ();
2379             }
2380         }
2381     }
2382
2383   /* try static mappings with port */
2384   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2385     {
2386       m_key.addr = ip0->dst_address;
2387       m_key.port = clib_net_to_host_u16 (port);
2388       m_key.protocol = proto;
2389       m_key.fib_index = rx_fib_index0;
2390       kv.key = m_key.as_u64;
2391       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2392         {
2393           m = pool_elt_at_index (sm->static_mappings, value.value);
2394           return m->worker_index;
2395         }
2396     }
2397
2398   /* worker by outside port */
2399   next_worker_index = sm->first_worker_index;
2400   next_worker_index +=
2401     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2402   return next_worker_index;
2403 }
2404
2405 static clib_error_t *
2406 snat_config (vlib_main_t * vm, unformat_input_t * input)
2407 {
2408   snat_main_t * sm = &snat_main;
2409   u32 translation_buckets = 1024;
2410   u32 translation_memory_size = 128<<20;
2411   u32 user_buckets = 128;
2412   u32 user_memory_size = 64<<20;
2413   u32 max_translations_per_user = 100;
2414   u32 outside_vrf_id = 0;
2415   u32 inside_vrf_id = 0;
2416   u32 static_mapping_buckets = 1024;
2417   u32 static_mapping_memory_size = 64<<20;
2418   u32 nat64_bib_buckets = 1024;
2419   u32 nat64_bib_memory_size = 128 << 20;
2420   u32 nat64_st_buckets = 2048;
2421   u32 nat64_st_memory_size = 256 << 20;
2422   u8 static_mapping_only = 0;
2423   u8 static_mapping_connection_tracking = 0;
2424   snat_main_per_thread_data_t *tsm;
2425   dslite_main_t * dm = &dslite_main;
2426
2427   sm->deterministic = 0;
2428   sm->out2in_dpo = 0;
2429
2430   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2431     {
2432       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2433         ;
2434       else if (unformat (input, "translation hash memory %d",
2435                          &translation_memory_size));
2436       else if (unformat (input, "user hash buckets %d", &user_buckets))
2437         ;
2438       else if (unformat (input, "user hash memory %d",
2439                          &user_memory_size))
2440         ;
2441       else if (unformat (input, "max translations per user %d",
2442                          &max_translations_per_user))
2443         ;
2444       else if (unformat (input, "outside VRF id %d",
2445                          &outside_vrf_id))
2446         ;
2447       else if (unformat (input, "inside VRF id %d",
2448                          &inside_vrf_id))
2449         ;
2450       else if (unformat (input, "static mapping only"))
2451         {
2452           static_mapping_only = 1;
2453           if (unformat (input, "connection tracking"))
2454             static_mapping_connection_tracking = 1;
2455         }
2456       else if (unformat (input, "deterministic"))
2457         sm->deterministic = 1;
2458       else if (unformat (input, "nat64 bib hash buckets %d",
2459                          &nat64_bib_buckets))
2460         ;
2461       else if (unformat (input, "nat64 bib hash memory %d",
2462                          &nat64_bib_memory_size))
2463         ;
2464       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2465         ;
2466       else if (unformat (input, "nat64 st hash memory %d",
2467                          &nat64_st_memory_size))
2468         ;
2469       else if (unformat (input, "out2in dpo"))
2470         sm->out2in_dpo = 1;
2471       else if (unformat (input, "dslite ce"))
2472         dslite_set_ce(dm, 1);
2473       else
2474         return clib_error_return (0, "unknown input '%U'",
2475                                   format_unformat_error, input);
2476     }
2477
2478   /* for show commands, etc. */
2479   sm->translation_buckets = translation_buckets;
2480   sm->translation_memory_size = translation_memory_size;
2481   /* do not exceed load factor 10 */
2482   sm->max_translations = 10 * translation_buckets;
2483   sm->user_buckets = user_buckets;
2484   sm->user_memory_size = user_memory_size;
2485   sm->max_translations_per_user = max_translations_per_user;
2486   sm->outside_vrf_id = outside_vrf_id;
2487   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2488                                                              outside_vrf_id,
2489                                                              FIB_SOURCE_PLUGIN_HI);
2490   sm->inside_vrf_id = inside_vrf_id;
2491   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2492                                                             inside_vrf_id,
2493                                                             FIB_SOURCE_PLUGIN_HI);
2494   sm->static_mapping_only = static_mapping_only;
2495   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2496
2497   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2498                  nat64_st_memory_size);
2499
2500   if (sm->deterministic)
2501     {
2502       sm->in2out_node_index = snat_det_in2out_node.index;
2503       sm->in2out_output_node_index = ~0;
2504       sm->out2in_node_index = snat_det_out2in_node.index;
2505       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2506       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2507     }
2508   else
2509     {
2510       sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2511       sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2512       sm->in2out_node_index = snat_in2out_node.index;
2513       sm->in2out_output_node_index = snat_in2out_output_node.index;
2514       sm->out2in_node_index = snat_out2in_node.index;
2515       if (!static_mapping_only ||
2516           (static_mapping_only && static_mapping_connection_tracking))
2517         {
2518           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2519           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2520
2521           vec_foreach (tsm, sm->per_thread_data)
2522             {
2523               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2524                                     translation_memory_size);
2525
2526               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2527                                     translation_memory_size);
2528
2529               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2530                                     user_memory_size);
2531             }
2532
2533           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2534                                  translation_buckets, translation_memory_size);
2535
2536           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2537                                  translation_buckets, translation_memory_size);
2538         }
2539       else
2540         {
2541           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2542           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2543         }
2544       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2545                             "static_mapping_by_local", static_mapping_buckets,
2546                             static_mapping_memory_size);
2547
2548       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2549                             "static_mapping_by_external", static_mapping_buckets,
2550                             static_mapping_memory_size);
2551     }
2552
2553   return 0;
2554 }
2555
2556 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2557
2558 u8 * format_snat_session_state (u8 * s, va_list * args)
2559 {
2560   u32 i = va_arg (*args, u32);
2561   u8 *t = 0;
2562
2563   switch (i)
2564     {
2565 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2566     foreach_snat_session_state
2567 #undef _
2568     default:
2569       t = format (t, "unknown");
2570     }
2571   s = format (s, "%s", t);
2572   return s;
2573 }
2574
2575 u8 * format_snat_key (u8 * s, va_list * args)
2576 {
2577   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2578
2579   s = format (s, "%U proto %U port %d fib %d",
2580               format_ip4_address, &key->addr,
2581               format_snat_protocol, key->protocol,
2582               clib_net_to_host_u16 (key->port), key->fib_index);
2583   return s;
2584 }
2585
2586 u8 * format_snat_session (u8 * s, va_list * args)
2587 {
2588   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2589   snat_session_t * sess = va_arg (*args, snat_session_t *);
2590
2591   if (snat_is_unk_proto_session (sess))
2592     {
2593       s = format (s, "  i2o %U proto %u fib %u\n",
2594                   format_ip4_address, &sess->in2out.addr,
2595                   clib_net_to_host_u16 (sess->in2out.port),
2596                   sess->in2out.fib_index);
2597       s = format (s, "    o2i %U proto %u fib %u\n",
2598                   format_ip4_address, &sess->out2in.addr,
2599                   clib_net_to_host_u16 (sess->out2in.port),
2600                   sess->out2in.fib_index);
2601     }
2602   else
2603     {
2604       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2605       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2606     }
2607   if (is_twice_nat_session (sess))
2608     {
2609       s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
2610                   format_ip4_address, &sess->ext_host_addr,
2611                   clib_net_to_host_u16 (sess->ext_host_port),
2612                   format_ip4_address, &sess->ext_host_nat_addr,
2613                   clib_net_to_host_u16 (sess->ext_host_nat_port));
2614     }
2615   else
2616     {
2617       if (sess->ext_host_addr.as_u32)
2618           s = format (s, "       external host %U\n",
2619                       format_ip4_address, &sess->ext_host_addr);
2620     }
2621   s = format (s, "       last heard %.2f\n", sess->last_heard);
2622   s = format (s, "       total pkts %d, total bytes %lld\n",
2623               sess->total_pkts, sess->total_bytes);
2624   if (snat_is_session_static (sess))
2625     s = format (s, "       static translation\n");
2626   else
2627     s = format (s, "       dynamic translation\n");
2628   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2629     s = format (s, "       load-balancing\n");
2630   if (is_twice_nat_session (sess))
2631     s = format (s, "       twice-nat\n");
2632
2633   return s;
2634 }
2635
2636 u8 * format_snat_user (u8 * s, va_list * args)
2637 {
2638   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2639   snat_user_t * u = va_arg (*args, snat_user_t *);
2640   int verbose = va_arg (*args, int);
2641   dlist_elt_t * head, * elt;
2642   u32 elt_index, head_index;
2643   u32 session_index;
2644   snat_session_t * sess;
2645
2646   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2647               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2648
2649   if (verbose == 0)
2650     return s;
2651
2652   if (u->nsessions || u->nstaticsessions)
2653     {
2654       head_index = u->sessions_per_user_list_head_index;
2655       head = pool_elt_at_index (sm->list_pool, head_index);
2656
2657       elt_index = head->next;
2658       elt = pool_elt_at_index (sm->list_pool, elt_index);
2659       session_index = elt->value;
2660
2661       while (session_index != ~0)
2662         {
2663           sess = pool_elt_at_index (sm->sessions, session_index);
2664
2665           s = format (s, "  %U\n", format_snat_session, sm, sess);
2666
2667           elt_index = elt->next;
2668           elt = pool_elt_at_index (sm->list_pool, elt_index);
2669           session_index = elt->value;
2670         }
2671     }
2672
2673   return s;
2674 }
2675
2676 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2677 {
2678   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2679   nat44_lb_addr_port_t *local;
2680
2681   if (m->addr_only)
2682       s = format (s, "local %U external %U vrf %d %s",
2683                   format_ip4_address, &m->local_addr,
2684                   format_ip4_address, &m->external_addr,
2685                   m->vrf_id, m->twice_nat ? "twice-nat" : "");
2686   else
2687    {
2688       if (vec_len (m->locals))
2689         {
2690           s = format (s, "%U vrf %d external %U:%d %s %s",
2691                       format_snat_protocol, m->proto,
2692                       m->vrf_id,
2693                       format_ip4_address, &m->external_addr, m->external_port,
2694                       m->twice_nat ? "twice-nat" : "",
2695                       m->out2in_only ? "out2in-only" : "");
2696           vec_foreach (local, m->locals)
2697             s = format (s, "\n  local %U:%d probability %d\%",
2698                         format_ip4_address, &local->addr, local->port,
2699                         local->probability);
2700         }
2701       else
2702         s = format (s, "%U local %U:%d external %U:%d vrf %d %s %s",
2703                     format_snat_protocol, m->proto,
2704                     format_ip4_address, &m->local_addr, m->local_port,
2705                     format_ip4_address, &m->external_addr, m->external_port,
2706                     m->vrf_id, m->twice_nat ? "twice-nat" : "",
2707                     m->out2in_only ? "out2in-only" : "");
2708    }
2709   return s;
2710 }
2711
2712 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2713 {
2714   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2715   vnet_main_t *vnm = vnet_get_main();
2716
2717   if (m->addr_only)
2718       s = format (s, "local %U external %U vrf %d",
2719                   format_ip4_address, &m->l_addr,
2720                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
2721                   m->vrf_id);
2722   else
2723       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2724                   format_snat_protocol, m->proto,
2725                   format_ip4_address, &m->l_addr, m->l_port,
2726                   format_vnet_sw_if_index_name, vnm, m->sw_if_index,
2727                   m->e_port, m->vrf_id);
2728
2729   return s;
2730 }
2731
2732 u8 * format_det_map_ses (u8 * s, va_list * args)
2733 {
2734   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2735   ip4_address_t in_addr, out_addr;
2736   u32 in_offset, out_offset;
2737   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2738   u32 * i = va_arg (*args, u32 *);
2739
2740   u32 user_index = *i / SNAT_DET_SES_PER_USER;
2741   in_addr.as_u32 = clib_host_to_net_u32 (
2742     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2743   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2744     clib_net_to_host_u32(det_map->in_addr.as_u32);
2745   out_offset = in_offset / det_map->sharing_ratio;
2746   out_addr.as_u32 = clib_host_to_net_u32(
2747     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2748   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2749               format_ip4_address, &in_addr,
2750               clib_net_to_host_u16 (ses->in_port),
2751               format_ip4_address, &out_addr,
2752               clib_net_to_host_u16 (ses->out.out_port),
2753               format_ip4_address, &ses->out.ext_host_addr,
2754               clib_net_to_host_u16 (ses->out.ext_host_port),
2755               format_snat_session_state, ses->state,
2756               ses->expire);
2757
2758   return s;
2759 }
2760
2761 static void
2762 nat_ip4_add_del_addr_only_sm_cb (ip4_main_t * im,
2763                                  uword opaque,
2764                                  u32 sw_if_index,
2765                                  ip4_address_t * address,
2766                                  u32 address_length,
2767                                  u32 if_address_index,
2768                                  u32 is_delete)
2769 {
2770   snat_main_t *sm = &snat_main;
2771   snat_static_map_resolve_t *rp;
2772   snat_static_mapping_t *m;
2773   snat_session_key_t m_key;
2774   clib_bihash_kv_8_8_t kv, value;
2775   int i, rv;
2776   ip4_address_t l_addr;
2777
2778   for (i = 0; i < vec_len (sm->to_resolve); i++)
2779     {
2780       rp = sm->to_resolve + i;
2781       if (rp->addr_only == 0)
2782         continue;
2783       if (rp->sw_if_index == sw_if_index)
2784         goto match;
2785     }
2786
2787   return;
2788
2789 match:
2790   m_key.addr.as_u32 = address->as_u32;
2791   m_key.port = rp->addr_only ? 0 : rp->e_port;
2792   m_key.protocol = rp->addr_only ? 0 : rp->proto;
2793   m_key.fib_index = sm->outside_fib_index;
2794   kv.key = m_key.as_u64;
2795   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2796     m = 0;
2797   else
2798     m = pool_elt_at_index (sm->static_mappings, value.value);
2799
2800   if (!is_delete)
2801     {
2802       /* Don't trip over lease renewal, static config */
2803       if (m)
2804         return;
2805     }
2806   else
2807     {
2808       if (!m)
2809         return;
2810     }
2811
2812   /* Indetity mapping? */
2813   if (rp->l_addr.as_u32 == 0)
2814     l_addr.as_u32 = address[0].as_u32;
2815   else
2816     l_addr.as_u32 = rp->l_addr.as_u32;
2817   /* Add the static mapping */
2818   rv = snat_add_static_mapping (l_addr,
2819                                 address[0],
2820                                 rp->l_port,
2821                                 rp->e_port,
2822                                 rp->vrf_id,
2823                                 rp->addr_only,
2824                                 ~0 /* sw_if_index */,
2825                                 rp->proto,
2826                                 !is_delete,
2827                                 0, 0, rp->tag);
2828   if (rv)
2829     clib_warning ("snat_add_static_mapping returned %d", rv);
2830 }
2831
2832 static void
2833 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2834                                        uword opaque,
2835                                        u32 sw_if_index,
2836                                        ip4_address_t * address,
2837                                        u32 address_length,
2838                                        u32 if_address_index,
2839                                        u32 is_delete)
2840 {
2841   snat_main_t *sm = &snat_main;
2842   snat_static_map_resolve_t *rp;
2843   ip4_address_t l_addr;
2844   int i, j;
2845   int rv;
2846   u8 twice_nat = 0;
2847   snat_address_t *addresses = sm->addresses;
2848
2849   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2850     {
2851       if (sw_if_index == sm->auto_add_sw_if_indices[i])
2852           goto match;
2853     }
2854
2855   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
2856     {
2857       twice_nat = 1;
2858       addresses = sm->twice_nat_addresses;
2859       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
2860           goto match;
2861     }
2862
2863   return;
2864
2865 match:
2866   if (!is_delete)
2867     {
2868       /* Don't trip over lease renewal, static config */
2869       for (j = 0; j < vec_len(addresses); j++)
2870         if (addresses[j].addr.as_u32 == address->as_u32)
2871           return;
2872
2873       snat_add_address (sm, address, ~0, twice_nat);
2874       /* Scan static map resolution vector */
2875       for (j = 0; j < vec_len (sm->to_resolve); j++)
2876         {
2877           rp = sm->to_resolve + j;
2878           if (rp->addr_only)
2879             continue;
2880           /* On this interface? */
2881           if (rp->sw_if_index == sw_if_index)
2882             {
2883               /* Indetity mapping? */
2884               if (rp->l_addr.as_u32 == 0)
2885                 l_addr.as_u32 = address[0].as_u32;
2886               else
2887                 l_addr.as_u32 = rp->l_addr.as_u32;
2888               /* Add the static mapping */
2889               rv = snat_add_static_mapping (l_addr,
2890                                             address[0],
2891                                             rp->l_port,
2892                                             rp->e_port,
2893                                             rp->vrf_id,
2894                                             rp->addr_only,
2895                                             ~0 /* sw_if_index */,
2896                                             rp->proto,
2897                                             rp->is_add,
2898                                             0, 0, rp->tag);
2899               if (rv)
2900                 clib_warning ("snat_add_static_mapping returned %d",
2901                               rv);
2902             }
2903         }
2904       return;
2905     }
2906   else
2907     {
2908       (void) snat_del_address(sm, address[0], 1, twice_nat);
2909       return;
2910     }
2911 }
2912
2913
2914 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
2915                                 u8 twice_nat)
2916 {
2917   ip4_main_t * ip4_main = sm->ip4_main;
2918   ip4_address_t * first_int_addr;
2919   snat_static_map_resolve_t *rp;
2920   u32 *indices_to_delete = 0;
2921   int i, j;
2922   u32 *auto_add_sw_if_indices =
2923     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
2924
2925   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2926                                                 0 /* just want the address*/);
2927
2928   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
2929     {
2930       if (auto_add_sw_if_indices[i] == sw_if_index)
2931         {
2932           if (is_del)
2933             {
2934               /* if have address remove it */
2935               if (first_int_addr)
2936                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
2937               else
2938                 {
2939                   for (j = 0; j < vec_len (sm->to_resolve); j++)
2940                     {
2941                       rp = sm->to_resolve + j;
2942                       if (rp->sw_if_index == sw_if_index)
2943                         vec_add1 (indices_to_delete, j);
2944                     }
2945                   if (vec_len(indices_to_delete))
2946                     {
2947                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2948                         vec_del1(sm->to_resolve, j);
2949                       vec_free(indices_to_delete);
2950                     }
2951                 }
2952               if (twice_nat)
2953                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
2954               else
2955                 vec_del1(sm->auto_add_sw_if_indices, i);
2956             }
2957           else
2958             return VNET_API_ERROR_VALUE_EXIST;
2959
2960           return 0;
2961         }
2962     }
2963
2964   if (is_del)
2965     return VNET_API_ERROR_NO_SUCH_ENTRY;
2966
2967   /* add to the auto-address list */
2968   if (twice_nat)
2969     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
2970   else
2971     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2972
2973   /* If the address is already bound - or static - add it now */
2974   if (first_int_addr)
2975       snat_add_address (sm, first_int_addr, ~0, twice_nat);
2976
2977   return 0;
2978 }
2979
2980 int
2981 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
2982                    snat_protocol_t proto, u32 vrf_id, int is_in)
2983 {
2984   snat_main_per_thread_data_t *tsm;
2985   clib_bihash_kv_8_8_t kv, value;
2986   ip4_header_t ip;
2987   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
2988   snat_session_key_t key;
2989   snat_session_t *s;
2990   clib_bihash_8_8_t *t;
2991   snat_user_key_t u_key;
2992   snat_user_t *u;
2993
2994   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
2995   if (sm->num_workers > 1)
2996     tsm =
2997       vec_elt_at_index (sm->per_thread_data,
2998                         sm->worker_in2out_cb (&ip, fib_index));
2999   else
3000     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3001
3002   key.addr.as_u32 = addr->as_u32;
3003   key.port = clib_host_to_net_u16 (port);
3004   key.protocol = proto;
3005   key.fib_index = fib_index;
3006   kv.key = key.as_u64;
3007   t = is_in ? &tsm->in2out : &tsm->out2in;
3008   if (!clib_bihash_search_8_8 (t, &kv, &value))
3009     {
3010       s = pool_elt_at_index (tsm->sessions, value.value);
3011       kv.key = s->in2out.as_u64;
3012       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3013       kv.key = s->out2in.as_u64;
3014       clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3015       u_key.addr = s->in2out.addr;
3016       u_key.fib_index = s->in2out.fib_index;
3017       kv.key = u_key.as_u64;
3018       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3019         {
3020           u = pool_elt_at_index (tsm->users, value.value);
3021           u->nsessions--;
3022         }
3023       clib_dlist_remove (tsm->list_pool, s->per_user_index);
3024       pool_put (tsm->sessions, s);
3025       return 0;
3026     }
3027
3028   return VNET_API_ERROR_NO_SUCH_ENTRY;
3029 }
3030
3031 void
3032 nat_set_alloc_addr_and_port_mape (u16 psid, u16 psid_offset, u16 psid_length)
3033 {
3034   snat_main_t *sm = &snat_main;
3035
3036   sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3037   sm->psid = psid;
3038   sm->psid_offset = psid_offset;
3039   sm->psid_length = psid_length;
3040 }
3041
3042 void
3043 nat_set_alloc_addr_and_port_default (void)
3044 {
3045   snat_main_t *sm = &snat_main;
3046
3047   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3048 }
3049