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