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