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