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