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