NAT44: asymmetrical load balancing static mapping rule (VPP-1132)
[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/dslite.h>
28 #include <nat/nat_reass.h>
29 #include <vnet/fib/fib_table.h>
30 #include <vnet/fib/ip4_fib.h>
31
32 #include <vpp/app/version.h>
33
34 snat_main_t snat_main;
35
36
37 /* Hook up input features */
38 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
39   .arc_name = "ip4-unicast",
40   .node_name = "nat44-in2out",
41   .runs_before = VNET_FEATURES ("nat44-out2in"),
42 };
43 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
44   .arc_name = "ip4-unicast",
45   .node_name = "nat44-out2in",
46   .runs_before = VNET_FEATURES ("ip4-lookup"),
47 };
48 VNET_FEATURE_INIT (ip4_nat_classify, static) = {
49   .arc_name = "ip4-unicast",
50   .node_name = "nat44-classify",
51   .runs_before = VNET_FEATURES ("ip4-lookup"),
52 };
53 VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = {
54   .arc_name = "ip4-unicast",
55   .node_name = "nat44-det-in2out",
56   .runs_before = VNET_FEATURES ("nat44-det-out2in"),
57 };
58 VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = {
59   .arc_name = "ip4-unicast",
60   .node_name = "nat44-det-out2in",
61   .runs_before = VNET_FEATURES ("ip4-lookup"),
62 };
63 VNET_FEATURE_INIT (ip4_nat_det_classify, static) = {
64   .arc_name = "ip4-unicast",
65   .node_name = "nat44-det-classify",
66   .runs_before = VNET_FEATURES ("ip4-lookup"),
67 };
68 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
69   .arc_name = "ip4-unicast",
70   .node_name = "nat44-in2out-worker-handoff",
71   .runs_before = VNET_FEATURES ("nat44-out2in-worker-handoff"),
72 };
73 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
74   .arc_name = "ip4-unicast",
75   .node_name = "nat44-out2in-worker-handoff",
76   .runs_before = VNET_FEATURES ("ip4-lookup"),
77 };
78 VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = {
79   .arc_name = "ip4-unicast",
80   .node_name = "nat44-handoff-classify",
81   .runs_before = VNET_FEATURES ("ip4-lookup"),
82 };
83 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
84   .arc_name = "ip4-unicast",
85   .node_name = "nat44-in2out-fast",
86   .runs_before = VNET_FEATURES ("nat44-out2in-fast"),
87 };
88 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
89   .arc_name = "ip4-unicast",
90   .node_name = "nat44-out2in-fast",
91   .runs_before = VNET_FEATURES ("ip4-lookup"),
92 };
93 VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = {
94   .arc_name = "ip4-unicast",
95   .node_name = "nat44-hairpin-dst",
96   .runs_before = VNET_FEATURES ("ip4-lookup"),
97 };
98
99 /* Hook up output features */
100 VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = {
101   .arc_name = "ip4-output",
102   .node_name = "nat44-in2out-output",
103   .runs_before = VNET_FEATURES ("interface-output"),
104 };
105 VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = {
106   .arc_name = "ip4-output",
107   .node_name = "nat44-in2out-output-worker-handoff",
108   .runs_before = VNET_FEATURES ("interface-output"),
109 };
110 VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = {
111   .arc_name = "ip4-output",
112   .node_name = "nat44-hairpin-src",
113   .runs_before = VNET_FEATURES ("interface-output"),
114 };
115
116 /* Hook up ip4-local features */
117 VNET_FEATURE_INIT (ip4_nat_hairpinning, static) =
118 {
119   .arc_name = "ip4-local",
120   .node_name = "nat44-hairpinning",
121   .runs_before = VNET_FEATURES("ip4-local-end-of-arc"),
122 };
123
124
125 /* *INDENT-OFF* */
126 VLIB_PLUGIN_REGISTER () = {
127     .version = VPP_BUILD_VER,
128     .description = "Network Address Translation",
129 };
130 /* *INDENT-ON* */
131
132 vlib_node_registration_t nat44_classify_node;
133 vlib_node_registration_t nat44_det_classify_node;
134 vlib_node_registration_t nat44_handoff_classify_node;
135
136 typedef enum {
137   NAT44_CLASSIFY_NEXT_IN2OUT,
138   NAT44_CLASSIFY_NEXT_OUT2IN,
139   NAT44_CLASSIFY_N_NEXT,
140 } nat44_classify_next_t;
141
142 void
143 nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index)
144 {
145   snat_session_key_t key;
146   clib_bihash_kv_8_8_t kv;
147   nat_ed_ses_key_t ed_key;
148   clib_bihash_kv_16_8_t ed_kv;
149   int i;
150   snat_address_t *a;
151   snat_main_per_thread_data_t *tsm =
152     vec_elt_at_index (sm->per_thread_data, thread_index);
153
154   /* Endpoint dependent session lookup tables */
155   if (is_ed_session (s))
156     {
157       ed_key.l_addr = s->out2in.addr;
158       ed_key.r_addr = s->ext_host_addr;
159       ed_key.fib_index = s->out2in.fib_index;
160       if (snat_is_unk_proto_session (s))
161         {
162           ed_key.proto = s->in2out.port;
163           ed_key.r_port = 0;
164           ed_key.l_port = 0;
165         }
166       else
167         {
168           ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol);
169           ed_key.l_port = s->out2in.port;
170           ed_key.r_port = s->ext_host_port;
171         }
172       ed_kv.key[0] = ed_key.as_u64[0];
173       ed_kv.key[1] = ed_key.as_u64[1];
174       if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0))
175         clib_warning ("out2in_ed key del failed");
176
177       ed_key.l_addr = s->in2out.addr;
178       ed_key.fib_index = s->in2out.fib_index;
179       if (!snat_is_unk_proto_session (s))
180         ed_key.l_port = s->in2out.port;
181       if (is_twice_nat_session (s))
182         {
183           ed_key.r_addr = s->ext_host_nat_addr;
184           ed_key.r_port = s->ext_host_nat_port;
185         }
186       ed_kv.key[0] = ed_key.as_u64[0];
187       ed_kv.key[1] = ed_key.as_u64[1];
188       if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0))
189         clib_warning ("in2out_ed key del failed");
190     }
191
192   if (snat_is_unk_proto_session (s))
193     return;
194
195   /* log NAT event */
196   snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32,
197                                       s->out2in.addr.as_u32,
198                                       s->in2out.protocol,
199                                       s->in2out.port,
200                                       s->out2in.port,
201                                       s->in2out.fib_index);
202
203   /* Twice NAT address and port for external host */
204   if (is_twice_nat_session (s))
205     {
206       for (i = 0; i < vec_len (sm->twice_nat_addresses); i++)
207         {
208           key.protocol = s->in2out.protocol;
209           key.port = s->ext_host_nat_port;
210           a = sm->twice_nat_addresses + i;
211           if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32)
212             {
213               snat_free_outside_address_and_port (sm->twice_nat_addresses,
214                                                   thread_index, &key, i);
215               break;
216             }
217         }
218     }
219
220   if (is_ed_session (s))
221     return;
222
223   /* Session lookup tables */
224   kv.key = s->in2out.as_u64;
225   if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0))
226     clib_warning ("in2out key del failed");
227   kv.key = s->out2in.as_u64;
228   if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0))
229     clib_warning ("out2in key del failed");
230
231   if (snat_is_session_static (s))
232     return;
233
234   if (s->outside_address_index != ~0)
235     snat_free_outside_address_and_port (sm->addresses, thread_index,
236                                         &s->out2in, s->outside_address_index);
237 }
238
239 snat_user_t *
240 nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, u32 fib_index,
241                         u32 thread_index)
242 {
243   snat_user_t *u = 0;
244   snat_user_key_t user_key;
245   clib_bihash_kv_8_8_t kv, value;
246   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
247   dlist_elt_t * per_user_list_head_elt;
248
249   user_key.addr.as_u32 = addr->as_u32;
250   user_key.fib_index = fib_index;
251   kv.key = user_key.as_u64;
252
253   /* Ever heard of the "user" = src ip4 address before? */
254   if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
255     {
256       /* no, make a new one */
257       pool_get (tsm->users, u);
258       memset (u, 0, sizeof (*u));
259       u->addr.as_u32 = addr->as_u32;
260       u->fib_index = fib_index;
261
262       pool_get (tsm->list_pool, per_user_list_head_elt);
263
264       u->sessions_per_user_list_head_index = per_user_list_head_elt -
265         tsm->list_pool;
266
267       clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index);
268
269       kv.value = u - tsm->users;
270
271       /* add user */
272       if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1))
273         clib_warning ("user_hash keay add failed");
274     }
275   else
276     {
277       u = pool_elt_at_index (tsm->users, value.value);
278     }
279
280   return u;
281 }
282
283 snat_session_t *
284 nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index)
285 {
286   snat_session_t *s;
287   snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
288   u32 oldest_per_user_translation_list_index, session_index;
289   dlist_elt_t * oldest_per_user_translation_list_elt;
290   dlist_elt_t * per_user_translation_list_elt;
291
292   /* Over quota? Recycle the least recently used translation */
293   if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user)
294     {
295       oldest_per_user_translation_list_index =
296         clib_dlist_remove_head (tsm->list_pool,
297                                 u->sessions_per_user_list_head_index);
298
299       ASSERT (oldest_per_user_translation_list_index != ~0);
300
301       /* Add it back to the end of the LRU list */
302       clib_dlist_addtail (tsm->list_pool,
303                           u->sessions_per_user_list_head_index,
304                           oldest_per_user_translation_list_index);
305       /* Get the list element */
306       oldest_per_user_translation_list_elt =
307         pool_elt_at_index (tsm->list_pool,
308                            oldest_per_user_translation_list_index);
309
310       /* Get the session index from the list element */
311       session_index = oldest_per_user_translation_list_elt->value;
312
313       /* Get the session */
314       s = pool_elt_at_index (tsm->sessions, session_index);
315       nat_free_session_data (sm, s, thread_index);
316       s->outside_address_index = ~0;
317       s->flags = 0;
318       s->total_bytes = 0;
319       s->total_pkts = 0;
320     }
321   else
322     {
323       pool_get (tsm->sessions, s);
324       memset (s, 0, sizeof (*s));
325       s->outside_address_index = ~0;
326
327       /* Create list elts */
328       pool_get (tsm->list_pool, per_user_translation_list_elt);
329       clib_dlist_init (tsm->list_pool,
330                        per_user_translation_list_elt - tsm->list_pool);
331
332       per_user_translation_list_elt->value = s - tsm->sessions;
333       s->per_user_index = per_user_translation_list_elt - tsm->list_pool;
334       s->per_user_list_head_index = u->sessions_per_user_list_head_index;
335
336       clib_dlist_addtail (tsm->list_pool,
337                           s->per_user_list_head_index,
338                           per_user_translation_list_elt - tsm->list_pool);
339     }
340
341   return s;
342 }
343
344 static inline uword
345 nat44_classify_node_fn_inline (vlib_main_t * vm,
346                                vlib_node_runtime_t * node,
347                                vlib_frame_t * frame)
348 {
349   u32 n_left_from, * from, * to_next;
350   nat44_classify_next_t next_index;
351   snat_main_t *sm = &snat_main;
352
353   from = vlib_frame_vector_args (frame);
354   n_left_from = frame->n_vectors;
355   next_index = node->cached_next_index;
356
357   while (n_left_from > 0)
358     {
359       u32 n_left_to_next;
360
361       vlib_get_next_frame (vm, node, next_index,
362                            to_next, n_left_to_next);
363
364       while (n_left_from > 0 && n_left_to_next > 0)
365         {
366           u32 bi0;
367           vlib_buffer_t *b0;
368           u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT;
369           ip4_header_t *ip0;
370           snat_address_t *ap;
371           snat_session_key_t m_key0;
372           clib_bihash_kv_8_8_t kv0, value0;
373
374           /* speculatively enqueue b0 to the current next frame */
375           bi0 = from[0];
376           to_next[0] = bi0;
377           from += 1;
378           to_next += 1;
379           n_left_from -= 1;
380           n_left_to_next -= 1;
381
382           b0 = vlib_get_buffer (vm, bi0);
383           ip0 = vlib_buffer_get_current (b0);
384
385           vec_foreach (ap, sm->addresses)
386             {
387               if (ip0->dst_address.as_u32 == ap->addr.as_u32)
388                 {
389                   next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
390                   break;
391                 }
392             }
393
394           if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
395             {
396               m_key0.addr = ip0->dst_address;
397               m_key0.port = 0;
398               m_key0.protocol = 0;
399               m_key0.fib_index = sm->outside_fib_index;
400               kv0.key = m_key0.as_u64;
401               if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0))
402                 {
403                   next0 = NAT44_CLASSIFY_NEXT_OUT2IN;
404                 }
405             }
406           /* verify speculative enqueue, maybe switch current next frame */
407           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
408                                            to_next, n_left_to_next,
409                                            bi0, next0);
410         }
411
412       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
413     }
414
415   return frame->n_vectors;
416 }
417
418 static uword
419 nat44_classify_node_fn (vlib_main_t * vm,
420                         vlib_node_runtime_t * node,
421                         vlib_frame_t * frame)
422 {
423   return nat44_classify_node_fn_inline (vm, node, frame);
424 };
425
426 VLIB_REGISTER_NODE (nat44_classify_node) = {
427   .function = nat44_classify_node_fn,
428   .name = "nat44-classify",
429   .vector_size = sizeof (u32),
430   .type = VLIB_NODE_TYPE_INTERNAL,
431   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
432   .next_nodes = {
433     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out",
434     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in",
435   },
436 };
437
438 VLIB_NODE_FUNCTION_MULTIARCH (nat44_classify_node,
439                               nat44_classify_node_fn);
440
441 static uword
442 nat44_det_classify_node_fn (vlib_main_t * vm,
443                             vlib_node_runtime_t * node,
444                             vlib_frame_t * frame)
445 {
446   return nat44_classify_node_fn_inline (vm, node, frame);
447 };
448
449 VLIB_REGISTER_NODE (nat44_det_classify_node) = {
450   .function = nat44_det_classify_node_fn,
451   .name = "nat44-det-classify",
452   .vector_size = sizeof (u32),
453   .type = VLIB_NODE_TYPE_INTERNAL,
454   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
455   .next_nodes = {
456     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out",
457     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in",
458   },
459 };
460
461 VLIB_NODE_FUNCTION_MULTIARCH (nat44_det_classify_node,
462                               nat44_det_classify_node_fn);
463
464 static uword
465 nat44_handoff_classify_node_fn (vlib_main_t * vm,
466                                 vlib_node_runtime_t * node,
467                                 vlib_frame_t * frame)
468 {
469   return nat44_classify_node_fn_inline (vm, node, frame);
470 };
471
472 VLIB_REGISTER_NODE (nat44_handoff_classify_node) = {
473   .function = nat44_handoff_classify_node_fn,
474   .name = "nat44-handoff-classify",
475   .vector_size = sizeof (u32),
476   .type = VLIB_NODE_TYPE_INTERNAL,
477   .n_next_nodes = NAT44_CLASSIFY_N_NEXT,
478   .next_nodes = {
479     [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff",
480     [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff",
481   },
482 };
483
484 VLIB_NODE_FUNCTION_MULTIARCH (nat44_handoff_classify_node,
485                               nat44_handoff_classify_node_fn);
486
487 /**
488  * @brief Add/del NAT address to FIB.
489  *
490  * Add the external NAT address to the FIB as receive entries. This ensures
491  * that VPP will reply to ARP for this address and we don't need to enable
492  * proxy ARP on the outside interface.
493  *
494  * @param addr IPv4 address.
495  * @param plen address prefix length
496  * @param sw_if_index Interface.
497  * @param is_add If 0 delete, otherwise add.
498  */
499 void
500 snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index,
501                           int is_add)
502 {
503   fib_prefix_t prefix = {
504     .fp_len = p_len,
505     .fp_proto = FIB_PROTOCOL_IP4,
506     .fp_addr = {
507         .ip4.as_u32 = addr->as_u32,
508     },
509   };
510   u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index);
511
512   if (is_add)
513     fib_table_entry_update_one_path(fib_index,
514                                     &prefix,
515                                     FIB_SOURCE_PLUGIN_HI,
516                                     (FIB_ENTRY_FLAG_CONNECTED |
517                                      FIB_ENTRY_FLAG_LOCAL |
518                                      FIB_ENTRY_FLAG_EXCLUSIVE),
519                                     DPO_PROTO_IP4,
520                                     NULL,
521                                     sw_if_index,
522                                     ~0,
523                                     1,
524                                     NULL,
525                                     FIB_ROUTE_PATH_FLAG_NONE);
526   else
527     fib_table_entry_delete(fib_index,
528                            &prefix,
529                            FIB_SOURCE_PLUGIN_HI);
530 }
531
532 void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id,
533                        u8 twice_nat)
534 {
535   snat_address_t * ap;
536   snat_interface_t *i;
537   vlib_thread_main_t *tm = vlib_get_thread_main ();
538
539   /* Check if address already exists */
540   vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses)
541     {
542       if (ap->addr.as_u32 == addr->as_u32)
543         return;
544     }
545
546   if (twice_nat)
547     vec_add2 (sm->twice_nat_addresses, ap, 1);
548   else
549     vec_add2 (sm->addresses, ap, 1);
550
551   ap->addr = *addr;
552   if (vrf_id != ~0)
553     ap->fib_index =
554       fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id,
555                                          FIB_SOURCE_PLUGIN_HI);
556   else
557     ap->fib_index = ~0;
558 #define _(N, i, n, s) \
559   clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \
560   ap->busy_##n##_ports = 0; \
561   vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0);
562   foreach_snat_protocol
563 #undef _
564
565   if (twice_nat)
566     return;
567
568   /* Add external address to FIB */
569   pool_foreach (i, sm->interfaces,
570   ({
571     if (nat_interface_is_inside(i) || sm->out2in_dpo)
572       continue;
573
574     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
575     break;
576   }));
577   pool_foreach (i, sm->output_feature_interfaces,
578   ({
579     if (nat_interface_is_inside(i) || sm->out2in_dpo)
580       continue;
581
582     snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1);
583     break;
584   }));
585 }
586
587 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
588                                                    ip4_address_t addr)
589 {
590   snat_static_mapping_t *m;
591   pool_foreach (m, sm->static_mappings,
592   ({
593       if (m->external_addr.as_u32 == addr.as_u32)
594         return 1;
595   }));
596
597   return 0;
598 }
599
600 void increment_v4_address (ip4_address_t * a)
601 {
602   u32 v;
603
604   v = clib_net_to_host_u32(a->as_u32) + 1;
605   a->as_u32 = clib_host_to_net_u32(v);
606 }
607
608 static void
609 snat_add_static_mapping_when_resolved (snat_main_t * sm,
610                                        ip4_address_t l_addr,
611                                        u16 l_port,
612                                        u32 sw_if_index,
613                                        u16 e_port,
614                                        u32 vrf_id,
615                                        snat_protocol_t proto,
616                                        int addr_only,
617                                        int is_add)
618 {
619   snat_static_map_resolve_t *rp;
620
621   vec_add2 (sm->to_resolve, rp, 1);
622   rp->l_addr.as_u32 = l_addr.as_u32;
623   rp->l_port = l_port;
624   rp->sw_if_index = sw_if_index;
625   rp->e_port = e_port;
626   rp->vrf_id = vrf_id;
627   rp->proto = proto;
628   rp->addr_only = addr_only;
629   rp->is_add = is_add;
630 }
631
632 /**
633  * @brief Add static mapping.
634  *
635  * Create static mapping between local addr+port and external addr+port.
636  *
637  * @param l_addr Local IPv4 address.
638  * @param e_addr External IPv4 address.
639  * @param l_port Local port number.
640  * @param e_port External port number.
641  * @param vrf_id VRF ID.
642  * @param addr_only If 0 address port and pair mapping, otherwise address only.
643  * @param sw_if_index External port instead of specific IP address.
644  * @param is_add If 0 delete static mapping, otherwise add.
645  * @param twice_nat If 1 translate external host address and port.
646  *
647  * @returns
648  */
649 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
650                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
651                             u32 sw_if_index, snat_protocol_t proto, int is_add,
652                             u8 twice_nat)
653 {
654   snat_main_t * sm = &snat_main;
655   snat_static_mapping_t *m;
656   snat_session_key_t m_key;
657   clib_bihash_kv_8_8_t kv, value;
658   snat_address_t *a = 0;
659   u32 fib_index = ~0;
660   uword * p;
661   snat_interface_t *interface;
662   int i;
663   snat_main_per_thread_data_t *tsm;
664
665   /* If the external address is a specific interface address */
666   if (sw_if_index != ~0)
667     {
668       ip4_address_t * first_int_addr;
669
670       /* Might be already set... */
671       first_int_addr = ip4_interface_first_address
672         (sm->ip4_main, sw_if_index, 0 /* just want the address*/);
673
674       /* DHCP resolution required? */
675       if (first_int_addr == 0)
676         {
677           snat_add_static_mapping_when_resolved
678             (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto,
679              addr_only,  is_add);
680           return 0;
681         }
682         else
683         {
684           e_addr.as_u32 = first_int_addr->as_u32;
685           /* Identity mapping? */
686           if (l_addr.as_u32 == 0)
687             l_addr.as_u32 = e_addr.as_u32;
688         }
689     }
690
691   m_key.addr = e_addr;
692   m_key.port = addr_only ? 0 : e_port;
693   m_key.protocol = addr_only ? 0 : proto;
694   m_key.fib_index = sm->outside_fib_index;
695   kv.key = m_key.as_u64;
696   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
697     m = 0;
698   else
699     m = pool_elt_at_index (sm->static_mappings, value.value);
700
701   if (is_add)
702     {
703       if (m)
704         return VNET_API_ERROR_VALUE_EXIST;
705
706       if (twice_nat && addr_only)
707         return VNET_API_ERROR_UNSUPPORTED;
708
709       /* Convert VRF id to FIB index */
710       if (vrf_id != ~0)
711         {
712           p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
713           if (!p)
714             return VNET_API_ERROR_NO_SUCH_FIB;
715           fib_index = p[0];
716         }
717       /* If not specified use inside VRF id from SNAT plugin startup config */
718       else
719         {
720           fib_index = sm->inside_fib_index;
721           vrf_id = sm->inside_vrf_id;
722         }
723
724       /* Find external address in allocated addresses and reserve port for
725          address and port pair mapping when dynamic translations enabled */
726       if (!addr_only && !(sm->static_mapping_only))
727         {
728           for (i = 0; i < vec_len (sm->addresses); i++)
729             {
730               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
731                 {
732                   a = sm->addresses + i;
733                   /* External port must be unused */
734                   switch (proto)
735                     {
736 #define _(N, j, n, s) \
737                     case SNAT_PROTOCOL_##N: \
738                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
739                         return VNET_API_ERROR_INVALID_VALUE; \
740                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
741                       if (e_port > 1024) \
742                         { \
743                           a->busy_##n##_ports++; \
744                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
745                         } \
746                       break;
747                       foreach_snat_protocol
748 #undef _
749                     default:
750                       clib_warning("unknown_protocol");
751                       return VNET_API_ERROR_INVALID_VALUE_2;
752                     }
753                   break;
754                 }
755             }
756           /* External address must be allocated */
757           if (!a)
758             return VNET_API_ERROR_NO_SUCH_ENTRY;
759         }
760
761       pool_get (sm->static_mappings, m);
762       memset (m, 0, sizeof (*m));
763       m->local_addr = l_addr;
764       m->external_addr = e_addr;
765       m->addr_only = addr_only;
766       m->vrf_id = vrf_id;
767       m->fib_index = fib_index;
768       m->twice_nat = twice_nat;
769       if (!addr_only)
770         {
771           m->local_port = l_port;
772           m->external_port = e_port;
773           m->proto = proto;
774         }
775
776       if (sm->workers)
777         {
778           ip4_header_t ip = {
779             .src_address = m->local_addr,
780           };
781           m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index);
782           tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
783         }
784       else
785         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
786
787       m_key.addr = m->local_addr;
788       m_key.port = m->local_port;
789       m_key.protocol = m->proto;
790       m_key.fib_index = m->fib_index;
791       kv.key = m_key.as_u64;
792       kv.value = m - sm->static_mappings;
793       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
794       if (twice_nat)
795         {
796           m_key.port = clib_host_to_net_u16 (l_port);
797           kv.key = m_key.as_u64;
798           kv.value = ~0ULL;
799           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
800             clib_warning ("in2out key add failed");
801         }
802
803       m_key.addr = m->external_addr;
804       m_key.port = m->external_port;
805       m_key.fib_index = sm->outside_fib_index;
806       kv.key = m_key.as_u64;
807       kv.value = m - sm->static_mappings;
808       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
809       if (twice_nat)
810         {
811           m_key.port = clib_host_to_net_u16 (e_port);
812           kv.key = m_key.as_u64;
813           kv.value = ~0ULL;
814           if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
815             clib_warning ("out2in key add failed");
816         }
817
818     }
819   else
820     {
821       if (!m)
822         return VNET_API_ERROR_NO_SUCH_ENTRY;
823
824       /* Free external address port */
825       if (!addr_only && !(sm->static_mapping_only))
826         {
827           for (i = 0; i < vec_len (sm->addresses); i++)
828             {
829               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
830                 {
831                   a = sm->addresses + i;
832                   switch (proto)
833                     {
834 #define _(N, j, n, s) \
835                     case SNAT_PROTOCOL_##N: \
836                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
837                       if (e_port > 1024) \
838                         { \
839                           a->busy_##n##_ports--; \
840                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
841                         } \
842                       break;
843                       foreach_snat_protocol
844 #undef _
845                     default:
846                       clib_warning("unknown_protocol");
847                       return VNET_API_ERROR_INVALID_VALUE_2;
848                     }
849                   break;
850                 }
851             }
852         }
853
854       if (sm->num_workers > 1)
855         tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
856       else
857         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
858
859       m_key.addr = m->local_addr;
860       m_key.port = m->local_port;
861       m_key.protocol = m->proto;
862       m_key.fib_index = m->fib_index;
863       kv.key = m_key.as_u64;
864       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
865       if (twice_nat)
866         {
867           m_key.port = clib_host_to_net_u16 (m->local_port);
868           kv.key = m_key.as_u64;
869           kv.value = ~0ULL;
870           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
871             clib_warning ("in2out key del failed");
872         }
873
874       m_key.addr = m->external_addr;
875       m_key.port = m->external_port;
876       m_key.fib_index = sm->outside_fib_index;
877       kv.key = m_key.as_u64;
878       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
879       if (twice_nat)
880         {
881           m_key.port = clib_host_to_net_u16 (m->external_port);
882           kv.key = m_key.as_u64;
883           kv.value = ~0ULL;
884           if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
885             clib_warning ("in2out key del failed");
886         }
887
888       /* Delete session(s) for static mapping if exist */
889       if (!(sm->static_mapping_only) ||
890           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
891         {
892           snat_user_key_t u_key;
893           snat_user_t *u;
894           dlist_elt_t * head, * elt;
895           u32 elt_index, head_index;
896           u32 ses_index;
897           u64 user_index;
898           snat_session_t * s;
899
900           u_key.addr = m->local_addr;
901           u_key.fib_index = m->fib_index;
902           kv.key = u_key.as_u64;
903           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
904             {
905               user_index = value.value;
906               u = pool_elt_at_index (tsm->users, user_index);
907               if (u->nstaticsessions)
908                 {
909                   head_index = u->sessions_per_user_list_head_index;
910                   head = pool_elt_at_index (tsm->list_pool, head_index);
911                   elt_index = head->next;
912                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
913                   ses_index = elt->value;
914                   while (ses_index != ~0)
915                     {
916                       s =  pool_elt_at_index (tsm->sessions, ses_index);
917                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
918                       ses_index = elt->value;
919
920                       if (!addr_only)
921                         {
922                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
923                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
924                             continue;
925                         }
926
927                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
928                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
929                       pool_put_index (tsm->list_pool, s->per_user_index);
930                       pool_put (tsm->sessions, s);
931                       u->nstaticsessions--;
932
933                       if (!addr_only)
934                         break;
935                     }
936                   if (addr_only)
937                     {
938                       pool_put (tsm->users, u);
939                       clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0);
940                     }
941                 }
942             }
943         }
944
945       /* Delete static mapping from pool */
946       pool_put (sm->static_mappings, m);
947     }
948
949   if (!addr_only || (l_addr.as_u32 == e_addr.as_u32))
950     return 0;
951
952   /* Add/delete external address to FIB */
953   pool_foreach (interface, sm->interfaces,
954   ({
955     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
956       continue;
957
958     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
959     break;
960   }));
961   pool_foreach (interface, sm->output_feature_interfaces,
962   ({
963     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
964       continue;
965
966     snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add);
967     break;
968   }));
969
970   return 0;
971 }
972
973 int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port,
974                                      snat_protocol_t proto, u32 vrf_id,
975                                      nat44_lb_addr_port_t *locals, u8 is_add,
976                                      u8 twice_nat, u8 out2in_only)
977 {
978   snat_main_t * sm = &snat_main;
979   snat_static_mapping_t *m;
980   snat_session_key_t m_key;
981   clib_bihash_kv_8_8_t kv, value;
982   u32 fib_index;
983   snat_address_t *a = 0;
984   int i;
985   nat44_lb_addr_port_t *local;
986   u32 worker_index = 0, elt_index, head_index, ses_index;
987   snat_main_per_thread_data_t *tsm;
988   snat_user_key_t u_key;
989   snat_user_t *u;
990   snat_session_t * s;
991   dlist_elt_t * head, * elt;
992
993   m_key.addr = e_addr;
994   m_key.port = e_port;
995   m_key.protocol = proto;
996   m_key.fib_index = sm->outside_fib_index;
997   kv.key = m_key.as_u64;
998   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
999     m = 0;
1000   else
1001     m = pool_elt_at_index (sm->static_mappings, value.value);
1002
1003   if (is_add)
1004     {
1005       if (m)
1006         return VNET_API_ERROR_VALUE_EXIST;
1007
1008       if (vec_len (locals) < 2)
1009         return VNET_API_ERROR_INVALID_VALUE;
1010
1011       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
1012                                                      vrf_id,
1013                                                      FIB_SOURCE_PLUGIN_HI);
1014
1015       /* Find external address in allocated addresses and reserve port for
1016          address and port pair mapping when dynamic translations enabled */
1017       if (!(sm->static_mapping_only || out2in_only))
1018         {
1019           for (i = 0; i < vec_len (sm->addresses); i++)
1020             {
1021               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1022                 {
1023                   a = sm->addresses + i;
1024                   /* External port must be unused */
1025                   switch (proto)
1026                     {
1027 #define _(N, j, n, s) \
1028                     case SNAT_PROTOCOL_##N: \
1029                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \
1030                         return VNET_API_ERROR_INVALID_VALUE; \
1031                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \
1032                       if (e_port > 1024) \
1033                         { \
1034                           a->busy_##n##_ports++; \
1035                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \
1036                         } \
1037                       break;
1038                       foreach_snat_protocol
1039 #undef _
1040                     default:
1041                       clib_warning("unknown_protocol");
1042                       return VNET_API_ERROR_INVALID_VALUE_2;
1043                     }
1044                   break;
1045                 }
1046             }
1047           /* External address must be allocated */
1048           if (!a)
1049             return VNET_API_ERROR_NO_SUCH_ENTRY;
1050         }
1051
1052       pool_get (sm->static_mappings, m);
1053       memset (m, 0, sizeof (*m));
1054       m->external_addr = e_addr;
1055       m->addr_only = 0;
1056       m->vrf_id = vrf_id;
1057       m->fib_index = fib_index;
1058       m->external_port = e_port;
1059       m->proto = proto;
1060       m->twice_nat = twice_nat;
1061       m->out2in_only = out2in_only;
1062
1063       m_key.addr = m->external_addr;
1064       m_key.port = m->external_port;
1065       m_key.protocol = m->proto;
1066       m_key.fib_index = sm->outside_fib_index;
1067       kv.key = m_key.as_u64;
1068       kv.value = m - sm->static_mappings;
1069       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1))
1070         {
1071           clib_warning ("static_mapping_by_external key add failed");
1072           return VNET_API_ERROR_UNSPECIFIED;
1073         }
1074
1075       /* Assign worker */
1076       if (sm->workers)
1077         {
1078           worker_index = sm->first_worker_index +
1079             sm->workers[sm->next_worker++ % vec_len (sm->workers)];
1080           tsm = vec_elt_at_index (sm->per_thread_data, worker_index);
1081           m->worker_index = worker_index;
1082         }
1083       else
1084         tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1085
1086       m_key.port = clib_host_to_net_u16 (m->external_port);
1087       kv.key = m_key.as_u64;
1088       kv.value = ~0ULL;
1089       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1))
1090         {
1091           clib_warning ("out2in key add failed");
1092           return VNET_API_ERROR_UNSPECIFIED;
1093         }
1094
1095       m_key.fib_index = m->fib_index;
1096       for (i = 0; i < vec_len (locals); i++)
1097         {
1098           m_key.addr = locals[i].addr;
1099           if (!out2in_only)
1100             {
1101               m_key.port = locals[i].port;
1102               kv.key = m_key.as_u64;
1103               kv.value = m - sm->static_mappings;
1104               clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
1105             }
1106           locals[i].prefix = (i == 0) ? locals[i].probability :\
1107             (locals[i - 1].prefix + locals[i].probability);
1108           vec_add1 (m->locals, locals[i]);
1109
1110           m_key.port = clib_host_to_net_u16 (locals[i].port);
1111           kv.key = m_key.as_u64;
1112           kv.value = ~0ULL;
1113           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1))
1114             {
1115               clib_warning ("in2out key add failed");
1116               return VNET_API_ERROR_UNSPECIFIED;
1117             }
1118         }
1119     }
1120   else
1121     {
1122       if (!m)
1123         return VNET_API_ERROR_NO_SUCH_ENTRY;
1124
1125       fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI);
1126
1127       /* Free external address port */
1128       if (!(sm->static_mapping_only || out2in_only))
1129         {
1130           for (i = 0; i < vec_len (sm->addresses); i++)
1131             {
1132               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
1133                 {
1134                   a = sm->addresses + i;
1135                   switch (proto)
1136                     {
1137 #define _(N, j, n, s) \
1138                     case SNAT_PROTOCOL_##N: \
1139                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \
1140                       if (e_port > 1024) \
1141                         { \
1142                           a->busy_##n##_ports--; \
1143                           a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \
1144                         } \
1145                       break;
1146                       foreach_snat_protocol
1147 #undef _
1148                     default:
1149                       clib_warning("unknown_protocol");
1150                       return VNET_API_ERROR_INVALID_VALUE_2;
1151                     }
1152                   break;
1153                 }
1154             }
1155         }
1156
1157       tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index);
1158       m_key.addr = m->external_addr;
1159       m_key.port = m->external_port;
1160       m_key.protocol = m->proto;
1161       m_key.fib_index = sm->outside_fib_index;
1162       kv.key = m_key.as_u64;
1163       if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0))
1164         {
1165           clib_warning ("static_mapping_by_external key del failed");
1166           return VNET_API_ERROR_UNSPECIFIED;
1167         }
1168
1169       m_key.port = clib_host_to_net_u16 (m->external_port);
1170       kv.key = m_key.as_u64;
1171       if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0))
1172         {
1173           clib_warning ("outi2in key del failed");
1174           return VNET_API_ERROR_UNSPECIFIED;
1175         }
1176
1177       vec_foreach (local, m->locals)
1178         {
1179           m_key.addr = local->addr;
1180           if (!out2in_only)
1181             {
1182               m_key.port = local->port;
1183               m_key.fib_index = m->fib_index;
1184               kv.key = m_key.as_u64;
1185               if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0))
1186                 {
1187                   clib_warning ("static_mapping_by_local key del failed");
1188                   return VNET_API_ERROR_UNSPECIFIED;
1189                 }
1190             }
1191
1192           m_key.port = clib_host_to_net_u16 (local->port);
1193           kv.key = m_key.as_u64;
1194           if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0))
1195             {
1196               clib_warning ("in2out key del failed");
1197               return VNET_API_ERROR_UNSPECIFIED;
1198             }
1199           /* Delete sessions */
1200           u_key.addr = local->addr;
1201           u_key.fib_index = m->fib_index;
1202           kv.key = u_key.as_u64;
1203           if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1204             {
1205               u = pool_elt_at_index (tsm->users, value.value);
1206               if (u->nstaticsessions)
1207                 {
1208                   head_index = u->sessions_per_user_list_head_index;
1209                   head = pool_elt_at_index (tsm->list_pool, head_index);
1210                   elt_index = head->next;
1211                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1212                   ses_index = elt->value;
1213                   while (ses_index != ~0)
1214                     {
1215                       s =  pool_elt_at_index (tsm->sessions, ses_index);
1216                       elt = pool_elt_at_index (tsm->list_pool, elt->next);
1217                       ses_index = elt->value;
1218
1219                       if ((s->in2out.addr.as_u32 != local->addr.as_u32) &&
1220                           (clib_net_to_host_u16 (s->in2out.port) != local->port))
1221                         continue;
1222
1223                       nat_free_session_data (sm, s, tsm - sm->per_thread_data);
1224                       clib_dlist_remove (tsm->list_pool, s->per_user_index);
1225                       pool_put_index (tsm->list_pool, s->per_user_index);
1226                       pool_put (tsm->sessions, s);
1227                       u->nstaticsessions--;
1228                     }
1229                 }
1230             }
1231         }
1232       vec_free(m->locals);
1233
1234       pool_put (sm->static_mappings, m);
1235     }
1236
1237   return 0;
1238 }
1239
1240 int
1241 snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm,
1242                   u8 twice_nat)
1243 {
1244   snat_address_t *a = 0;
1245   snat_session_t *ses;
1246   u32 *ses_to_be_removed = 0, *ses_index;
1247   clib_bihash_kv_8_8_t kv, value;
1248   snat_user_key_t user_key;
1249   snat_user_t *u;
1250   snat_main_per_thread_data_t *tsm;
1251   snat_static_mapping_t *m;
1252   snat_interface_t *interface;
1253   int i;
1254   snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses;
1255
1256   /* Find SNAT address */
1257   for (i=0; i < vec_len (addresses); i++)
1258     {
1259       if (addresses[i].addr.as_u32 == addr.as_u32)
1260         {
1261           a = addresses + i;
1262           break;
1263         }
1264     }
1265   if (!a)
1266     return VNET_API_ERROR_NO_SUCH_ENTRY;
1267
1268   if (delete_sm)
1269     {
1270       pool_foreach (m, sm->static_mappings,
1271       ({
1272           if (m->external_addr.as_u32 == addr.as_u32)
1273             (void) snat_add_static_mapping (m->local_addr, m->external_addr,
1274                                             m->local_port, m->external_port,
1275                                             m->vrf_id, m->addr_only, ~0,
1276                                             m->proto, 0, m->twice_nat);
1277       }));
1278     }
1279   else
1280     {
1281       /* Check if address is used in some static mapping */
1282       if (is_snat_address_used_in_static_mapping(sm, addr))
1283         {
1284           clib_warning ("address used in static mapping");
1285           return VNET_API_ERROR_UNSPECIFIED;
1286         }
1287     }
1288
1289   if (a->fib_index != ~0)
1290     fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4,
1291                      FIB_SOURCE_PLUGIN_HI);
1292
1293   /* Delete sessions using address */
1294   if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports)
1295     {
1296       vec_foreach (tsm, sm->per_thread_data)
1297         {
1298           pool_foreach (ses, tsm->sessions, ({
1299             if (ses->out2in.addr.as_u32 == addr.as_u32)
1300               {
1301                 ses->outside_address_index = ~0;
1302                 nat_free_session_data (sm, ses, tsm - sm->per_thread_data);
1303                 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
1304                 pool_put_index (tsm->list_pool, ses->per_user_index);
1305                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
1306                 user_key.addr = ses->in2out.addr;
1307                 user_key.fib_index = ses->in2out.fib_index;
1308                 kv.key = user_key.as_u64;
1309                 if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
1310                   {
1311                     u = pool_elt_at_index (tsm->users, value.value);
1312                     u->nsessions--;
1313                   }
1314               }
1315           }));
1316
1317           vec_foreach (ses_index, ses_to_be_removed)
1318             pool_put_index (tsm->sessions, ses_index[0]);
1319
1320           vec_free (ses_to_be_removed);
1321        }
1322     }
1323
1324   if (twice_nat)
1325     {
1326       vec_del1 (sm->twice_nat_addresses, i);
1327       return 0;
1328     }
1329   else
1330     vec_del1 (sm->addresses, i);
1331
1332   /* Delete external address from FIB */
1333   pool_foreach (interface, sm->interfaces,
1334   ({
1335     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1336       continue;
1337
1338     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1339     break;
1340   }));
1341   pool_foreach (interface, sm->output_feature_interfaces,
1342   ({
1343     if (nat_interface_is_inside(interface) || sm->out2in_dpo)
1344       continue;
1345
1346     snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0);
1347     break;
1348   }));
1349
1350   return 0;
1351 }
1352
1353 int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
1354 {
1355   snat_main_t *sm = &snat_main;
1356   snat_interface_t *i;
1357   const char * feature_name, *del_feature_name;
1358   snat_address_t * ap;
1359   snat_static_mapping_t * m;
1360   snat_det_map_t * dm;
1361
1362   if (sm->out2in_dpo && !is_inside)
1363     return VNET_API_ERROR_UNSUPPORTED;
1364
1365   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1366     feature_name = is_inside ?  "nat44-in2out-fast" : "nat44-out2in-fast";
1367   else
1368     {
1369       if (sm->num_workers > 1 && !sm->deterministic)
1370         feature_name = is_inside ?  "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff";
1371       else if (sm->deterministic)
1372         feature_name = is_inside ?  "nat44-det-in2out" : "nat44-det-out2in";
1373       else
1374         feature_name = is_inside ?  "nat44-in2out" : "nat44-out2in";
1375     }
1376
1377   if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1378     sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0);
1379
1380   if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1)
1381     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1382
1383   pool_foreach (i, sm->interfaces,
1384   ({
1385     if (i->sw_if_index == sw_if_index)
1386       {
1387         if (is_del)
1388           {
1389             if (nat_interface_is_inside(i) && nat_interface_is_outside(i))
1390               {
1391                 if (is_inside)
1392                   i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE;
1393                 else
1394                   i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
1395
1396                 if (sm->num_workers > 1 && !sm->deterministic)
1397                   del_feature_name = "nat44-handoff-classify";
1398                 else if (sm->deterministic)
1399                   del_feature_name = "nat44-det-classify";
1400                 else
1401                   del_feature_name = "nat44-classify";
1402
1403                 vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1404                                              sw_if_index, 0, 0, 0);
1405                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1406                                              sw_if_index, 1, 0, 0);
1407               }
1408             else
1409               {
1410                 vnet_feature_enable_disable ("ip4-unicast", feature_name,
1411                                              sw_if_index, 0, 0, 0);
1412                 pool_put (sm->interfaces, i);
1413               }
1414           }
1415         else
1416           {
1417             if ((nat_interface_is_inside(i) && is_inside) ||
1418                 (nat_interface_is_outside(i) && !is_inside))
1419               return 0;
1420
1421             if (sm->num_workers > 1 && !sm->deterministic)
1422               {
1423                 del_feature_name = !is_inside ?  "nat44-in2out-worker-handoff" :
1424                                                  "nat44-out2in-worker-handoff";
1425                 feature_name = "nat44-handoff-classify";
1426               }
1427             else if (sm->deterministic)
1428               {
1429                 del_feature_name = !is_inside ?  "nat44-det-in2out" :
1430                                                  "nat44-det-out2in";
1431                 feature_name = "nat44-det-classify";
1432               }
1433             else
1434               {
1435                 del_feature_name = !is_inside ?  "nat44-in2out" : "nat44-out2in";
1436                 feature_name = "nat44-classify";
1437               }
1438
1439             vnet_feature_enable_disable ("ip4-unicast", del_feature_name,
1440                                          sw_if_index, 0, 0, 0);
1441             vnet_feature_enable_disable ("ip4-unicast", feature_name,
1442                                          sw_if_index, 1, 0, 0);
1443             goto set_flags;
1444           }
1445
1446         goto fib;
1447       }
1448   }));
1449
1450   if (is_del)
1451     return VNET_API_ERROR_NO_SUCH_ENTRY;
1452
1453   pool_get (sm->interfaces, i);
1454   i->sw_if_index = sw_if_index;
1455   i->flags = 0;
1456   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0);
1457
1458 set_flags:
1459   if (is_inside)
1460     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1461   else
1462     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1463
1464   /* Add/delete external addresses to FIB */
1465 fib:
1466   if (is_inside && !sm->out2in_dpo)
1467     {
1468       vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning",
1469                                    sw_if_index, !is_del, 0, 0);
1470       return 0;
1471     }
1472
1473   vec_foreach (ap, sm->addresses)
1474     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1475
1476   pool_foreach (m, sm->static_mappings,
1477   ({
1478     if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32))
1479       continue;
1480
1481     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1482   }));
1483
1484   pool_foreach (dm, sm->det_maps,
1485   ({
1486     snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del);
1487   }));
1488
1489   return 0;
1490 }
1491
1492 int snat_interface_add_del_output_feature (u32 sw_if_index,
1493                                            u8 is_inside,
1494                                            int is_del)
1495 {
1496   snat_main_t *sm = &snat_main;
1497   snat_interface_t *i;
1498   snat_address_t * ap;
1499   snat_static_mapping_t * m;
1500
1501   if (sm->deterministic ||
1502       (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)))
1503     return VNET_API_ERROR_UNSUPPORTED;
1504
1505   if (is_inside)
1506     {
1507       vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst",
1508                                    sw_if_index, !is_del, 0, 0);
1509       vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src",
1510                                    sw_if_index, !is_del, 0, 0);
1511       goto fq;
1512     }
1513
1514   if (sm->num_workers > 1)
1515     {
1516       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff",
1517                                    sw_if_index, !is_del, 0, 0);
1518       vnet_feature_enable_disable ("ip4-output",
1519                                    "nat44-in2out-output-worker-handoff",
1520                                    sw_if_index, !is_del, 0, 0);
1521     }
1522   else
1523     {
1524       vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index,
1525                                    !is_del, 0, 0);
1526       vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output",
1527                                    sw_if_index, !is_del, 0, 0);
1528     }
1529
1530 fq:
1531   if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1)
1532     sm->fq_in2out_output_index =
1533       vlib_frame_queue_main_init (sm->in2out_output_node_index, 0);
1534
1535   if (sm->fq_out2in_index == ~0 && sm->num_workers > 1)
1536     sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0);
1537
1538   pool_foreach (i, sm->output_feature_interfaces,
1539   ({
1540     if (i->sw_if_index == sw_if_index)
1541       {
1542         if (is_del)
1543           pool_put (sm->output_feature_interfaces, i);
1544         else
1545           return VNET_API_ERROR_VALUE_EXIST;
1546
1547         goto fib;
1548       }
1549   }));
1550
1551   if (is_del)
1552     return VNET_API_ERROR_NO_SUCH_ENTRY;
1553
1554   pool_get (sm->output_feature_interfaces, i);
1555   i->sw_if_index = sw_if_index;
1556   i->flags = 0;
1557   if (is_inside)
1558     i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
1559   else
1560     i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
1561
1562   /* Add/delete external addresses to FIB */
1563 fib:
1564   if (is_inside)
1565     return 0;
1566
1567   vec_foreach (ap, sm->addresses)
1568     snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del);
1569
1570   pool_foreach (m, sm->static_mappings,
1571   ({
1572     if (!(m->addr_only))
1573       continue;
1574
1575     snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del);
1576   }));
1577
1578   return 0;
1579 }
1580
1581 int snat_set_workers (uword * bitmap)
1582 {
1583   snat_main_t *sm = &snat_main;
1584   int i, j = 0;
1585
1586   if (sm->num_workers < 2)
1587     return VNET_API_ERROR_FEATURE_DISABLED;
1588
1589   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
1590     return VNET_API_ERROR_INVALID_WORKER;
1591
1592   vec_free (sm->workers);
1593   clib_bitmap_foreach (i, bitmap,
1594     ({
1595       vec_add1(sm->workers, i);
1596       sm->per_thread_data[sm->first_worker_index + i].snat_thread_index = j;
1597       j++;
1598     }));
1599
1600   sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers);
1601   sm->num_snat_thread = _vec_len (sm->workers);
1602
1603   return 0;
1604 }
1605
1606
1607 static void
1608 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1609                                        uword opaque,
1610                                        u32 sw_if_index,
1611                                        ip4_address_t * address,
1612                                        u32 address_length,
1613                                        u32 if_address_index,
1614                                        u32 is_delete);
1615
1616 static int
1617 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1618                                  u32 fib_index,
1619                                  u32 thread_index,
1620                                  snat_session_key_t * k,
1621                                  u32 * address_indexp,
1622                                  u16 port_per_thread,
1623                                  u32 snat_thread_index);
1624
1625 static clib_error_t * snat_init (vlib_main_t * vm)
1626 {
1627   snat_main_t * sm = &snat_main;
1628   clib_error_t * error = 0;
1629   ip4_main_t * im = &ip4_main;
1630   ip_lookup_main_t * lm = &im->lookup_main;
1631   uword *p;
1632   vlib_thread_registration_t *tr;
1633   vlib_thread_main_t *tm = vlib_get_thread_main ();
1634   uword *bitmap = 0;
1635   u32 i;
1636   ip4_add_del_interface_address_callback_t cb4;
1637
1638   sm->vlib_main = vm;
1639   sm->vnet_main = vnet_get_main();
1640   sm->ip4_main = im;
1641   sm->ip4_lookup_main = lm;
1642   sm->api_main = &api_main;
1643   sm->first_worker_index = 0;
1644   sm->next_worker = 0;
1645   sm->num_workers = 0;
1646   sm->num_snat_thread = 1;
1647   sm->workers = 0;
1648   sm->port_per_thread = 0xffff - 1024;
1649   sm->fq_in2out_index = ~0;
1650   sm->fq_out2in_index = ~0;
1651   sm->udp_timeout = SNAT_UDP_TIMEOUT;
1652   sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1653   sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1654   sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1655   sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
1656   sm->forwarding_enabled = 0;
1657
1658   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1659   if (p)
1660     {
1661       tr = (vlib_thread_registration_t *) p[0];
1662       if (tr)
1663         {
1664           sm->num_workers = tr->count;
1665           sm->first_worker_index = tr->first_index;
1666         }
1667     }
1668
1669   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1670
1671   /* Use all available workers by default */
1672   if (sm->num_workers > 1)
1673     {
1674       for (i=0; i < sm->num_workers; i++)
1675         bitmap = clib_bitmap_set (bitmap, i, 1);
1676       snat_set_workers(bitmap);
1677       clib_bitmap_free (bitmap);
1678     }
1679   else
1680     {
1681       sm->per_thread_data[0].snat_thread_index = 0;
1682     }
1683
1684   error = snat_api_init(vm, sm);
1685   if (error)
1686     return error;
1687
1688   /* Set up the interface address add/del callback */
1689   cb4.function = snat_ip4_add_del_interface_address_cb;
1690   cb4.function_opaque = 0;
1691
1692   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1693
1694   nat_dpo_module_init ();
1695
1696   /* Init IPFIX logging */
1697   snat_ipfix_logging_init(vm);
1698
1699   /* Init NAT64 */
1700   error = nat64_init(vm);
1701   if (error)
1702     return error;
1703
1704   dslite_init(vm);
1705
1706   /* Init virtual fragmenentation reassembly */
1707   return nat_reass_init(vm);
1708 }
1709
1710 VLIB_INIT_FUNCTION (snat_init);
1711
1712 void snat_free_outside_address_and_port (snat_address_t * addresses,
1713                                          u32 thread_index,
1714                                          snat_session_key_t * k,
1715                                          u32 address_index)
1716 {
1717   snat_address_t *a;
1718   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1719
1720   ASSERT (address_index < vec_len (addresses));
1721
1722   a = addresses + address_index;
1723
1724   switch (k->protocol)
1725     {
1726 #define _(N, i, n, s) \
1727     case SNAT_PROTOCOL_##N: \
1728       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1729         port_host_byte_order) == 1); \
1730       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1731         port_host_byte_order, 0); \
1732       a->busy_##n##_ports--; \
1733       a->busy_##n##_ports_per_thread[thread_index]--; \
1734       break;
1735       foreach_snat_protocol
1736 #undef _
1737     default:
1738       clib_warning("unknown_protocol");
1739       return;
1740     }
1741 }
1742
1743 /**
1744  * @brief Match NAT44 static mapping.
1745  *
1746  * @param sm          NAT main.
1747  * @param match       Address and port to match.
1748  * @param mapping     External or local address and port of the matched mapping.
1749  * @param by_external If 0 match by local address otherwise match by external
1750  *                    address.
1751  * @param is_addr_only If matched mapping is address only
1752  * @param twice_nat If matched mapping is twice NAT.
1753  *
1754  * @returns 0 if match found otherwise 1.
1755  */
1756 int snat_static_mapping_match (snat_main_t * sm,
1757                                snat_session_key_t match,
1758                                snat_session_key_t * mapping,
1759                                u8 by_external,
1760                                u8 *is_addr_only,
1761                                u8 *twice_nat)
1762 {
1763   clib_bihash_kv_8_8_t kv, value;
1764   snat_static_mapping_t *m;
1765   snat_session_key_t m_key;
1766   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1767   u32 rand, lo = 0, hi, mid;
1768
1769   if (by_external)
1770     mapping_hash = &sm->static_mapping_by_external;
1771
1772   m_key.addr = match.addr;
1773   m_key.port = clib_net_to_host_u16 (match.port);
1774   m_key.protocol = match.protocol;
1775   m_key.fib_index = match.fib_index;
1776
1777   kv.key = m_key.as_u64;
1778
1779   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1780     {
1781       /* Try address only mapping */
1782       m_key.port = 0;
1783       m_key.protocol = 0;
1784       kv.key = m_key.as_u64;
1785       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1786         return 1;
1787     }
1788
1789   m = pool_elt_at_index (sm->static_mappings, value.value);
1790
1791   if (by_external)
1792     {
1793       if (vec_len (m->locals))
1794         {
1795           hi = vec_len (m->locals) - 1;
1796           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1797           while (lo < hi)
1798             {
1799               mid = ((hi - lo) >> 1) + lo;
1800               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1801             }
1802           if (!(m->locals[lo].prefix >= rand))
1803             return 1;
1804           mapping->addr = m->locals[lo].addr;
1805           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1806         }
1807       else
1808         {
1809           mapping->addr = m->local_addr;
1810           /* Address only mapping doesn't change port */
1811           mapping->port = m->addr_only ? match.port
1812             : clib_host_to_net_u16 (m->local_port);
1813         }
1814       mapping->fib_index = m->fib_index;
1815       mapping->protocol = m->proto;
1816     }
1817   else
1818     {
1819       mapping->addr = m->external_addr;
1820       /* Address only mapping doesn't change port */
1821       mapping->port = m->addr_only ? match.port
1822         : clib_host_to_net_u16 (m->external_port);
1823       mapping->fib_index = sm->outside_fib_index;
1824     }
1825
1826   if (PREDICT_FALSE(is_addr_only != 0))
1827     *is_addr_only = m->addr_only;
1828
1829   if (PREDICT_FALSE(twice_nat != 0))
1830     *twice_nat = m->twice_nat;
1831
1832   return 0;
1833 }
1834
1835 static_always_inline u16
1836 snat_random_port (u16 min, u16 max)
1837 {
1838   snat_main_t *sm = &snat_main;
1839   return min + random_u32 (&sm->random_seed) /
1840     (random_u32_max() / (max - min + 1) + 1);
1841 }
1842
1843 int
1844 snat_alloc_outside_address_and_port (snat_address_t * addresses,
1845                                      u32 fib_index,
1846                                      u32 thread_index,
1847                                      snat_session_key_t * k,
1848                                      u32 * address_indexp,
1849                                      u16 port_per_thread,
1850                                      u32 snat_thread_index)
1851 {
1852   snat_main_t *sm = &snat_main;
1853
1854   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
1855                                  address_indexp, port_per_thread,
1856                                  snat_thread_index);
1857 }
1858
1859 static int
1860 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1861                                  u32 fib_index,
1862                                  u32 thread_index,
1863                                  snat_session_key_t * k,
1864                                  u32 * address_indexp,
1865                                  u16 port_per_thread,
1866                                  u32 snat_thread_index)
1867 {
1868   int i, gi = 0;
1869   snat_address_t *a, *ga = 0;
1870   u32 portnum;
1871
1872   for (i = 0; i < vec_len (addresses); i++)
1873     {
1874       a = addresses + i;
1875       switch (k->protocol)
1876         {
1877 #define _(N, j, n, s) \
1878         case SNAT_PROTOCOL_##N: \
1879           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1880             { \
1881               if (a->fib_index == fib_index) \
1882                 { \
1883                   while (1) \
1884                     { \
1885                       portnum = (port_per_thread * \
1886                         snat_thread_index) + \
1887                         snat_random_port(1, port_per_thread) + 1024; \
1888                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1889                         continue; \
1890                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1891                       a->busy_##n##_ports_per_thread[thread_index]++; \
1892                       a->busy_##n##_ports++; \
1893                       k->addr = a->addr; \
1894                       k->port = clib_host_to_net_u16(portnum); \
1895                       *address_indexp = i; \
1896                       return 0; \
1897                     } \
1898                 } \
1899               else if (a->fib_index == ~0) \
1900                 { \
1901                   ga = a; \
1902                   gi = i; \
1903                 } \
1904             } \
1905           break;
1906           foreach_snat_protocol
1907 #undef _
1908         default:
1909           clib_warning("unknown protocol");
1910           return 1;
1911         }
1912
1913     }
1914
1915   if (ga)
1916     {
1917       a = ga;
1918       switch (k->protocol)
1919         {
1920 #define _(N, j, n, s) \
1921         case SNAT_PROTOCOL_##N: \
1922           while (1) \
1923             { \
1924               portnum = (port_per_thread * \
1925                 snat_thread_index) + \
1926                 snat_random_port(1, port_per_thread) + 1024; \
1927               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1928                 continue; \
1929               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1930               a->busy_##n##_ports_per_thread[thread_index]++; \
1931               a->busy_##n##_ports++; \
1932               k->addr = a->addr; \
1933               k->port = clib_host_to_net_u16(portnum); \
1934               *address_indexp = gi; \
1935               return 0; \
1936             }
1937           break;
1938           foreach_snat_protocol
1939 #undef _
1940         default:
1941           clib_warning ("unknown protocol");
1942           return 1;
1943         }
1944     }
1945
1946   /* Totally out of translations to use... */
1947   snat_ipfix_logging_addresses_exhausted(0);
1948   return 1;
1949 }
1950
1951 static int
1952 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
1953                               u32 fib_index,
1954                               u32 thread_index,
1955                               snat_session_key_t * k,
1956                               u32 * address_indexp,
1957                               u16 port_per_thread,
1958                               u32 snat_thread_index)
1959 {
1960   snat_main_t *sm = &snat_main;
1961   snat_address_t *a = addresses;
1962   u16 m, ports, portnum, A, j;
1963   m = 16 - (sm->psid_offset + sm->psid_length);
1964   ports = (1 << (16 - sm->psid_length)) - (1 << m);
1965
1966   if (!vec_len (addresses))
1967     goto exhausted;
1968
1969   switch (k->protocol)
1970     {
1971 #define _(N, i, n, s) \
1972     case SNAT_PROTOCOL_##N: \
1973       if (a->busy_##n##_ports < ports) \
1974         { \
1975           while (1) \
1976             { \
1977               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
1978               j = snat_random_port(0, pow2_mask(m)); \
1979               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
1980               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1981                 continue; \
1982               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1983               a->busy_##n##_ports++; \
1984               k->addr = a->addr; \
1985               k->port = clib_host_to_net_u16 (portnum); \
1986               *address_indexp = i; \
1987               return 0; \
1988             } \
1989         } \
1990       break;
1991       foreach_snat_protocol
1992 #undef _
1993     default:
1994       clib_warning("unknown protocol");
1995       return 1;
1996     }
1997
1998 exhausted:
1999   /* Totally out of translations to use... */
2000   snat_ipfix_logging_addresses_exhausted(0);
2001   return 1;
2002 }
2003
2004 void
2005 nat44_add_del_address_dpo (ip4_address_t addr, u8 is_add)
2006 {
2007   dpo_id_t dpo_v4 = DPO_INVALID;
2008   fib_prefix_t pfx = {
2009     .fp_proto = FIB_PROTOCOL_IP4,
2010     .fp_len = 32,
2011     .fp_addr.ip4.as_u32 = addr.as_u32,
2012   };
2013
2014   if (is_add)
2015     {
2016       nat_dpo_create (DPO_PROTO_IP4, 0, &dpo_v4);
2017       fib_table_entry_special_dpo_add (0, &pfx, FIB_SOURCE_PLUGIN_HI,
2018                                        FIB_ENTRY_FLAG_EXCLUSIVE, &dpo_v4);
2019       dpo_reset (&dpo_v4);
2020     }
2021   else
2022     {
2023       fib_table_entry_special_remove (0, &pfx, FIB_SOURCE_PLUGIN_HI);
2024     }
2025 }
2026
2027 static clib_error_t *
2028 add_address_command_fn (vlib_main_t * vm,
2029                         unformat_input_t * input,
2030                         vlib_cli_command_t * cmd)
2031 {
2032   unformat_input_t _line_input, *line_input = &_line_input;
2033   snat_main_t * sm = &snat_main;
2034   ip4_address_t start_addr, end_addr, this_addr;
2035   u32 start_host_order, end_host_order;
2036   u32 vrf_id = ~0;
2037   int i, count;
2038   int is_add = 1;
2039   int rv = 0;
2040   clib_error_t *error = 0;
2041   u8 twice_nat = 0;
2042
2043   /* Get a line of input. */
2044   if (!unformat_user (input, unformat_line_input, line_input))
2045     return 0;
2046
2047   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2048     {
2049       if (unformat (line_input, "%U - %U",
2050                     unformat_ip4_address, &start_addr,
2051                     unformat_ip4_address, &end_addr))
2052         ;
2053       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
2054         ;
2055       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
2056         end_addr = start_addr;
2057       else if (unformat (line_input, "twice-nat"))
2058         twice_nat = 1;
2059       else if (unformat (line_input, "del"))
2060         is_add = 0;
2061       else
2062         {
2063           error = clib_error_return (0, "unknown input '%U'",
2064             format_unformat_error, line_input);
2065           goto done;
2066         }
2067      }
2068
2069   if (sm->static_mapping_only)
2070     {
2071       error = clib_error_return (0, "static mapping only mode");
2072       goto done;
2073     }
2074
2075   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
2076   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
2077
2078   if (end_host_order < start_host_order)
2079     {
2080       error = clib_error_return (0, "end address less than start address");
2081       goto done;
2082     }
2083
2084   count = (end_host_order - start_host_order) + 1;
2085
2086   if (count > 1024)
2087     clib_warning ("%U - %U, %d addresses...",
2088                   format_ip4_address, &start_addr,
2089                   format_ip4_address, &end_addr,
2090                   count);
2091
2092   this_addr = start_addr;
2093
2094   for (i = 0; i < count; i++)
2095     {
2096       if (is_add)
2097         snat_add_address (sm, &this_addr, vrf_id, twice_nat);
2098       else
2099         rv = snat_del_address (sm, this_addr, 0, twice_nat);
2100
2101       switch (rv)
2102         {
2103         case VNET_API_ERROR_NO_SUCH_ENTRY:
2104           error = clib_error_return (0, "S-NAT address not exist.");
2105           goto done;
2106         case VNET_API_ERROR_UNSPECIFIED:
2107           error = clib_error_return (0, "S-NAT address used in static mapping.");
2108           goto done;
2109         default:
2110           break;
2111         }
2112
2113       if (sm->out2in_dpo)
2114         nat44_add_del_address_dpo (this_addr, is_add);
2115
2116       increment_v4_address (&this_addr);
2117     }
2118
2119 done:
2120   unformat_free (line_input);
2121
2122   return error;
2123 }
2124
2125 VLIB_CLI_COMMAND (add_address_command, static) = {
2126   .path = "nat44 add address",
2127   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
2128                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
2129   .function = add_address_command_fn,
2130 };
2131
2132 static clib_error_t *
2133 snat_feature_command_fn (vlib_main_t * vm,
2134                           unformat_input_t * input,
2135                           vlib_cli_command_t * cmd)
2136 {
2137   unformat_input_t _line_input, *line_input = &_line_input;
2138   vnet_main_t * vnm = vnet_get_main();
2139   clib_error_t * error = 0;
2140   u32 sw_if_index;
2141   u32 * inside_sw_if_indices = 0;
2142   u32 * outside_sw_if_indices = 0;
2143   u8 is_output_feature = 0;
2144   int is_del = 0;
2145   int i;
2146
2147   sw_if_index = ~0;
2148
2149   /* Get a line of input. */
2150   if (!unformat_user (input, unformat_line_input, line_input))
2151     return 0;
2152
2153   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2154     {
2155       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
2156                     vnm, &sw_if_index))
2157         vec_add1 (inside_sw_if_indices, sw_if_index);
2158       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
2159                          vnm, &sw_if_index))
2160         vec_add1 (outside_sw_if_indices, sw_if_index);
2161       else if (unformat (line_input, "output-feature"))
2162         is_output_feature = 1;
2163       else if (unformat (line_input, "del"))
2164         is_del = 1;
2165       else
2166         {
2167           error = clib_error_return (0, "unknown input '%U'",
2168             format_unformat_error, line_input);
2169           goto done;
2170         }
2171     }
2172
2173   if (vec_len (inside_sw_if_indices))
2174     {
2175       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
2176         {
2177           sw_if_index = inside_sw_if_indices[i];
2178           if (is_output_feature)
2179             {
2180               if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
2181                 {
2182                   error = clib_error_return (0, "%s %U failed",
2183                                              is_del ? "del" : "add",
2184                                              format_vnet_sw_interface_name, vnm,
2185                                              vnet_get_sw_interface (vnm,
2186                                                                     sw_if_index));
2187                   goto done;
2188                 }
2189             }
2190           else
2191             {
2192               if (snat_interface_add_del (sw_if_index, 1, is_del))
2193                 {
2194                   error = clib_error_return (0, "%s %U failed",
2195                                              is_del ? "del" : "add",
2196                                              format_vnet_sw_interface_name, vnm,
2197                                              vnet_get_sw_interface (vnm,
2198                                                                     sw_if_index));
2199                   goto done;
2200                 }
2201             }
2202         }
2203     }
2204
2205   if (vec_len (outside_sw_if_indices))
2206     {
2207       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
2208         {
2209           sw_if_index = outside_sw_if_indices[i];
2210           if (is_output_feature)
2211             {
2212               if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
2213                 {
2214                   error = clib_error_return (0, "%s %U failed",
2215                                              is_del ? "del" : "add",
2216                                              format_vnet_sw_interface_name, vnm,
2217                                              vnet_get_sw_interface (vnm,
2218                                                                     sw_if_index));
2219                   goto done;
2220                 }
2221             }
2222           else
2223             {
2224               if (snat_interface_add_del (sw_if_index, 0, is_del))
2225                 {
2226                   error = clib_error_return (0, "%s %U failed",
2227                                              is_del ? "del" : "add",
2228                                              format_vnet_sw_interface_name, vnm,
2229                                              vnet_get_sw_interface (vnm,
2230                                                                     sw_if_index));
2231                   goto done;
2232                 }
2233             }
2234         }
2235     }
2236
2237 done:
2238   unformat_free (line_input);
2239   vec_free (inside_sw_if_indices);
2240   vec_free (outside_sw_if_indices);
2241
2242   return error;
2243 }
2244
2245 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
2246   .path = "set interface nat44",
2247   .function = snat_feature_command_fn,
2248   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
2249                 "[del]",
2250 };
2251
2252 uword
2253 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2254 {
2255   u32 *r = va_arg (*args, u32 *);
2256
2257   if (0);
2258 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2259   foreach_snat_protocol
2260 #undef _
2261   else
2262     return 0;
2263   return 1;
2264 }
2265
2266 u8 *
2267 format_snat_protocol (u8 * s, va_list * args)
2268 {
2269   u32 i = va_arg (*args, u32);
2270   u8 *t = 0;
2271
2272   switch (i)
2273     {
2274 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2275       foreach_snat_protocol
2276 #undef _
2277     default:
2278       s = format (s, "unknown");
2279       return s;
2280     }
2281   s = format (s, "%s", t);
2282   return s;
2283 }
2284
2285 static clib_error_t *
2286 add_static_mapping_command_fn (vlib_main_t * vm,
2287                                unformat_input_t * input,
2288                                vlib_cli_command_t * cmd)
2289 {
2290   unformat_input_t _line_input, *line_input = &_line_input;
2291   clib_error_t * error = 0;
2292   ip4_address_t l_addr, e_addr;
2293   u32 l_port = 0, e_port = 0, vrf_id = ~0;
2294   int is_add = 1;
2295   int addr_only = 1;
2296   u32 sw_if_index = ~0;
2297   vnet_main_t * vnm = vnet_get_main();
2298   int rv;
2299   snat_protocol_t proto = ~0;
2300   u8 proto_set = 0;
2301   u8 twice_nat = 0;
2302
2303   /* Get a line of input. */
2304   if (!unformat_user (input, unformat_line_input, line_input))
2305     return 0;
2306
2307   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2308     {
2309       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2310                     &l_port))
2311         addr_only = 0;
2312       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2313         ;
2314       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2315                          &e_addr, &e_port))
2316         addr_only = 0;
2317       else if (unformat (line_input, "external %U", unformat_ip4_address,
2318                          &e_addr))
2319         ;
2320       else if (unformat (line_input, "external %U %u",
2321                          unformat_vnet_sw_interface, vnm, &sw_if_index,
2322                          &e_port))
2323         addr_only = 0;
2324
2325       else if (unformat (line_input, "external %U",
2326                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2327         ;
2328       else if (unformat (line_input, "vrf %u", &vrf_id))
2329         ;
2330       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2331         proto_set = 1;
2332       else if (unformat (line_input, "twice-nat"))
2333         twice_nat = 1;
2334       else if (unformat (line_input, "del"))
2335         is_add = 0;
2336       else
2337         {
2338           error = clib_error_return (0, "unknown input: '%U'",
2339             format_unformat_error, line_input);
2340           goto done;
2341         }
2342     }
2343
2344   if (twice_nat && addr_only)
2345     {
2346       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
2347       goto done;
2348     }
2349
2350   if (!addr_only && !proto_set)
2351     {
2352       error = clib_error_return (0, "missing protocol");
2353       goto done;
2354     }
2355
2356   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2357                                vrf_id, addr_only, sw_if_index, proto, is_add,
2358                                twice_nat);
2359
2360   switch (rv)
2361     {
2362     case VNET_API_ERROR_INVALID_VALUE:
2363       error = clib_error_return (0, "External port already in use.");
2364       goto done;
2365     case VNET_API_ERROR_NO_SUCH_ENTRY:
2366       if (is_add)
2367         error = clib_error_return (0, "External addres must be allocated.");
2368       else
2369         error = clib_error_return (0, "Mapping not exist.");
2370       goto done;
2371     case VNET_API_ERROR_NO_SUCH_FIB:
2372       error = clib_error_return (0, "No such VRF id.");
2373       goto done;
2374     case VNET_API_ERROR_VALUE_EXIST:
2375       error = clib_error_return (0, "Mapping already exist.");
2376       goto done;
2377     default:
2378       break;
2379     }
2380
2381 done:
2382   unformat_free (line_input);
2383
2384   return error;
2385 }
2386
2387 /*?
2388  * @cliexpar
2389  * @cliexstart{snat add static mapping}
2390  * Static mapping allows hosts on the external network to initiate connection
2391  * to to the local network host.
2392  * To create static mapping between local host address 10.0.0.3 port 6303 and
2393  * external address 4.4.4.4 port 3606 for TCP protocol use:
2394  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2395  * If not runnig "static mapping only" NAT plugin mode use before:
2396  *  vpp# nat44 add address 4.4.4.4
2397  * To create static mapping between local and external address use:
2398  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2399  * @cliexend
2400 ?*/
2401 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2402   .path = "nat44 add static mapping",
2403   .function = add_static_mapping_command_fn,
2404   .short_help =
2405     "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
2406     "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
2407 };
2408
2409 static clib_error_t *
2410 add_identity_mapping_command_fn (vlib_main_t * vm,
2411                                  unformat_input_t * input,
2412                                  vlib_cli_command_t * cmd)
2413 {
2414   unformat_input_t _line_input, *line_input = &_line_input;
2415   clib_error_t * error = 0;
2416   ip4_address_t addr;
2417   u32 port = 0, vrf_id = ~0;
2418   int is_add = 1;
2419   int addr_only = 1;
2420   u32 sw_if_index = ~0;
2421   vnet_main_t * vnm = vnet_get_main();
2422   int rv;
2423   snat_protocol_t proto;
2424
2425   addr.as_u32 = 0;
2426
2427   /* Get a line of input. */
2428   if (!unformat_user (input, unformat_line_input, line_input))
2429     return 0;
2430
2431   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2432     {
2433       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2434         ;
2435       else if (unformat (line_input, "external %U",
2436                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2437         ;
2438       else if (unformat (line_input, "vrf %u", &vrf_id))
2439         ;
2440       else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2441                          &port))
2442         addr_only = 0;
2443       else if (unformat (line_input, "del"))
2444         is_add = 0;
2445       else
2446         {
2447           error = clib_error_return (0, "unknown input: '%U'",
2448             format_unformat_error, line_input);
2449           goto done;
2450         }
2451     }
2452
2453   rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2454                                vrf_id, addr_only, sw_if_index, proto, is_add,
2455                                0);
2456
2457   switch (rv)
2458     {
2459     case VNET_API_ERROR_INVALID_VALUE:
2460       error = clib_error_return (0, "External port already in use.");
2461       goto done;
2462     case VNET_API_ERROR_NO_SUCH_ENTRY:
2463       if (is_add)
2464         error = clib_error_return (0, "External addres must be allocated.");
2465       else
2466         error = clib_error_return (0, "Mapping not exist.");
2467       goto done;
2468     case VNET_API_ERROR_NO_SUCH_FIB:
2469       error = clib_error_return (0, "No such VRF id.");
2470       goto done;
2471     case VNET_API_ERROR_VALUE_EXIST:
2472       error = clib_error_return (0, "Mapping already exist.");
2473       goto done;
2474     default:
2475       break;
2476     }
2477
2478 done:
2479   unformat_free (line_input);
2480
2481   return error;
2482 }
2483
2484 /*?
2485  * @cliexpar
2486  * @cliexstart{snat add identity mapping}
2487  * Identity mapping translate an IP address to itself.
2488  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2489  * use:
2490  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2491  * To create identity mapping for address 10.0.0.3 use:
2492  *  vpp# nat44 add identity mapping 10.0.0.3
2493  * To create identity mapping for DHCP addressed interface use:
2494  *  vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2495  * @cliexend
2496 ?*/
2497 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2498   .path = "nat44 add identity mapping",
2499   .function = add_identity_mapping_command_fn,
2500   .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2501     "[<protocol> <port>] [vrf <table-id>] [del]",
2502 };
2503
2504 static clib_error_t *
2505 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2506                                   unformat_input_t * input,
2507                                   vlib_cli_command_t * cmd)
2508 {
2509   unformat_input_t _line_input, *line_input = &_line_input;
2510   clib_error_t * error = 0;
2511   ip4_address_t l_addr, e_addr;
2512   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2513   int is_add = 1;
2514   int rv;
2515   snat_protocol_t proto;
2516   u8 proto_set = 0;
2517   nat44_lb_addr_port_t *locals = 0, local;
2518   u8 twice_nat = 0;
2519   u8 out2in_only = 0;
2520
2521   /* Get a line of input. */
2522   if (!unformat_user (input, unformat_line_input, line_input))
2523     return 0;
2524
2525   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2526     {
2527       if (unformat (line_input, "local %U:%u probability %u",
2528                     unformat_ip4_address, &l_addr, &l_port, &probability))
2529         {
2530           memset (&local, 0, sizeof (local));
2531           local.addr = l_addr;
2532           local.port = (u16) l_port;
2533           local.probability = (u8) probability;
2534           vec_add1 (locals, local);
2535         }
2536       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2537                          &e_addr, &e_port))
2538         ;
2539       else if (unformat (line_input, "vrf %u", &vrf_id))
2540         ;
2541       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2542                          &proto))
2543         proto_set = 1;
2544       else if (unformat (line_input, "twice-nat"))
2545         twice_nat = 1;
2546       else if (unformat (line_input, "out2in-only"))
2547         out2in_only = 1;
2548       else if (unformat (line_input, "del"))
2549         is_add = 0;
2550       else
2551         {
2552           error = clib_error_return (0, "unknown input: '%U'",
2553             format_unformat_error, line_input);
2554           goto done;
2555         }
2556     }
2557
2558   if (vec_len (locals) < 2)
2559     {
2560       error = clib_error_return (0, "at least two local must be set");
2561       goto done;
2562     }
2563
2564   if (!proto_set)
2565     {
2566       error = clib_error_return (0, "missing protocol");
2567       goto done;
2568     }
2569
2570   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2571                                         locals, is_add, twice_nat, out2in_only);
2572
2573   switch (rv)
2574     {
2575     case VNET_API_ERROR_INVALID_VALUE:
2576       error = clib_error_return (0, "External port already in use.");
2577       goto done;
2578     case VNET_API_ERROR_NO_SUCH_ENTRY:
2579       if (is_add)
2580         error = clib_error_return (0, "External addres must be allocated.");
2581       else
2582         error = clib_error_return (0, "Mapping not exist.");
2583       goto done;
2584     case VNET_API_ERROR_VALUE_EXIST:
2585       error = clib_error_return (0, "Mapping already exist.");
2586       goto done;
2587     default:
2588       break;
2589     }
2590
2591 done:
2592   unformat_free (line_input);
2593   vec_free (locals);
2594
2595   return error;
2596 }
2597
2598 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2599   .path = "nat44 add load-balancing static mapping",
2600   .function = add_lb_static_mapping_command_fn,
2601   .short_help =
2602     "nat44 add load-balancing static mapping protocol tcp|udp "
2603     "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
2604     "[vrf <table-id>] [out2in-only] [del]",
2605 };
2606
2607 static clib_error_t *
2608 set_workers_command_fn (vlib_main_t * vm,
2609                         unformat_input_t * input,
2610                         vlib_cli_command_t * cmd)
2611 {
2612   unformat_input_t _line_input, *line_input = &_line_input;
2613   uword *bitmap = 0;
2614   int rv = 0;
2615   clib_error_t *error = 0;
2616
2617   /* Get a line of input. */
2618   if (!unformat_user (input, unformat_line_input, line_input))
2619     return 0;
2620
2621   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2622     {
2623       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2624         ;
2625       else
2626         {
2627           error = clib_error_return (0, "unknown input '%U'",
2628             format_unformat_error, line_input);
2629           goto done;
2630         }
2631      }
2632
2633   if (bitmap == 0)
2634     {
2635       error = clib_error_return (0, "List of workers must be specified.");
2636       goto done;
2637     }
2638
2639   rv = snat_set_workers(bitmap);
2640
2641   clib_bitmap_free (bitmap);
2642
2643   switch (rv)
2644     {
2645     case VNET_API_ERROR_INVALID_WORKER:
2646       error = clib_error_return (0, "Invalid worker(s).");
2647       goto done;
2648     case VNET_API_ERROR_FEATURE_DISABLED:
2649       error = clib_error_return (0,
2650         "Supported only if 2 or more workes available.");
2651       goto done;
2652     default:
2653       break;
2654     }
2655
2656 done:
2657   unformat_free (line_input);
2658
2659   return error;
2660 }
2661
2662 /*?
2663  * @cliexpar
2664  * @cliexstart{set snat workers}
2665  * Set NAT workers if 2 or more workers available, use:
2666  *  vpp# set snat workers 0-2,5
2667  * @cliexend
2668 ?*/
2669 VLIB_CLI_COMMAND (set_workers_command, static) = {
2670   .path = "set nat workers",
2671   .function = set_workers_command_fn,
2672   .short_help =
2673     "set nat workers <workers-list>",
2674 };
2675
2676 static clib_error_t *
2677 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2678                                               unformat_input_t * input,
2679                                               vlib_cli_command_t * cmd)
2680 {
2681   unformat_input_t _line_input, *line_input = &_line_input;
2682   u32 domain_id = 0;
2683   u32 src_port = 0;
2684   u8 enable = 1;
2685   int rv = 0;
2686   clib_error_t *error = 0;
2687
2688   /* Get a line of input. */
2689   if (!unformat_user (input, unformat_line_input, line_input))
2690     return 0;
2691
2692   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2693     {
2694       if (unformat (line_input, "domain %d", &domain_id))
2695         ;
2696       else if (unformat (line_input, "src-port %d", &src_port))
2697         ;
2698       else if (unformat (line_input, "disable"))
2699         enable = 0;
2700       else
2701         {
2702           error = clib_error_return (0, "unknown input '%U'",
2703             format_unformat_error, line_input);
2704           goto done;
2705         }
2706      }
2707
2708   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2709
2710   if (rv)
2711     {
2712       error = clib_error_return (0, "ipfix logging enable failed");
2713       goto done;
2714     }
2715
2716 done:
2717   unformat_free (line_input);
2718
2719   return error;
2720 }
2721
2722 /*?
2723  * @cliexpar
2724  * @cliexstart{snat ipfix logging}
2725  * To enable NAT IPFIX logging use:
2726  *  vpp# nat ipfix logging
2727  * To set IPFIX exporter use:
2728  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2729  * @cliexend
2730 ?*/
2731 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2732   .path = "nat ipfix logging",
2733   .function = snat_ipfix_logging_enable_disable_command_fn,
2734   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2735 };
2736
2737 static u32
2738 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2739 {
2740   snat_main_t *sm = &snat_main;
2741   u32 next_worker_index = 0;
2742   u32 hash;
2743
2744   next_worker_index = sm->first_worker_index;
2745   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2746          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2747
2748   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2749     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2750   else
2751     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2752
2753   return next_worker_index;
2754 }
2755
2756 static u32
2757 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2758 {
2759   snat_main_t *sm = &snat_main;
2760   udp_header_t *udp;
2761   u16 port;
2762   snat_session_key_t m_key;
2763   clib_bihash_kv_8_8_t kv, value;
2764   snat_static_mapping_t *m;
2765   nat_ed_ses_key_t key;
2766   clib_bihash_kv_16_8_t s_kv, s_value;
2767   snat_main_per_thread_data_t *tsm;
2768   snat_session_t *s;
2769   int i;
2770   u32 proto;
2771   u32 next_worker_index = 0;
2772
2773   /* first try static mappings without port */
2774   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2775     {
2776       m_key.addr = ip0->dst_address;
2777       m_key.port = 0;
2778       m_key.protocol = 0;
2779       m_key.fib_index = rx_fib_index0;
2780       kv.key = m_key.as_u64;
2781       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2782         {
2783           m = pool_elt_at_index (sm->static_mappings, value.value);
2784           return m->worker_index;
2785         }
2786     }
2787
2788   proto = ip_proto_to_snat_proto (ip0->protocol);
2789   udp = ip4_next_header (ip0);
2790   port = udp->dst_port;
2791
2792   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2793     {
2794       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2795         return vlib_get_thread_index ();
2796
2797       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2798         {
2799           nat_reass_ip4_t *reass;
2800
2801           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2802                                       ip0->fragment_id, ip0->protocol);
2803
2804           if (reass && (reass->thread_index != (u32) ~ 0))
2805             return reass->thread_index;
2806           else
2807             return vlib_get_thread_index ();
2808         }
2809     }
2810
2811   /* unknown protocol */
2812   if (PREDICT_FALSE (proto == ~0))
2813     {
2814       key.l_addr = ip0->dst_address;
2815       key.r_addr = ip0->src_address;
2816       key.fib_index = rx_fib_index0;
2817       key.proto = ip0->protocol;
2818       key.r_port = 0;
2819       key.l_port = 0;
2820       s_kv.key[0] = key.as_u64[0];
2821       s_kv.key[1] = key.as_u64[1];
2822
2823       if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2824         {
2825           for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2826             {
2827               tsm = vec_elt_at_index (sm->per_thread_data, i);
2828               if (!pool_is_free_index(tsm->sessions, s_value.value))
2829                 {
2830                   s = pool_elt_at_index (tsm->sessions, s_value.value);
2831                   if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2832                       s->out2in.port == ip0->protocol &&
2833                       snat_is_unk_proto_session (s))
2834                     return i;
2835                 }
2836             }
2837          }
2838
2839       /* if no session use current thread */
2840       return vlib_get_thread_index ();
2841     }
2842
2843   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2844     {
2845       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2846       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2847       if (!icmp_is_error_message (icmp))
2848         port = echo->identifier;
2849       else
2850         {
2851           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2852           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2853           void *l4_header = ip4_next_header (inner_ip);
2854           switch (proto)
2855             {
2856             case SNAT_PROTOCOL_ICMP:
2857               icmp = (icmp46_header_t*)l4_header;
2858               echo = (icmp_echo_header_t *)(icmp + 1);
2859               port = echo->identifier;
2860               break;
2861             case SNAT_PROTOCOL_UDP:
2862             case SNAT_PROTOCOL_TCP:
2863               port = ((tcp_udp_header_t*)l4_header)->src_port;
2864               break;
2865             default:
2866               return vlib_get_thread_index ();
2867             }
2868         }
2869     }
2870
2871   /* try static mappings with port */
2872   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2873     {
2874       m_key.addr = ip0->dst_address;
2875       m_key.port = clib_net_to_host_u16 (port);
2876       m_key.protocol = proto;
2877       m_key.fib_index = rx_fib_index0;
2878       kv.key = m_key.as_u64;
2879       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2880         {
2881           m = pool_elt_at_index (sm->static_mappings, value.value);
2882           return m->worker_index;
2883         }
2884     }
2885
2886   /* worker by outside port */
2887   next_worker_index = sm->first_worker_index;
2888   next_worker_index +=
2889     sm->workers[(clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread];
2890   return next_worker_index;
2891 }
2892
2893 static clib_error_t *
2894 snat_config (vlib_main_t * vm, unformat_input_t * input)
2895 {
2896   snat_main_t * sm = &snat_main;
2897   u32 translation_buckets = 1024;
2898   u32 translation_memory_size = 128<<20;
2899   u32 user_buckets = 128;
2900   u32 user_memory_size = 64<<20;
2901   u32 max_translations_per_user = 100;
2902   u32 outside_vrf_id = 0;
2903   u32 inside_vrf_id = 0;
2904   u32 static_mapping_buckets = 1024;
2905   u32 static_mapping_memory_size = 64<<20;
2906   u32 nat64_bib_buckets = 1024;
2907   u32 nat64_bib_memory_size = 128 << 20;
2908   u32 nat64_st_buckets = 2048;
2909   u32 nat64_st_memory_size = 256 << 20;
2910   u8 static_mapping_only = 0;
2911   u8 static_mapping_connection_tracking = 0;
2912   snat_main_per_thread_data_t *tsm;
2913   dslite_main_t * dm = &dslite_main;
2914
2915   sm->deterministic = 0;
2916   sm->out2in_dpo = 0;
2917
2918   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2919     {
2920       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2921         ;
2922       else if (unformat (input, "translation hash memory %d",
2923                          &translation_memory_size));
2924       else if (unformat (input, "user hash buckets %d", &user_buckets))
2925         ;
2926       else if (unformat (input, "user hash memory %d",
2927                          &user_memory_size))
2928         ;
2929       else if (unformat (input, "max translations per user %d",
2930                          &max_translations_per_user))
2931         ;
2932       else if (unformat (input, "outside VRF id %d",
2933                          &outside_vrf_id))
2934         ;
2935       else if (unformat (input, "inside VRF id %d",
2936                          &inside_vrf_id))
2937         ;
2938       else if (unformat (input, "static mapping only"))
2939         {
2940           static_mapping_only = 1;
2941           if (unformat (input, "connection tracking"))
2942             static_mapping_connection_tracking = 1;
2943         }
2944       else if (unformat (input, "deterministic"))
2945         sm->deterministic = 1;
2946       else if (unformat (input, "nat64 bib hash buckets %d",
2947                          &nat64_bib_buckets))
2948         ;
2949       else if (unformat (input, "nat64 bib hash memory %d",
2950                          &nat64_bib_memory_size))
2951         ;
2952       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2953         ;
2954       else if (unformat (input, "nat64 st hash memory %d",
2955                          &nat64_st_memory_size))
2956         ;
2957       else if (unformat (input, "out2in dpo"))
2958         sm->out2in_dpo = 1;
2959       else if (unformat (input, "dslite ce"))
2960         dslite_set_ce(dm, 1);
2961       else
2962         return clib_error_return (0, "unknown input '%U'",
2963                                   format_unformat_error, input);
2964     }
2965
2966   /* for show commands, etc. */
2967   sm->translation_buckets = translation_buckets;
2968   sm->translation_memory_size = translation_memory_size;
2969   /* do not exceed load factor 10 */
2970   sm->max_translations = 10 * translation_buckets;
2971   sm->user_buckets = user_buckets;
2972   sm->user_memory_size = user_memory_size;
2973   sm->max_translations_per_user = max_translations_per_user;
2974   sm->outside_vrf_id = outside_vrf_id;
2975   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2976                                                              outside_vrf_id,
2977                                                              FIB_SOURCE_PLUGIN_HI);
2978   sm->inside_vrf_id = inside_vrf_id;
2979   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2980                                                             inside_vrf_id,
2981                                                             FIB_SOURCE_PLUGIN_HI);
2982   sm->static_mapping_only = static_mapping_only;
2983   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2984
2985   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2986                  nat64_st_memory_size);
2987
2988   if (sm->deterministic)
2989     {
2990       sm->in2out_node_index = snat_det_in2out_node.index;
2991       sm->in2out_output_node_index = ~0;
2992       sm->out2in_node_index = snat_det_out2in_node.index;
2993       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2994       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2995     }
2996   else
2997     {
2998       sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2999       sm->worker_out2in_cb = snat_get_worker_out2in_cb;
3000       sm->in2out_node_index = snat_in2out_node.index;
3001       sm->in2out_output_node_index = snat_in2out_output_node.index;
3002       sm->out2in_node_index = snat_out2in_node.index;
3003       if (!static_mapping_only ||
3004           (static_mapping_only && static_mapping_connection_tracking))
3005         {
3006           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
3007           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
3008
3009           vec_foreach (tsm, sm->per_thread_data)
3010             {
3011               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
3012                                     translation_memory_size);
3013
3014               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
3015                                     translation_memory_size);
3016
3017               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
3018                                     user_memory_size);
3019             }
3020
3021           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
3022                                  translation_buckets, translation_memory_size);
3023
3024           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
3025                                  translation_buckets, translation_memory_size);
3026         }
3027       else
3028         {
3029           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
3030           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
3031         }
3032       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
3033                             "static_mapping_by_local", static_mapping_buckets,
3034                             static_mapping_memory_size);
3035
3036       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
3037                             "static_mapping_by_external", static_mapping_buckets,
3038                             static_mapping_memory_size);
3039     }
3040
3041   return 0;
3042 }
3043
3044 VLIB_CONFIG_FUNCTION (snat_config, "nat");
3045
3046 u8 * format_snat_session_state (u8 * s, va_list * args)
3047 {
3048   u32 i = va_arg (*args, u32);
3049   u8 *t = 0;
3050
3051   switch (i)
3052     {
3053 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
3054     foreach_snat_session_state
3055 #undef _
3056     default:
3057       t = format (t, "unknown");
3058     }
3059   s = format (s, "%s", t);
3060   return s;
3061 }
3062
3063 u8 * format_snat_key (u8 * s, va_list * args)
3064 {
3065   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
3066
3067   s = format (s, "%U proto %U port %d fib %d",
3068               format_ip4_address, &key->addr,
3069               format_snat_protocol, key->protocol,
3070               clib_net_to_host_u16 (key->port), key->fib_index);
3071   return s;
3072 }
3073
3074 u8 * format_snat_session (u8 * s, va_list * args)
3075 {
3076   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
3077   snat_session_t * sess = va_arg (*args, snat_session_t *);
3078
3079   if (snat_is_unk_proto_session (sess))
3080     {
3081       s = format (s, "  i2o %U proto %u fib %u\n",
3082                   format_ip4_address, &sess->in2out.addr,
3083                   clib_net_to_host_u16 (sess->in2out.port),
3084                   sess->in2out.fib_index);
3085       s = format (s, "    o2i %U proto %u fib %u\n",
3086                   format_ip4_address, &sess->out2in.addr,
3087                   clib_net_to_host_u16 (sess->out2in.port),
3088                   sess->out2in.fib_index);
3089     }
3090   else
3091     {
3092       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
3093       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
3094     }
3095   if (is_twice_nat_session (sess))
3096     {
3097       s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
3098                   format_ip4_address, &sess->ext_host_addr,
3099                   clib_net_to_host_u16 (sess->ext_host_port),
3100                   format_ip4_address, &sess->ext_host_nat_addr,
3101                   clib_net_to_host_u16 (sess->ext_host_nat_port));
3102     }
3103   else
3104     {
3105       if (sess->ext_host_addr.as_u32)
3106           s = format (s, "       external host %U\n",
3107                       format_ip4_address, &sess->ext_host_addr);
3108     }
3109   s = format (s, "       last heard %.2f\n", sess->last_heard);
3110   s = format (s, "       total pkts %d, total bytes %lld\n",
3111               sess->total_pkts, sess->total_bytes);
3112   if (snat_is_session_static (sess))
3113     s = format (s, "       static translation\n");
3114   else
3115     s = format (s, "       dynamic translation\n");
3116   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
3117     s = format (s, "       load-balancing\n");
3118   if (is_twice_nat_session (sess))
3119     s = format (s, "       twice-nat\n");
3120
3121   return s;
3122 }
3123
3124 u8 * format_snat_user (u8 * s, va_list * args)
3125 {
3126   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
3127   snat_user_t * u = va_arg (*args, snat_user_t *);
3128   int verbose = va_arg (*args, int);
3129   dlist_elt_t * head, * elt;
3130   u32 elt_index, head_index;
3131   u32 session_index;
3132   snat_session_t * sess;
3133
3134   s = format (s, "%U: %d dynamic translations, %d static translations\n",
3135               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
3136
3137   if (verbose == 0)
3138     return s;
3139
3140   if (u->nsessions || u->nstaticsessions)
3141     {
3142       head_index = u->sessions_per_user_list_head_index;
3143       head = pool_elt_at_index (sm->list_pool, head_index);
3144
3145       elt_index = head->next;
3146       elt = pool_elt_at_index (sm->list_pool, elt_index);
3147       session_index = elt->value;
3148
3149       while (session_index != ~0)
3150         {
3151           sess = pool_elt_at_index (sm->sessions, session_index);
3152
3153           s = format (s, "  %U\n", format_snat_session, sm, sess);
3154
3155           elt_index = elt->next;
3156           elt = pool_elt_at_index (sm->list_pool, elt_index);
3157           session_index = elt->value;
3158         }
3159     }
3160
3161   return s;
3162 }
3163
3164 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3165 {
3166   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3167   nat44_lb_addr_port_t *local;
3168
3169   if (m->addr_only)
3170       s = format (s, "local %U external %U vrf %d %s",
3171                   format_ip4_address, &m->local_addr,
3172                   format_ip4_address, &m->external_addr,
3173                   m->vrf_id, m->twice_nat ? "twice-nat" : "");
3174   else
3175    {
3176       if (vec_len (m->locals))
3177         {
3178           s = format (s, "%U vrf %d external %U:%d %s",
3179                       format_snat_protocol, m->proto,
3180                       m->vrf_id,
3181                       format_ip4_address, &m->external_addr, m->external_port,
3182                       m->twice_nat ? "twice-nat" : "");
3183           vec_foreach (local, m->locals)
3184             s = format (s, "\n  local %U:%d probability %d\%",
3185                         format_ip4_address, &local->addr, local->port,
3186                         local->probability);
3187         }
3188       else
3189         s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
3190                     format_snat_protocol, m->proto,
3191                     format_ip4_address, &m->local_addr, m->local_port,
3192                     format_ip4_address, &m->external_addr, m->external_port,
3193                     m->vrf_id, m->twice_nat ? "twice-nat" : "");
3194    }
3195   return s;
3196 }
3197
3198 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3199 {
3200   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
3201   vnet_main_t *vnm = vnet_get_main();
3202
3203   if (m->addr_only)
3204       s = format (s, "local %U external %U vrf %d",
3205                   format_ip4_address, &m->l_addr,
3206                   format_vnet_sw_interface_name, vnm,
3207                   vnet_get_sw_interface (vnm, m->sw_if_index),
3208                   m->vrf_id);
3209   else
3210       s = format (s, "%U local %U:%d external %U:%d vrf %d",
3211                   format_snat_protocol, m->proto,
3212                   format_ip4_address, &m->l_addr, m->l_port,
3213                   format_vnet_sw_interface_name, vnm,
3214                   vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
3215                   m->vrf_id);
3216
3217   return s;
3218 }
3219
3220 u8 * format_det_map_ses (u8 * s, va_list * args)
3221 {
3222   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3223   ip4_address_t in_addr, out_addr;
3224   u32 in_offset, out_offset;
3225   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3226   u32 * i = va_arg (*args, u32 *);
3227
3228   u32 user_index = *i / SNAT_DET_SES_PER_USER;
3229   in_addr.as_u32 = clib_host_to_net_u32 (
3230     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3231   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3232     clib_net_to_host_u32(det_map->in_addr.as_u32);
3233   out_offset = in_offset / det_map->sharing_ratio;
3234   out_addr.as_u32 = clib_host_to_net_u32(
3235     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3236   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3237               format_ip4_address, &in_addr,
3238               clib_net_to_host_u16 (ses->in_port),
3239               format_ip4_address, &out_addr,
3240               clib_net_to_host_u16 (ses->out.out_port),
3241               format_ip4_address, &ses->out.ext_host_addr,
3242               clib_net_to_host_u16 (ses->out.ext_host_port),
3243               format_snat_session_state, ses->state,
3244               ses->expire);
3245
3246   return s;
3247 }
3248
3249 static clib_error_t *
3250 show_snat_command_fn (vlib_main_t * vm,
3251                  unformat_input_t * input,
3252                  vlib_cli_command_t * cmd)
3253 {
3254   int verbose = 0;
3255   snat_main_t * sm = &snat_main;
3256   snat_user_t * u;
3257   snat_static_mapping_t *m;
3258   snat_interface_t *i;
3259   snat_address_t * ap;
3260   vnet_main_t *vnm = vnet_get_main();
3261   snat_main_per_thread_data_t *tsm;
3262   u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
3263   uword j = 0;
3264   snat_static_map_resolve_t *rp;
3265   snat_det_map_t * dm;
3266   snat_det_session_t * ses;
3267
3268   if (unformat (input, "detail"))
3269     verbose = 1;
3270   else if (unformat (input, "verbose"))
3271     verbose = 2;
3272
3273   if (sm->static_mapping_only)
3274     {
3275       if (sm->static_mapping_connection_tracking)
3276         vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
3277                          "tracking");
3278       else
3279         vlib_cli_output (vm, "NAT plugin mode: static mapping only");
3280     }
3281   else if (sm->deterministic)
3282     {
3283       vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
3284     }
3285   else
3286     {
3287       vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
3288     }
3289
3290   if (verbose > 0)
3291     {
3292       pool_foreach (i, sm->interfaces,
3293       ({
3294         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
3295                          vnet_get_sw_interface (vnm, i->sw_if_index),
3296                          (nat_interface_is_inside(i) &&
3297                           nat_interface_is_outside(i)) ? "in out" :
3298                          (nat_interface_is_inside(i) ? "in" : "out"));
3299       }));
3300
3301       pool_foreach (i, sm->output_feature_interfaces,
3302       ({
3303         vlib_cli_output (vm, "%U output-feature %s",
3304                          format_vnet_sw_interface_name, vnm,
3305                          vnet_get_sw_interface (vnm, i->sw_if_index),
3306                          (nat_interface_is_inside(i) &&
3307                           nat_interface_is_outside(i)) ? "in out" :
3308                          (nat_interface_is_inside(i) ? "in" : "out"));
3309       }));
3310
3311       if (vec_len (sm->auto_add_sw_if_indices))
3312         {
3313           vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
3314           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
3315             {
3316               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
3317                                vnet_get_sw_interface (vnm, *sw_if_index));
3318             }
3319         }
3320
3321       if (vec_len (sm->auto_add_sw_if_indices_twice_nat))
3322         {
3323           vlib_cli_output (vm, "NAT44 twice-nat pool addresses interfaces:");
3324           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
3325             {
3326               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
3327                                vnet_get_sw_interface (vnm, *sw_if_index));
3328             }
3329         }
3330
3331       vlib_cli_output (vm, "NAT44 pool addresses:");
3332       vec_foreach (ap, sm->addresses)
3333         {
3334           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3335           if (ap->fib_index != ~0)
3336               vlib_cli_output (vm, "  tenant VRF: %u",
3337                                ip4_fib_get(ap->fib_index)->table_id);
3338           else
3339             vlib_cli_output (vm, "  tenant VRF independent");
3340 #define _(N, i, n, s) \
3341           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
3342           foreach_snat_protocol
3343 #undef _
3344         }
3345
3346       vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
3347       vec_foreach (ap, sm->twice_nat_addresses)
3348         {
3349           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3350           if (ap->fib_index != ~0)
3351               vlib_cli_output (vm, "  tenant VRF: %u",
3352                                ip4_fib_get(ap->fib_index)->table_id);
3353           else
3354             vlib_cli_output (vm, "  tenant VRF independent");
3355 #define _(N, i, n, s) \
3356           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
3357           foreach_snat_protocol
3358 #undef _
3359         }
3360     }
3361
3362   if (sm->num_workers > 1)
3363     {
3364       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
3365       if (verbose > 0)
3366         {
3367           vec_foreach (worker, sm->workers)
3368             {
3369               vlib_worker_thread_t *w =
3370                 vlib_worker_threads + *worker + sm->first_worker_index;
3371               vlib_cli_output (vm, "  %s", w->name);
3372             }
3373         }
3374     }
3375
3376   if (sm->deterministic)
3377     {
3378       vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
3379       vlib_cli_output (vm, "tcp-established timeout: %dsec",
3380                        sm->tcp_established_timeout);
3381       vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
3382                        sm->tcp_transitory_timeout);
3383       vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
3384       vlib_cli_output (vm, "%d deterministic mappings",
3385                        pool_elts (sm->det_maps));
3386       if (verbose > 0)
3387         {
3388           pool_foreach (dm, sm->det_maps,
3389           ({
3390             vlib_cli_output (vm, "in %U/%d out %U/%d\n",
3391                              format_ip4_address, &dm->in_addr, dm->in_plen,
3392                              format_ip4_address, &dm->out_addr, dm->out_plen);
3393             vlib_cli_output (vm, " outside address sharing ratio: %d\n",
3394                              dm->sharing_ratio);
3395             vlib_cli_output (vm, " number of ports per inside host: %d\n",
3396                              dm->ports_per_host);
3397             vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
3398             if (verbose > 1)
3399               {
3400                 vec_foreach_index (j, dm->sessions)
3401                   {
3402                     ses = vec_elt_at_index (dm->sessions, j);
3403                     if (ses->in_port)
3404                       vlib_cli_output (vm, "  %U", format_det_map_ses, dm, ses,
3405                                        &j);
3406                   }
3407               }
3408           }));
3409         }
3410     }
3411   else
3412     {
3413       if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
3414         {
3415           vlib_cli_output (vm, "%d static mappings",
3416                            pool_elts (sm->static_mappings));
3417
3418           if (verbose > 0)
3419             {
3420               pool_foreach (m, sm->static_mappings,
3421               ({
3422                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3423               }));
3424             }
3425         }
3426       else
3427         {
3428           vec_foreach (tsm, sm->per_thread_data)
3429             {
3430               users_num += pool_elts (tsm->users);
3431               sessions_num += pool_elts (tsm->sessions);
3432             }
3433
3434           vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3435                            " %d static mappings, %d twice-nat addresses",
3436                            users_num,
3437                            vec_len (sm->addresses),
3438                            sessions_num,
3439                            pool_elts (sm->static_mappings),
3440                            vec_len (sm->twice_nat_addresses));
3441
3442           if (verbose > 0)
3443             {
3444               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3445                                verbose - 1);
3446               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3447                                verbose - 1);
3448               vec_foreach_index (j, sm->per_thread_data)
3449                 {
3450                   tsm = vec_elt_at_index (sm->per_thread_data, j);
3451
3452                   if (pool_elts (tsm->users) == 0)
3453                     continue;
3454
3455                   vlib_worker_thread_t *w = vlib_worker_threads + j;
3456                   vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3457                                    w->lcore_id);
3458                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->in2out,
3459                                    verbose - 1);
3460                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->out2in,
3461                                    verbose - 1);
3462                   vlib_cli_output (vm, "  %d list pool elements",
3463                                    pool_elts (tsm->list_pool));
3464
3465                   pool_foreach (u, tsm->users,
3466                   ({
3467                     vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
3468                                      verbose - 1);
3469                   }));
3470                 }
3471
3472               if (pool_elts (sm->static_mappings))
3473                 {
3474                   vlib_cli_output (vm, "static mappings:");
3475                   pool_foreach (m, sm->static_mappings,
3476                   ({
3477                     vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3478                   }));
3479                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3480                     {
3481                       rp = sm->to_resolve + j;
3482                       vlib_cli_output (vm, "%U",
3483                                        format_snat_static_map_to_resolve, rp);
3484                     }
3485                 }
3486             }
3487         }
3488     }
3489
3490   return 0;
3491 }
3492
3493 VLIB_CLI_COMMAND (show_snat_command, static) = {
3494     .path = "show nat44",
3495     .short_help = "show nat44",
3496     .function = show_snat_command_fn,
3497 };
3498
3499
3500 static void
3501 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3502                                        uword opaque,
3503                                        u32 sw_if_index,
3504                                        ip4_address_t * address,
3505                                        u32 address_length,
3506                                        u32 if_address_index,
3507                                        u32 is_delete)
3508 {
3509   snat_main_t *sm = &snat_main;
3510   snat_static_map_resolve_t *rp;
3511   u32 *indices_to_delete = 0;
3512   ip4_address_t l_addr;
3513   int i, j;
3514   int rv;
3515   u8 twice_nat = 0;
3516   snat_address_t *addresses = sm->addresses;
3517
3518   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3519     {
3520       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3521           goto match;
3522     }
3523
3524   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3525     {
3526       twice_nat = 1;
3527       addresses = sm->twice_nat_addresses;
3528       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3529           goto match;
3530     }
3531
3532   return;
3533
3534 match:
3535   if (!is_delete)
3536     {
3537       /* Don't trip over lease renewal, static config */
3538       for (j = 0; j < vec_len(addresses); j++)
3539         if (addresses[j].addr.as_u32 == address->as_u32)
3540           return;
3541
3542       snat_add_address (sm, address, ~0, twice_nat);
3543       /* Scan static map resolution vector */
3544       for (j = 0; j < vec_len (sm->to_resolve); j++)
3545         {
3546           rp = sm->to_resolve + j;
3547           /* On this interface? */
3548           if (rp->sw_if_index == sw_if_index)
3549             {
3550               /* Indetity mapping? */
3551               if (rp->l_addr.as_u32 == 0)
3552                 l_addr.as_u32 = address[0].as_u32;
3553               else
3554                 l_addr.as_u32 = rp->l_addr.as_u32;
3555               /* Add the static mapping */
3556               rv = snat_add_static_mapping (l_addr,
3557                                             address[0],
3558                                             rp->l_port,
3559                                             rp->e_port,
3560                                             rp->vrf_id,
3561                                             rp->addr_only,
3562                                             ~0 /* sw_if_index */,
3563                                             rp->proto,
3564                                             rp->is_add,
3565                                             0);
3566               if (rv)
3567                 clib_warning ("snat_add_static_mapping returned %d",
3568                               rv);
3569               vec_add1 (indices_to_delete, j);
3570             }
3571         }
3572       /* If we resolved any of the outstanding static mappings */
3573       if (vec_len(indices_to_delete))
3574         {
3575           /* Delete them */
3576           for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3577             vec_delete(sm->to_resolve, 1, j);
3578           vec_free(indices_to_delete);
3579         }
3580       return;
3581     }
3582   else
3583     {
3584       (void) snat_del_address(sm, address[0], 1, twice_nat);
3585       return;
3586     }
3587 }
3588
3589
3590 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3591                                 u8 twice_nat)
3592 {
3593   ip4_main_t * ip4_main = sm->ip4_main;
3594   ip4_address_t * first_int_addr;
3595   snat_static_map_resolve_t *rp;
3596   u32 *indices_to_delete = 0;
3597   int i, j;
3598   u32 *auto_add_sw_if_indices =
3599     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3600
3601   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3602                                                 0 /* just want the address*/);
3603
3604   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3605     {
3606       if (auto_add_sw_if_indices[i] == sw_if_index)
3607         {
3608           if (is_del)
3609             {
3610               /* if have address remove it */
3611               if (first_int_addr)
3612                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3613               else
3614                 {
3615                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3616                     {
3617                       rp = sm->to_resolve + j;
3618                       if (rp->sw_if_index == sw_if_index)
3619                         vec_add1 (indices_to_delete, j);
3620                     }
3621                   if (vec_len(indices_to_delete))
3622                     {
3623                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3624                         vec_del1(sm->to_resolve, j);
3625                       vec_free(indices_to_delete);
3626                     }
3627                 }
3628               if (twice_nat)
3629                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
3630               else
3631                 vec_del1(sm->auto_add_sw_if_indices, i);
3632             }
3633           else
3634             return VNET_API_ERROR_VALUE_EXIST;
3635
3636           return 0;
3637         }
3638     }
3639
3640   if (is_del)
3641     return VNET_API_ERROR_NO_SUCH_ENTRY;
3642
3643   /* add to the auto-address list */
3644   if (twice_nat)
3645     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3646   else
3647     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3648
3649   /* If the address is already bound - or static - add it now */
3650   if (first_int_addr)
3651       snat_add_address (sm, first_int_addr, ~0, twice_nat);
3652
3653   return 0;
3654 }
3655
3656 static clib_error_t *
3657 snat_add_interface_address_command_fn (vlib_main_t * vm,
3658                                        unformat_input_t * input,
3659                                        vlib_cli_command_t * cmd)
3660 {
3661   snat_main_t *sm = &snat_main;
3662   unformat_input_t _line_input, *line_input = &_line_input;
3663   u32 sw_if_index;
3664   int rv;
3665   int is_del = 0;
3666   clib_error_t *error = 0;
3667   u8 twice_nat = 0;
3668
3669   /* Get a line of input. */
3670   if (!unformat_user (input, unformat_line_input, line_input))
3671     return 0;
3672
3673   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3674     {
3675       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3676                     sm->vnet_main, &sw_if_index))
3677         ;
3678       else if (unformat (line_input, "twice-nat"))
3679         twice_nat = 1;
3680       else if (unformat (line_input, "del"))
3681         is_del = 1;
3682       else
3683         {
3684           error = clib_error_return (0, "unknown input '%U'",
3685                                      format_unformat_error, line_input);
3686           goto done;
3687         }
3688     }
3689
3690   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
3691
3692   switch (rv)
3693     {
3694     case 0:
3695       break;
3696
3697     default:
3698       error = clib_error_return (0, "snat_add_interface_address returned %d",
3699                                  rv);
3700       goto done;
3701     }
3702
3703 done:
3704   unformat_free (line_input);
3705
3706   return error;
3707 }
3708
3709 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3710     .path = "nat44 add interface address",
3711     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
3712     .function = snat_add_interface_address_command_fn,
3713 };
3714
3715 int
3716 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3717                    snat_protocol_t proto, u32 vrf_id, int is_in)
3718 {
3719   snat_main_per_thread_data_t *tsm;
3720   clib_bihash_kv_8_8_t kv, value;
3721   ip4_header_t ip;
3722   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3723   snat_session_key_t key;
3724   snat_session_t *s;
3725   clib_bihash_8_8_t *t;
3726   snat_user_key_t u_key;
3727   snat_user_t *u;
3728
3729   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3730   if (sm->num_workers)
3731     tsm =
3732       vec_elt_at_index (sm->per_thread_data,
3733                         sm->worker_in2out_cb (&ip, fib_index));
3734   else
3735     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3736
3737   key.addr.as_u32 = addr->as_u32;
3738   key.port = clib_host_to_net_u16 (port);
3739   key.protocol = proto;
3740   key.fib_index = fib_index;
3741   kv.key = key.as_u64;
3742   t = is_in ? &tsm->in2out : &tsm->out2in;
3743   if (!clib_bihash_search_8_8 (t, &kv, &value))
3744     {
3745       s = pool_elt_at_index (tsm->sessions, value.value);
3746       kv.key = s->in2out.as_u64;
3747       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3748       kv.key = s->out2in.as_u64;
3749       clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3750       u_key.addr = s->in2out.addr;
3751       u_key.fib_index = s->in2out.fib_index;
3752       kv.key = u_key.as_u64;
3753       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3754         {
3755           u = pool_elt_at_index (tsm->users, value.value);
3756           u->nsessions--;
3757         }
3758       clib_dlist_remove (tsm->list_pool, s->per_user_index);
3759       pool_put (tsm->sessions, s);
3760       return 0;
3761     }
3762
3763   return VNET_API_ERROR_NO_SUCH_ENTRY;
3764 }
3765
3766 static clib_error_t *
3767 nat44_del_session_command_fn (vlib_main_t * vm,
3768                               unformat_input_t * input,
3769                               vlib_cli_command_t * cmd)
3770 {
3771   snat_main_t *sm = &snat_main;
3772   unformat_input_t _line_input, *line_input = &_line_input;
3773   int is_in = 0;
3774   clib_error_t *error = 0;
3775   ip4_address_t addr;
3776   u32 port = 0, vrf_id = sm->outside_vrf_id;
3777   snat_protocol_t proto;
3778   int rv;
3779
3780   /* Get a line of input. */
3781   if (!unformat_user (input, unformat_line_input, line_input))
3782     return 0;
3783
3784   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3785     {
3786       if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3787           unformat_snat_protocol, &proto))
3788         ;
3789       else if (unformat (line_input, "in"))
3790         {
3791           is_in = 1;
3792           vrf_id = sm->inside_vrf_id;
3793         }
3794       else if (unformat (line_input, "vrf %u", &vrf_id))
3795         ;
3796       else
3797         {
3798           error = clib_error_return (0, "unknown input '%U'",
3799                                      format_unformat_error, line_input);
3800           goto done;
3801         }
3802     }
3803
3804   rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3805
3806   switch (rv)
3807     {
3808     case 0:
3809       break;
3810
3811     default:
3812       error = clib_error_return (0, "nat44_del_session returned %d", rv);
3813       goto done;
3814     }
3815
3816 done:
3817   unformat_free (line_input);
3818
3819   return error;
3820 }
3821
3822 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3823     .path = "nat44 del session",
3824     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3825     .function = nat44_del_session_command_fn,
3826 };
3827
3828 static clib_error_t *
3829 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
3830                                               unformat_input_t * input,
3831                                               vlib_cli_command_t * cmd)
3832 {
3833   snat_main_t *sm = &snat_main;
3834   unformat_input_t _line_input, *line_input = &_line_input;
3835   clib_error_t *error = 0;
3836   u32 psid, psid_offset, psid_length;
3837
3838   /* Get a line of input. */
3839   if (!unformat_user (input, unformat_line_input, line_input))
3840     return 0;
3841
3842   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3843     {
3844       if (unformat (line_input, "default"))
3845         sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3846       else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3847                &psid, &psid_offset, &psid_length))
3848         {
3849           sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3850           sm->psid = (u16) psid;
3851           sm->psid_offset = (u16) psid_offset;
3852           sm->psid_length = (u16) psid_length;
3853         }
3854       else
3855         {
3856           error = clib_error_return (0, "unknown input '%U'",
3857                                      format_unformat_error, line_input);
3858           goto done;
3859         }
3860     }
3861
3862 done:
3863   unformat_free (line_input);
3864
3865   return error;
3866 };
3867
3868 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3869     .path = "nat addr-port-assignment-alg",
3870     .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
3871     .function = nat44_set_alloc_addr_and_port_alg_command_fn,
3872 };
3873
3874 static clib_error_t *
3875 snat_det_map_command_fn (vlib_main_t * vm,
3876                          unformat_input_t * input,
3877                          vlib_cli_command_t * cmd)
3878 {
3879   snat_main_t *sm = &snat_main;
3880   unformat_input_t _line_input, *line_input = &_line_input;
3881   ip4_address_t in_addr, out_addr;
3882   u32 in_plen, out_plen;
3883   int is_add = 1, rv;
3884   clib_error_t *error = 0;
3885
3886   /* Get a line of input. */
3887   if (!unformat_user (input, unformat_line_input, line_input))
3888     return 0;
3889
3890   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3891     {
3892       if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3893         ;
3894       else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3895         ;
3896       else if (unformat (line_input, "del"))
3897         is_add = 0;
3898       else
3899         {
3900           error = clib_error_return (0, "unknown input '%U'",
3901                                      format_unformat_error, line_input);
3902           goto done;
3903         }
3904     }
3905
3906   rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3907                         is_add);
3908
3909   if (rv)
3910     {
3911       error = clib_error_return (0, "snat_det_add_map return %d", rv);
3912       goto done;
3913     }
3914
3915 done:
3916   unformat_free (line_input);
3917
3918   return error;
3919 }
3920
3921 /*?
3922  * @cliexpar
3923  * @cliexstart{snat deterministic add}
3924  * Create bijective mapping of inside address to outside address and port range
3925  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3926  * CGN deployments.
3927  * To create deterministic mapping between inside network 10.0.0.0/18 and
3928  * outside network 1.1.1.0/30 use:
3929  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3930  * @cliexend
3931 ?*/
3932 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3933     .path = "nat44 deterministic add",
3934     .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3935     .function = snat_det_map_command_fn,
3936 };
3937
3938 static clib_error_t *
3939 snat_det_forward_command_fn (vlib_main_t * vm,
3940                              unformat_input_t * input,
3941                              vlib_cli_command_t * cmd)
3942 {
3943   snat_main_t *sm = &snat_main;
3944   unformat_input_t _line_input, *line_input = &_line_input;
3945   ip4_address_t in_addr, out_addr;
3946   u16 lo_port;
3947   snat_det_map_t * dm;
3948   clib_error_t *error = 0;
3949
3950   /* Get a line of input. */
3951   if (!unformat_user (input, unformat_line_input, line_input))
3952     return 0;
3953
3954   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3955     {
3956       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3957         ;
3958       else
3959         {
3960           error = clib_error_return (0, "unknown input '%U'",
3961                                      format_unformat_error, line_input);
3962           goto done;
3963         }
3964     }
3965
3966   dm = snat_det_map_by_user(sm, &in_addr);
3967   if (!dm)
3968     vlib_cli_output (vm, "no match");
3969   else
3970     {
3971       snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3972       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3973                        lo_port, lo_port + dm->ports_per_host - 1);
3974     }
3975
3976 done:
3977   unformat_free (line_input);
3978
3979   return error;
3980 }
3981
3982 /*?
3983  * @cliexpar
3984  * @cliexstart{snat deterministic forward}
3985  * Return outside address and port range from inside address for deterministic
3986  * NAT.
3987  * To obtain outside address and port of inside host use:
3988  *  vpp# nat44 deterministic forward 10.0.0.2
3989  *  1.1.1.0:<1054-1068>
3990  * @cliexend
3991 ?*/
3992 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3993     .path = "nat44 deterministic forward",
3994     .short_help = "nat44 deterministic forward <addr>",
3995     .function = snat_det_forward_command_fn,
3996 };
3997
3998 static clib_error_t *
3999 snat_det_reverse_command_fn (vlib_main_t * vm,
4000                              unformat_input_t * input,
4001                              vlib_cli_command_t * cmd)
4002 {
4003   snat_main_t *sm = &snat_main;
4004   unformat_input_t _line_input, *line_input = &_line_input;
4005   ip4_address_t in_addr, out_addr;
4006   u32 out_port;
4007   snat_det_map_t * dm;
4008   clib_error_t *error = 0;
4009
4010   /* Get a line of input. */
4011   if (!unformat_user (input, unformat_line_input, line_input))
4012     return 0;
4013
4014   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4015     {
4016       if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
4017         ;
4018       else
4019         {
4020           error =  clib_error_return (0, "unknown input '%U'",
4021                                       format_unformat_error, line_input);
4022           goto done;
4023         }
4024     }
4025
4026   if (out_port < 1024 || out_port > 65535)
4027     {
4028       error = clib_error_return (0, "wrong port, must be <1024-65535>");
4029       goto done;
4030     }
4031
4032   dm = snat_det_map_by_out(sm, &out_addr);
4033   if (!dm)
4034     vlib_cli_output (vm, "no match");
4035   else
4036     {
4037       snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
4038       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
4039     }
4040
4041 done:
4042   unformat_free (line_input);
4043
4044   return error;
4045 }
4046
4047 /*?
4048  * @cliexpar
4049  * @cliexstart{snat deterministic reverse}
4050  * Return inside address from outside address and port for deterministic NAT.
4051  * To obtain inside host address from outside address and port use:
4052  *  #vpp nat44 deterministic reverse 1.1.1.1:1276
4053  *  10.0.16.16
4054  * @cliexend
4055 ?*/
4056 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
4057     .path = "nat44 deterministic reverse",
4058     .short_help = "nat44 deterministic reverse <addr>:<port>",
4059     .function = snat_det_reverse_command_fn,
4060 };
4061
4062 static clib_error_t *
4063 set_timeout_command_fn (vlib_main_t * vm,
4064                         unformat_input_t * input,
4065                         vlib_cli_command_t * cmd)
4066 {
4067   snat_main_t *sm = &snat_main;
4068   unformat_input_t _line_input, *line_input = &_line_input;
4069   clib_error_t *error = 0;
4070
4071   /* Get a line of input. */
4072   if (!unformat_user (input, unformat_line_input, line_input))
4073     return 0;
4074
4075   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4076     {
4077       if (unformat (line_input, "udp %u", &sm->udp_timeout))
4078         ;
4079       else if (unformat (line_input, "tcp-established %u",
4080                &sm->tcp_established_timeout))
4081         ;
4082       else if (unformat (line_input, "tcp-transitory %u",
4083                &sm->tcp_transitory_timeout))
4084         ;
4085       else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
4086         ;
4087       else if (unformat (line_input, "reset"))
4088         {
4089           sm->udp_timeout = SNAT_UDP_TIMEOUT;
4090           sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
4091           sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
4092           sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
4093         }
4094       else
4095         {
4096           error = clib_error_return (0, "unknown input '%U'",
4097                                      format_unformat_error, line_input);
4098           goto done;
4099         }
4100     }
4101
4102 done:
4103   unformat_free (line_input);
4104
4105   return error;
4106 }
4107
4108 /*?
4109  * @cliexpar
4110  * @cliexstart{set snat deterministic timeout}
4111  * Set values of timeouts for deterministic NAT (in seconds), use:
4112  *  vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
4113  *  tcp-transitory 250 icmp 90
4114  * To reset default values use:
4115  *  vpp# set nat44 deterministic timeout reset
4116  * @cliexend
4117 ?*/
4118 VLIB_CLI_COMMAND (set_timeout_command, static) = {
4119   .path = "set nat44 deterministic timeout",
4120   .function = set_timeout_command_fn,
4121   .short_help =
4122     "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
4123     "tcp-transitory <sec> | icmp <sec> | reset]",
4124 };
4125
4126 static clib_error_t *
4127 snat_det_close_session_out_fn (vlib_main_t *vm,
4128                                unformat_input_t * input,
4129                                vlib_cli_command_t * cmd)
4130 {
4131   snat_main_t *sm = &snat_main;
4132   unformat_input_t _line_input, *line_input = &_line_input;
4133   ip4_address_t out_addr, ext_addr, in_addr;
4134   u32 out_port, ext_port;
4135   snat_det_map_t * dm;
4136   snat_det_session_t * ses;
4137   snat_det_out_key_t key;
4138   clib_error_t *error = 0;
4139
4140   /* Get a line of input. */
4141   if (!unformat_user (input, unformat_line_input, line_input))
4142     return 0;
4143
4144   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4145     {
4146       if (unformat (line_input, "%U:%d %U:%d",
4147                     unformat_ip4_address, &out_addr, &out_port,
4148                     unformat_ip4_address, &ext_addr, &ext_port))
4149         ;
4150       else
4151         {
4152           error = clib_error_return (0, "unknown input '%U'",
4153                                      format_unformat_error, line_input);
4154           goto done;
4155         }
4156     }
4157
4158   unformat_free (line_input);
4159
4160   dm = snat_det_map_by_out(sm, &out_addr);
4161   if (!dm)
4162     vlib_cli_output (vm, "no match");
4163   else
4164     {
4165       snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
4166       key.ext_host_addr = out_addr;
4167       key.ext_host_port = ntohs((u16)ext_port);
4168       key.out_port = ntohs((u16)out_port);
4169       ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
4170       if (!ses)
4171         vlib_cli_output (vm, "no match");
4172       else
4173        snat_det_ses_close(dm, ses);
4174     }
4175
4176 done:
4177   unformat_free (line_input);
4178
4179   return error;
4180 }
4181
4182 /*?
4183  * @cliexpar
4184  * @cliexstart{snat deterministic close session out}
4185  * Close session using outside ip address and port
4186  * and external ip address and port, use:
4187  *  vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
4188  * @cliexend
4189 ?*/
4190 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
4191   .path = "nat44 deterministic close session out",
4192   .short_help = "nat44 deterministic close session out "
4193                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
4194   .function = snat_det_close_session_out_fn,
4195 };
4196
4197 static clib_error_t *
4198 snat_det_close_session_in_fn (vlib_main_t *vm,
4199                               unformat_input_t * input,
4200                               vlib_cli_command_t * cmd)
4201 {
4202   snat_main_t *sm = &snat_main;
4203   unformat_input_t _line_input, *line_input = &_line_input;
4204   ip4_address_t in_addr, ext_addr;
4205   u32 in_port, ext_port;
4206   snat_det_map_t * dm;
4207   snat_det_session_t * ses;
4208   snat_det_out_key_t key;
4209   clib_error_t *error = 0;
4210
4211   /* Get a line of input. */
4212   if (!unformat_user (input, unformat_line_input, line_input))
4213     return 0;
4214
4215   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4216     {
4217       if (unformat (line_input, "%U:%d %U:%d",
4218                     unformat_ip4_address, &in_addr, &in_port,
4219                     unformat_ip4_address, &ext_addr, &ext_port))
4220         ;
4221       else
4222         {
4223           error = clib_error_return (0, "unknown input '%U'",
4224                                      format_unformat_error, line_input);
4225           goto done;
4226         }
4227     }
4228
4229   unformat_free (line_input);
4230
4231   dm = snat_det_map_by_user (sm, &in_addr);
4232   if (!dm)
4233     vlib_cli_output (vm, "no match");
4234   else
4235     {
4236       key.ext_host_addr = ext_addr;
4237       key.ext_host_port = ntohs ((u16)ext_port);
4238       ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
4239       if (!ses)
4240         vlib_cli_output (vm, "no match");
4241       else
4242         snat_det_ses_close(dm, ses);
4243     }
4244
4245 done:
4246   unformat_free(line_input);
4247
4248   return error;
4249 }
4250
4251 /*?
4252  * @cliexpar
4253  * @cliexstart{snat deterministic close_session_in}
4254  * Close session using inside ip address and port
4255  * and external ip address and port, use:
4256  *  vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
4257  * @cliexend
4258 ?*/
4259 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
4260   .path = "nat44 deterministic close session in",
4261   .short_help = "nat44 deterministic close session in "
4262                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
4263   .function = snat_det_close_session_in_fn,
4264 };
4265
4266 static clib_error_t *
4267 snat_forwarding_set_command_fn (vlib_main_t *vm,
4268                                 unformat_input_t * input,
4269                                 vlib_cli_command_t * cmd)
4270 {
4271   snat_main_t *sm = &snat_main;
4272   unformat_input_t _line_input, *line_input = &_line_input;
4273   u8 forwarding_enable;
4274   u8 forwarding_enable_set = 0;
4275   clib_error_t *error = 0;
4276
4277   /* Get a line of input. */
4278   if (!unformat_user (input, unformat_line_input, line_input))
4279       return clib_error_return (0, "'enable' or 'disable' expected");
4280
4281   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4282     {
4283       if (!forwarding_enable_set && unformat (line_input, "enable"))
4284         {
4285           forwarding_enable = 1;
4286           forwarding_enable_set = 1;
4287         }
4288       else if (!forwarding_enable_set && unformat (line_input, "disable"))
4289         {
4290           forwarding_enable = 0;
4291           forwarding_enable_set = 1;
4292         }
4293       else
4294         {
4295           error = clib_error_return (0, "unknown input '%U'",
4296                                      format_unformat_error, line_input);
4297           goto done;
4298         }
4299     }
4300
4301   if (!forwarding_enable_set)
4302     {
4303       error = clib_error_return (0, "'enable' or 'disable' expected");
4304       goto done;
4305     }
4306
4307   sm->forwarding_enabled = forwarding_enable;
4308
4309 done:
4310   unformat_free(line_input);
4311
4312   return error;
4313 }
4314
4315 /*?
4316  * @cliexpar
4317  * @cliexstart{nat44 forwarding}
4318  * Enable or disable forwarding
4319  * Forward packets which don't match existing translation
4320  * or static mapping instead of dropping them.
4321  * To enable forwarding, use:
4322  *  vpp# nat44 forwarding enable
4323  * To disable forwarding, use:
4324  *  vpp# nat44 forwarding disable
4325  * @cliexend
4326 ?*/
4327 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
4328   .path = "nat44 forwarding",
4329   .short_help = "nat44 forwarding enable|disable",
4330   .function = snat_forwarding_set_command_fn,
4331 };