Translate matching packets using NAT (VPP-1069)
[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   sm->forwarding_enabled = 0;
1646
1647   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1648   if (p)
1649     {
1650       tr = (vlib_thread_registration_t *) p[0];
1651       if (tr)
1652         {
1653           sm->num_workers = tr->count;
1654           sm->first_worker_index = tr->first_index;
1655         }
1656     }
1657
1658   vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1659
1660   /* Use all available workers by default */
1661   if (sm->num_workers > 1)
1662     {
1663       for (i=0; i < sm->num_workers; i++)
1664         bitmap = clib_bitmap_set (bitmap, i, 1);
1665       snat_set_workers(bitmap);
1666       clib_bitmap_free (bitmap);
1667     }
1668   else
1669     {
1670       sm->per_thread_data[0].snat_thread_index = 0;
1671     }
1672
1673   error = snat_api_init(vm, sm);
1674   if (error)
1675     return error;
1676
1677   /* Set up the interface address add/del callback */
1678   cb4.function = snat_ip4_add_del_interface_address_cb;
1679   cb4.function_opaque = 0;
1680
1681   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1682
1683   /* Init IPFIX logging */
1684   snat_ipfix_logging_init(vm);
1685
1686   /* Init NAT64 */
1687   error = nat64_init(vm);
1688   if (error)
1689     return error;
1690
1691   dslite_init(vm);
1692
1693   /* Init virtual fragmenentation reassembly */
1694   return nat_reass_init(vm);
1695 }
1696
1697 VLIB_INIT_FUNCTION (snat_init);
1698
1699 void snat_free_outside_address_and_port (snat_address_t * addresses,
1700                                          u32 thread_index,
1701                                          snat_session_key_t * k,
1702                                          u32 address_index)
1703 {
1704   snat_address_t *a;
1705   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1706
1707   ASSERT (address_index < vec_len (addresses));
1708
1709   a = addresses + address_index;
1710
1711   switch (k->protocol)
1712     {
1713 #define _(N, i, n, s) \
1714     case SNAT_PROTOCOL_##N: \
1715       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1716         port_host_byte_order) == 1); \
1717       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1718         port_host_byte_order, 0); \
1719       a->busy_##n##_ports--; \
1720       a->busy_##n##_ports_per_thread[thread_index]--; \
1721       break;
1722       foreach_snat_protocol
1723 #undef _
1724     default:
1725       clib_warning("unknown_protocol");
1726       return;
1727     }
1728 }
1729
1730 /**
1731  * @brief Match NAT44 static mapping.
1732  *
1733  * @param sm          NAT main.
1734  * @param match       Address and port to match.
1735  * @param mapping     External or local address and port of the matched mapping.
1736  * @param by_external If 0 match by local address otherwise match by external
1737  *                    address.
1738  * @param is_addr_only If matched mapping is address only
1739  * @param twice_nat If matched mapping is twice NAT.
1740  *
1741  * @returns 0 if match found otherwise 1.
1742  */
1743 int snat_static_mapping_match (snat_main_t * sm,
1744                                snat_session_key_t match,
1745                                snat_session_key_t * mapping,
1746                                u8 by_external,
1747                                u8 *is_addr_only,
1748                                u8 *twice_nat)
1749 {
1750   clib_bihash_kv_8_8_t kv, value;
1751   snat_static_mapping_t *m;
1752   snat_session_key_t m_key;
1753   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1754   u32 rand, lo = 0, hi, mid;
1755
1756   if (by_external)
1757     mapping_hash = &sm->static_mapping_by_external;
1758
1759   m_key.addr = match.addr;
1760   m_key.port = clib_net_to_host_u16 (match.port);
1761   m_key.protocol = match.protocol;
1762   m_key.fib_index = match.fib_index;
1763
1764   kv.key = m_key.as_u64;
1765
1766   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1767     {
1768       /* Try address only mapping */
1769       m_key.port = 0;
1770       m_key.protocol = 0;
1771       kv.key = m_key.as_u64;
1772       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1773         return 1;
1774     }
1775
1776   m = pool_elt_at_index (sm->static_mappings, value.value);
1777
1778   if (by_external)
1779     {
1780       if (vec_len (m->locals))
1781         {
1782           hi = vec_len (m->locals) - 1;
1783           rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix);
1784           while (lo < hi)
1785             {
1786               mid = ((hi - lo) >> 1) + lo;
1787               (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid);
1788             }
1789           if (!(m->locals[lo].prefix >= rand))
1790             return 1;
1791           mapping->addr = m->locals[lo].addr;
1792           mapping->port = clib_host_to_net_u16 (m->locals[lo].port);
1793         }
1794       else
1795         {
1796           mapping->addr = m->local_addr;
1797           /* Address only mapping doesn't change port */
1798           mapping->port = m->addr_only ? match.port
1799             : clib_host_to_net_u16 (m->local_port);
1800         }
1801       mapping->fib_index = m->fib_index;
1802       mapping->protocol = m->proto;
1803     }
1804   else
1805     {
1806       mapping->addr = m->external_addr;
1807       /* Address only mapping doesn't change port */
1808       mapping->port = m->addr_only ? match.port
1809         : clib_host_to_net_u16 (m->external_port);
1810       mapping->fib_index = sm->outside_fib_index;
1811     }
1812
1813   if (PREDICT_FALSE(is_addr_only != 0))
1814     *is_addr_only = m->addr_only;
1815
1816   if (PREDICT_FALSE(twice_nat != 0))
1817     *twice_nat = m->twice_nat;
1818
1819   return 0;
1820 }
1821
1822 static_always_inline u16
1823 snat_random_port (u16 min, u16 max)
1824 {
1825   snat_main_t *sm = &snat_main;
1826   return min + random_u32 (&sm->random_seed) /
1827     (random_u32_max() / (max - min + 1) + 1);
1828 }
1829
1830 int
1831 snat_alloc_outside_address_and_port (snat_address_t * addresses,
1832                                      u32 fib_index,
1833                                      u32 thread_index,
1834                                      snat_session_key_t * k,
1835                                      u32 * address_indexp,
1836                                      u16 port_per_thread,
1837                                      u32 snat_thread_index)
1838 {
1839   snat_main_t *sm = &snat_main;
1840
1841   return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k,
1842                                  address_indexp, port_per_thread,
1843                                  snat_thread_index);
1844 }
1845
1846 static int
1847 nat_alloc_addr_and_port_default (snat_address_t * addresses,
1848                                  u32 fib_index,
1849                                  u32 thread_index,
1850                                  snat_session_key_t * k,
1851                                  u32 * address_indexp,
1852                                  u16 port_per_thread,
1853                                  u32 snat_thread_index)
1854 {
1855   int i, gi = 0;
1856   snat_address_t *a, *ga = 0;
1857   u32 portnum;
1858
1859   for (i = 0; i < vec_len (addresses); i++)
1860     {
1861       a = addresses + i;
1862       switch (k->protocol)
1863         {
1864 #define _(N, j, n, s) \
1865         case SNAT_PROTOCOL_##N: \
1866           if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \
1867             { \
1868               if (a->fib_index == fib_index) \
1869                 { \
1870                   while (1) \
1871                     { \
1872                       portnum = (port_per_thread * \
1873                         snat_thread_index) + \
1874                         snat_random_port(1, port_per_thread) + 1024; \
1875                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1876                         continue; \
1877                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1878                       a->busy_##n##_ports_per_thread[thread_index]++; \
1879                       a->busy_##n##_ports++; \
1880                       k->addr = a->addr; \
1881                       k->port = clib_host_to_net_u16(portnum); \
1882                       *address_indexp = i; \
1883                       return 0; \
1884                     } \
1885                 } \
1886               else if (a->fib_index == ~0) \
1887                 { \
1888                   ga = a; \
1889                   gi = i; \
1890                 } \
1891             } \
1892           break;
1893           foreach_snat_protocol
1894 #undef _
1895         default:
1896           clib_warning("unknown protocol");
1897           return 1;
1898         }
1899
1900     }
1901
1902   if (ga)
1903     {
1904       a = ga;
1905       switch (k->protocol)
1906         {
1907 #define _(N, j, n, s) \
1908         case SNAT_PROTOCOL_##N: \
1909           while (1) \
1910             { \
1911               portnum = (port_per_thread * \
1912                 snat_thread_index) + \
1913                 snat_random_port(1, port_per_thread) + 1024; \
1914               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1915                 continue; \
1916               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1917               a->busy_##n##_ports_per_thread[thread_index]++; \
1918               a->busy_##n##_ports++; \
1919               k->addr = a->addr; \
1920               k->port = clib_host_to_net_u16(portnum); \
1921               *address_indexp = gi; \
1922               return 0; \
1923             }
1924           break;
1925           foreach_snat_protocol
1926 #undef _
1927         default:
1928           clib_warning ("unknown protocol");
1929           return 1;
1930         }
1931     }
1932
1933   /* Totally out of translations to use... */
1934   snat_ipfix_logging_addresses_exhausted(0);
1935   return 1;
1936 }
1937
1938 static int
1939 nat_alloc_addr_and_port_mape (snat_address_t * addresses,
1940                               u32 fib_index,
1941                               u32 thread_index,
1942                               snat_session_key_t * k,
1943                               u32 * address_indexp,
1944                               u16 port_per_thread,
1945                               u32 snat_thread_index)
1946 {
1947   snat_main_t *sm = &snat_main;
1948   snat_address_t *a = addresses;
1949   u16 m, ports, portnum, A, j;
1950   m = 16 - (sm->psid_offset + sm->psid_length);
1951   ports = (1 << (16 - sm->psid_length)) - (1 << m);
1952
1953   if (!vec_len (addresses))
1954     goto exhausted;
1955
1956   switch (k->protocol)
1957     {
1958 #define _(N, i, n, s) \
1959     case SNAT_PROTOCOL_##N: \
1960       if (a->busy_##n##_ports < ports) \
1961         { \
1962           while (1) \
1963             { \
1964               A = snat_random_port(1, pow2_mask(sm->psid_offset)); \
1965               j = snat_random_port(0, pow2_mask(m)); \
1966               portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \
1967               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1968                 continue; \
1969               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1970               a->busy_##n##_ports++; \
1971               k->addr = a->addr; \
1972               k->port = clib_host_to_net_u16 (portnum); \
1973               *address_indexp = i; \
1974               return 0; \
1975             } \
1976         } \
1977       break;
1978       foreach_snat_protocol
1979 #undef _
1980     default:
1981       clib_warning("unknown protocol");
1982       return 1;
1983     }
1984
1985 exhausted:
1986   /* Totally out of translations to use... */
1987   snat_ipfix_logging_addresses_exhausted(0);
1988   return 1;
1989 }
1990
1991 static clib_error_t *
1992 add_address_command_fn (vlib_main_t * vm,
1993                         unformat_input_t * input,
1994                         vlib_cli_command_t * cmd)
1995 {
1996   unformat_input_t _line_input, *line_input = &_line_input;
1997   snat_main_t * sm = &snat_main;
1998   ip4_address_t start_addr, end_addr, this_addr;
1999   u32 start_host_order, end_host_order;
2000   u32 vrf_id = ~0;
2001   int i, count;
2002   int is_add = 1;
2003   int rv = 0;
2004   clib_error_t *error = 0;
2005   u8 twice_nat = 0;
2006
2007   /* Get a line of input. */
2008   if (!unformat_user (input, unformat_line_input, line_input))
2009     return 0;
2010
2011   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2012     {
2013       if (unformat (line_input, "%U - %U",
2014                     unformat_ip4_address, &start_addr,
2015                     unformat_ip4_address, &end_addr))
2016         ;
2017       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
2018         ;
2019       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
2020         end_addr = start_addr;
2021       else if (unformat (line_input, "twice-nat"))
2022         twice_nat = 1;
2023       else if (unformat (line_input, "del"))
2024         is_add = 0;
2025       else
2026         {
2027           error = clib_error_return (0, "unknown input '%U'",
2028             format_unformat_error, line_input);
2029           goto done;
2030         }
2031      }
2032
2033   if (sm->static_mapping_only)
2034     {
2035       error = clib_error_return (0, "static mapping only mode");
2036       goto done;
2037     }
2038
2039   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
2040   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
2041
2042   if (end_host_order < start_host_order)
2043     {
2044       error = clib_error_return (0, "end address less than start address");
2045       goto done;
2046     }
2047
2048   count = (end_host_order - start_host_order) + 1;
2049
2050   if (count > 1024)
2051     clib_warning ("%U - %U, %d addresses...",
2052                   format_ip4_address, &start_addr,
2053                   format_ip4_address, &end_addr,
2054                   count);
2055
2056   this_addr = start_addr;
2057
2058   for (i = 0; i < count; i++)
2059     {
2060       if (is_add)
2061         snat_add_address (sm, &this_addr, vrf_id, twice_nat);
2062       else
2063         rv = snat_del_address (sm, this_addr, 0, twice_nat);
2064
2065       switch (rv)
2066         {
2067         case VNET_API_ERROR_NO_SUCH_ENTRY:
2068           error = clib_error_return (0, "S-NAT address not exist.");
2069           goto done;
2070         case VNET_API_ERROR_UNSPECIFIED:
2071           error = clib_error_return (0, "S-NAT address used in static mapping.");
2072           goto done;
2073         default:
2074           break;
2075         }
2076
2077       increment_v4_address (&this_addr);
2078     }
2079
2080 done:
2081   unformat_free (line_input);
2082
2083   return error;
2084 }
2085
2086 VLIB_CLI_COMMAND (add_address_command, static) = {
2087   .path = "nat44 add address",
2088   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
2089                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
2090   .function = add_address_command_fn,
2091 };
2092
2093 static clib_error_t *
2094 snat_feature_command_fn (vlib_main_t * vm,
2095                           unformat_input_t * input,
2096                           vlib_cli_command_t * cmd)
2097 {
2098   unformat_input_t _line_input, *line_input = &_line_input;
2099   vnet_main_t * vnm = vnet_get_main();
2100   clib_error_t * error = 0;
2101   u32 sw_if_index;
2102   u32 * inside_sw_if_indices = 0;
2103   u32 * outside_sw_if_indices = 0;
2104   u8 is_output_feature = 0;
2105   int is_del = 0;
2106   int i;
2107
2108   sw_if_index = ~0;
2109
2110   /* Get a line of input. */
2111   if (!unformat_user (input, unformat_line_input, line_input))
2112     return 0;
2113
2114   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2115     {
2116       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
2117                     vnm, &sw_if_index))
2118         vec_add1 (inside_sw_if_indices, sw_if_index);
2119       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
2120                          vnm, &sw_if_index))
2121         vec_add1 (outside_sw_if_indices, sw_if_index);
2122       else if (unformat (line_input, "output-feature"))
2123         is_output_feature = 1;
2124       else if (unformat (line_input, "del"))
2125         is_del = 1;
2126       else
2127         {
2128           error = clib_error_return (0, "unknown input '%U'",
2129             format_unformat_error, line_input);
2130           goto done;
2131         }
2132     }
2133
2134   if (vec_len (inside_sw_if_indices))
2135     {
2136       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
2137         {
2138           sw_if_index = inside_sw_if_indices[i];
2139           if (is_output_feature)
2140             {
2141               if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del))
2142                 {
2143                   error = clib_error_return (0, "%s %U failed",
2144                                              is_del ? "del" : "add",
2145                                              format_vnet_sw_interface_name, vnm,
2146                                              vnet_get_sw_interface (vnm,
2147                                                                     sw_if_index));
2148                   goto done;
2149                 }
2150             }
2151           else
2152             {
2153               if (snat_interface_add_del (sw_if_index, 1, is_del))
2154                 {
2155                   error = clib_error_return (0, "%s %U failed",
2156                                              is_del ? "del" : "add",
2157                                              format_vnet_sw_interface_name, vnm,
2158                                              vnet_get_sw_interface (vnm,
2159                                                                     sw_if_index));
2160                   goto done;
2161                 }
2162             }
2163         }
2164     }
2165
2166   if (vec_len (outside_sw_if_indices))
2167     {
2168       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
2169         {
2170           sw_if_index = outside_sw_if_indices[i];
2171           if (is_output_feature)
2172             {
2173               if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del))
2174                 {
2175                   error = clib_error_return (0, "%s %U failed",
2176                                              is_del ? "del" : "add",
2177                                              format_vnet_sw_interface_name, vnm,
2178                                              vnet_get_sw_interface (vnm,
2179                                                                     sw_if_index));
2180                   goto done;
2181                 }
2182             }
2183           else
2184             {
2185               if (snat_interface_add_del (sw_if_index, 0, is_del))
2186                 {
2187                   error = clib_error_return (0, "%s %U failed",
2188                                              is_del ? "del" : "add",
2189                                              format_vnet_sw_interface_name, vnm,
2190                                              vnet_get_sw_interface (vnm,
2191                                                                     sw_if_index));
2192                   goto done;
2193                 }
2194             }
2195         }
2196     }
2197
2198 done:
2199   unformat_free (line_input);
2200   vec_free (inside_sw_if_indices);
2201   vec_free (outside_sw_if_indices);
2202
2203   return error;
2204 }
2205
2206 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
2207   .path = "set interface nat44",
2208   .function = snat_feature_command_fn,
2209   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
2210                 "[del]",
2211 };
2212
2213 uword
2214 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2215 {
2216   u32 *r = va_arg (*args, u32 *);
2217
2218   if (0);
2219 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2220   foreach_snat_protocol
2221 #undef _
2222   else
2223     return 0;
2224   return 1;
2225 }
2226
2227 u8 *
2228 format_snat_protocol (u8 * s, va_list * args)
2229 {
2230   u32 i = va_arg (*args, u32);
2231   u8 *t = 0;
2232
2233   switch (i)
2234     {
2235 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2236       foreach_snat_protocol
2237 #undef _
2238     default:
2239       s = format (s, "unknown");
2240       return s;
2241     }
2242   s = format (s, "%s", t);
2243   return s;
2244 }
2245
2246 static clib_error_t *
2247 add_static_mapping_command_fn (vlib_main_t * vm,
2248                                unformat_input_t * input,
2249                                vlib_cli_command_t * cmd)
2250 {
2251   unformat_input_t _line_input, *line_input = &_line_input;
2252   clib_error_t * error = 0;
2253   ip4_address_t l_addr, e_addr;
2254   u32 l_port = 0, e_port = 0, vrf_id = ~0;
2255   int is_add = 1;
2256   int addr_only = 1;
2257   u32 sw_if_index = ~0;
2258   vnet_main_t * vnm = vnet_get_main();
2259   int rv;
2260   snat_protocol_t proto = ~0;
2261   u8 proto_set = 0;
2262   u8 twice_nat = 0;
2263
2264   /* Get a line of input. */
2265   if (!unformat_user (input, unformat_line_input, line_input))
2266     return 0;
2267
2268   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2269     {
2270       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2271                     &l_port))
2272         addr_only = 0;
2273       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2274         ;
2275       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2276                          &e_addr, &e_port))
2277         addr_only = 0;
2278       else if (unformat (line_input, "external %U", unformat_ip4_address,
2279                          &e_addr))
2280         ;
2281       else if (unformat (line_input, "external %U %u",
2282                          unformat_vnet_sw_interface, vnm, &sw_if_index,
2283                          &e_port))
2284         addr_only = 0;
2285
2286       else if (unformat (line_input, "external %U",
2287                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2288         ;
2289       else if (unformat (line_input, "vrf %u", &vrf_id))
2290         ;
2291       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2292         proto_set = 1;
2293       else if (unformat (line_input, "twice-nat"))
2294         twice_nat = 1;
2295       else if (unformat (line_input, "del"))
2296         is_add = 0;
2297       else
2298         {
2299           error = clib_error_return (0, "unknown input: '%U'",
2300             format_unformat_error, line_input);
2301           goto done;
2302         }
2303     }
2304
2305   if (twice_nat && addr_only)
2306     {
2307       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
2308       goto done;
2309     }
2310
2311   if (!addr_only && !proto_set)
2312     {
2313       error = clib_error_return (0, "missing protocol");
2314       goto done;
2315     }
2316
2317   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2318                                vrf_id, addr_only, sw_if_index, proto, is_add,
2319                                twice_nat);
2320
2321   switch (rv)
2322     {
2323     case VNET_API_ERROR_INVALID_VALUE:
2324       error = clib_error_return (0, "External port already in use.");
2325       goto done;
2326     case VNET_API_ERROR_NO_SUCH_ENTRY:
2327       if (is_add)
2328         error = clib_error_return (0, "External addres must be allocated.");
2329       else
2330         error = clib_error_return (0, "Mapping not exist.");
2331       goto done;
2332     case VNET_API_ERROR_NO_SUCH_FIB:
2333       error = clib_error_return (0, "No such VRF id.");
2334       goto done;
2335     case VNET_API_ERROR_VALUE_EXIST:
2336       error = clib_error_return (0, "Mapping already exist.");
2337       goto done;
2338     default:
2339       break;
2340     }
2341
2342 done:
2343   unformat_free (line_input);
2344
2345   return error;
2346 }
2347
2348 /*?
2349  * @cliexpar
2350  * @cliexstart{snat add static mapping}
2351  * Static mapping allows hosts on the external network to initiate connection
2352  * to to the local network host.
2353  * To create static mapping between local host address 10.0.0.3 port 6303 and
2354  * external address 4.4.4.4 port 3606 for TCP protocol use:
2355  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2356  * If not runnig "static mapping only" NAT plugin mode use before:
2357  *  vpp# nat44 add address 4.4.4.4
2358  * To create static mapping between local and external address use:
2359  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2360  * @cliexend
2361 ?*/
2362 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2363   .path = "nat44 add static mapping",
2364   .function = add_static_mapping_command_fn,
2365   .short_help =
2366     "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
2367     "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]",
2368 };
2369
2370 static clib_error_t *
2371 add_identity_mapping_command_fn (vlib_main_t * vm,
2372                                  unformat_input_t * input,
2373                                  vlib_cli_command_t * cmd)
2374 {
2375   unformat_input_t _line_input, *line_input = &_line_input;
2376   clib_error_t * error = 0;
2377   ip4_address_t addr;
2378   u32 port = 0, vrf_id = ~0;
2379   int is_add = 1;
2380   int addr_only = 1;
2381   u32 sw_if_index = ~0;
2382   vnet_main_t * vnm = vnet_get_main();
2383   int rv;
2384   snat_protocol_t proto;
2385
2386   addr.as_u32 = 0;
2387
2388   /* Get a line of input. */
2389   if (!unformat_user (input, unformat_line_input, line_input))
2390     return 0;
2391
2392   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2393     {
2394       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2395         ;
2396       else if (unformat (line_input, "external %U",
2397                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2398         ;
2399       else if (unformat (line_input, "vrf %u", &vrf_id))
2400         ;
2401       else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2402                          &port))
2403         addr_only = 0;
2404       else if (unformat (line_input, "del"))
2405         is_add = 0;
2406       else
2407         {
2408           error = clib_error_return (0, "unknown input: '%U'",
2409             format_unformat_error, line_input);
2410           goto done;
2411         }
2412     }
2413
2414   rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2415                                vrf_id, addr_only, sw_if_index, proto, is_add,
2416                                0);
2417
2418   switch (rv)
2419     {
2420     case VNET_API_ERROR_INVALID_VALUE:
2421       error = clib_error_return (0, "External port already in use.");
2422       goto done;
2423     case VNET_API_ERROR_NO_SUCH_ENTRY:
2424       if (is_add)
2425         error = clib_error_return (0, "External addres must be allocated.");
2426       else
2427         error = clib_error_return (0, "Mapping not exist.");
2428       goto done;
2429     case VNET_API_ERROR_NO_SUCH_FIB:
2430       error = clib_error_return (0, "No such VRF id.");
2431       goto done;
2432     case VNET_API_ERROR_VALUE_EXIST:
2433       error = clib_error_return (0, "Mapping already exist.");
2434       goto done;
2435     default:
2436       break;
2437     }
2438
2439 done:
2440   unformat_free (line_input);
2441
2442   return error;
2443 }
2444
2445 /*?
2446  * @cliexpar
2447  * @cliexstart{snat add identity mapping}
2448  * Identity mapping translate an IP address to itself.
2449  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2450  * use:
2451  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2452  * To create identity mapping for address 10.0.0.3 use:
2453  *  vpp# nat44 add identity mapping 10.0.0.3
2454  * To create identity mapping for DHCP addressed interface use:
2455  *  vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2456  * @cliexend
2457 ?*/
2458 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2459   .path = "nat44 add identity mapping",
2460   .function = add_identity_mapping_command_fn,
2461   .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2462     "[<protocol> <port>] [vrf <table-id>] [del]",
2463 };
2464
2465 static clib_error_t *
2466 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2467                                   unformat_input_t * input,
2468                                   vlib_cli_command_t * cmd)
2469 {
2470   unformat_input_t _line_input, *line_input = &_line_input;
2471   clib_error_t * error = 0;
2472   ip4_address_t l_addr, e_addr;
2473   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2474   int is_add = 1;
2475   int rv;
2476   snat_protocol_t proto;
2477   u8 proto_set = 0;
2478   nat44_lb_addr_port_t *locals = 0, local;
2479   u8 twice_nat = 0;
2480
2481   /* Get a line of input. */
2482   if (!unformat_user (input, unformat_line_input, line_input))
2483     return 0;
2484
2485   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2486     {
2487       if (unformat (line_input, "local %U:%u probability %u",
2488                     unformat_ip4_address, &l_addr, &l_port, &probability))
2489         {
2490           memset (&local, 0, sizeof (local));
2491           local.addr = l_addr;
2492           local.port = (u16) l_port;
2493           local.probability = (u8) probability;
2494           vec_add1 (locals, local);
2495         }
2496       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2497                          &e_addr, &e_port))
2498         ;
2499       else if (unformat (line_input, "vrf %u", &vrf_id))
2500         ;
2501       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2502                          &proto))
2503         proto_set = 1;
2504       else if (unformat (line_input, "twice-nat"))
2505         twice_nat = 1;
2506       else if (unformat (line_input, "del"))
2507         is_add = 0;
2508       else
2509         {
2510           error = clib_error_return (0, "unknown input: '%U'",
2511             format_unformat_error, line_input);
2512           goto done;
2513         }
2514     }
2515
2516   if (vec_len (locals) < 2)
2517     {
2518       error = clib_error_return (0, "at least two local must be set");
2519       goto done;
2520     }
2521
2522   if (!proto_set)
2523     {
2524       error = clib_error_return (0, "missing protocol");
2525       goto done;
2526     }
2527
2528   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2529                                         locals, is_add, twice_nat);
2530
2531   switch (rv)
2532     {
2533     case VNET_API_ERROR_INVALID_VALUE:
2534       error = clib_error_return (0, "External port already in use.");
2535       goto done;
2536     case VNET_API_ERROR_NO_SUCH_ENTRY:
2537       if (is_add)
2538         error = clib_error_return (0, "External addres must be allocated.");
2539       else
2540         error = clib_error_return (0, "Mapping not exist.");
2541       goto done;
2542     case VNET_API_ERROR_VALUE_EXIST:
2543       error = clib_error_return (0, "Mapping already exist.");
2544       goto done;
2545     default:
2546       break;
2547     }
2548
2549 done:
2550   unformat_free (line_input);
2551   vec_free (locals);
2552
2553   return error;
2554 }
2555
2556 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2557   .path = "nat44 add load-balancing static mapping",
2558   .function = add_lb_static_mapping_command_fn,
2559   .short_help =
2560     "nat44 add load-balancing static mapping protocol tcp|udp "
2561     "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] "
2562     "[vrf <table-id>] [del]",
2563 };
2564
2565 static clib_error_t *
2566 set_workers_command_fn (vlib_main_t * vm,
2567                         unformat_input_t * input,
2568                         vlib_cli_command_t * cmd)
2569 {
2570   unformat_input_t _line_input, *line_input = &_line_input;
2571   uword *bitmap = 0;
2572   int rv = 0;
2573   clib_error_t *error = 0;
2574
2575   /* Get a line of input. */
2576   if (!unformat_user (input, unformat_line_input, line_input))
2577     return 0;
2578
2579   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2580     {
2581       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2582         ;
2583       else
2584         {
2585           error = clib_error_return (0, "unknown input '%U'",
2586             format_unformat_error, line_input);
2587           goto done;
2588         }
2589      }
2590
2591   if (bitmap == 0)
2592     {
2593       error = clib_error_return (0, "List of workers must be specified.");
2594       goto done;
2595     }
2596
2597   rv = snat_set_workers(bitmap);
2598
2599   clib_bitmap_free (bitmap);
2600
2601   switch (rv)
2602     {
2603     case VNET_API_ERROR_INVALID_WORKER:
2604       error = clib_error_return (0, "Invalid worker(s).");
2605       goto done;
2606     case VNET_API_ERROR_FEATURE_DISABLED:
2607       error = clib_error_return (0,
2608         "Supported only if 2 or more workes available.");
2609       goto done;
2610     default:
2611       break;
2612     }
2613
2614 done:
2615   unformat_free (line_input);
2616
2617   return error;
2618 }
2619
2620 /*?
2621  * @cliexpar
2622  * @cliexstart{set snat workers}
2623  * Set NAT workers if 2 or more workers available, use:
2624  *  vpp# set snat workers 0-2,5
2625  * @cliexend
2626 ?*/
2627 VLIB_CLI_COMMAND (set_workers_command, static) = {
2628   .path = "set nat workers",
2629   .function = set_workers_command_fn,
2630   .short_help =
2631     "set nat workers <workers-list>",
2632 };
2633
2634 static clib_error_t *
2635 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2636                                               unformat_input_t * input,
2637                                               vlib_cli_command_t * cmd)
2638 {
2639   unformat_input_t _line_input, *line_input = &_line_input;
2640   u32 domain_id = 0;
2641   u32 src_port = 0;
2642   u8 enable = 1;
2643   int rv = 0;
2644   clib_error_t *error = 0;
2645
2646   /* Get a line of input. */
2647   if (!unformat_user (input, unformat_line_input, line_input))
2648     return 0;
2649
2650   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2651     {
2652       if (unformat (line_input, "domain %d", &domain_id))
2653         ;
2654       else if (unformat (line_input, "src-port %d", &src_port))
2655         ;
2656       else if (unformat (line_input, "disable"))
2657         enable = 0;
2658       else
2659         {
2660           error = clib_error_return (0, "unknown input '%U'",
2661             format_unformat_error, line_input);
2662           goto done;
2663         }
2664      }
2665
2666   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2667
2668   if (rv)
2669     {
2670       error = clib_error_return (0, "ipfix logging enable failed");
2671       goto done;
2672     }
2673
2674 done:
2675   unformat_free (line_input);
2676
2677   return error;
2678 }
2679
2680 /*?
2681  * @cliexpar
2682  * @cliexstart{snat ipfix logging}
2683  * To enable NAT IPFIX logging use:
2684  *  vpp# nat ipfix logging
2685  * To set IPFIX exporter use:
2686  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2687  * @cliexend
2688 ?*/
2689 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2690   .path = "nat ipfix logging",
2691   .function = snat_ipfix_logging_enable_disable_command_fn,
2692   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2693 };
2694
2695 static u32
2696 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2697 {
2698   snat_main_t *sm = &snat_main;
2699   u32 next_worker_index = 0;
2700   u32 hash;
2701
2702   next_worker_index = sm->first_worker_index;
2703   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2704          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2705
2706   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2707     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2708   else
2709     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2710
2711   return next_worker_index;
2712 }
2713
2714 static u32
2715 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2716 {
2717   snat_main_t *sm = &snat_main;
2718   udp_header_t *udp;
2719   u16 port;
2720   snat_session_key_t m_key;
2721   clib_bihash_kv_8_8_t kv, value;
2722   snat_static_mapping_t *m;
2723   nat_ed_ses_key_t key;
2724   clib_bihash_kv_16_8_t s_kv, s_value;
2725   snat_main_per_thread_data_t *tsm;
2726   snat_session_t *s;
2727   int i;
2728   u32 proto;
2729
2730   /* first try static mappings without port */
2731   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2732     {
2733       m_key.addr = ip0->dst_address;
2734       m_key.port = 0;
2735       m_key.protocol = 0;
2736       m_key.fib_index = rx_fib_index0;
2737       kv.key = m_key.as_u64;
2738       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2739         {
2740           m = pool_elt_at_index (sm->static_mappings, value.value);
2741           return m->worker_index;
2742         }
2743     }
2744
2745   proto = ip_proto_to_snat_proto (ip0->protocol);
2746   udp = ip4_next_header (ip0);
2747   port = udp->dst_port;
2748
2749   if (PREDICT_FALSE (ip4_is_fragment (ip0)))
2750     {
2751       if (PREDICT_FALSE (nat_reass_is_drop_frag (0)))
2752         return vlib_get_thread_index ();
2753
2754       if (PREDICT_TRUE (!ip4_is_first_fragment (ip0)))
2755         {
2756           nat_reass_ip4_t *reass;
2757
2758           reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address,
2759                                       ip0->fragment_id, ip0->protocol);
2760
2761           if (reass && (reass->thread_index != (u32) ~ 0))
2762             return reass->thread_index;
2763           else
2764             return vlib_get_thread_index ();
2765         }
2766     }
2767
2768   /* unknown protocol */
2769   if (PREDICT_FALSE (proto == ~0))
2770     {
2771       key.l_addr = ip0->dst_address;
2772       key.r_addr = ip0->src_address;
2773       key.fib_index = rx_fib_index0;
2774       key.proto = ip0->protocol;
2775       key.r_port = 0;
2776       key.l_port = 0;
2777       s_kv.key[0] = key.as_u64[0];
2778       s_kv.key[1] = key.as_u64[1];
2779
2780       if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2781         {
2782           for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2783             {
2784               tsm = vec_elt_at_index (sm->per_thread_data, i);
2785               if (!pool_is_free_index(tsm->sessions, s_value.value))
2786                 {
2787                   s = pool_elt_at_index (tsm->sessions, s_value.value);
2788                   if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2789                       s->out2in.port == ip0->protocol &&
2790                       snat_is_unk_proto_session (s))
2791                     return i;
2792                 }
2793             }
2794          }
2795
2796       /* if no session use current thread */
2797       return vlib_get_thread_index ();
2798     }
2799
2800   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2801     {
2802       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2803       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2804       if (!icmp_is_error_message (icmp))
2805         port = echo->identifier;
2806       else
2807         {
2808           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2809           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2810           void *l4_header = ip4_next_header (inner_ip);
2811           switch (proto)
2812             {
2813             case SNAT_PROTOCOL_ICMP:
2814               icmp = (icmp46_header_t*)l4_header;
2815               echo = (icmp_echo_header_t *)(icmp + 1);
2816               port = echo->identifier;
2817               break;
2818             case SNAT_PROTOCOL_UDP:
2819             case SNAT_PROTOCOL_TCP:
2820               port = ((tcp_udp_header_t*)l4_header)->src_port;
2821               break;
2822             default:
2823               return vlib_get_thread_index ();
2824             }
2825         }
2826     }
2827
2828   /* try static mappings with port */
2829   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2830     {
2831       m_key.addr = ip0->dst_address;
2832       m_key.port = clib_net_to_host_u16 (port);
2833       m_key.protocol = proto;
2834       m_key.fib_index = rx_fib_index0;
2835       kv.key = m_key.as_u64;
2836       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2837         {
2838           m = pool_elt_at_index (sm->static_mappings, value.value);
2839           return m->worker_index;
2840         }
2841     }
2842
2843   /* worker by outside port */
2844   return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2845 }
2846
2847 static clib_error_t *
2848 snat_config (vlib_main_t * vm, unformat_input_t * input)
2849 {
2850   snat_main_t * sm = &snat_main;
2851   u32 translation_buckets = 1024;
2852   u32 translation_memory_size = 128<<20;
2853   u32 user_buckets = 128;
2854   u32 user_memory_size = 64<<20;
2855   u32 max_translations_per_user = 100;
2856   u32 outside_vrf_id = 0;
2857   u32 inside_vrf_id = 0;
2858   u32 static_mapping_buckets = 1024;
2859   u32 static_mapping_memory_size = 64<<20;
2860   u32 nat64_bib_buckets = 1024;
2861   u32 nat64_bib_memory_size = 128 << 20;
2862   u32 nat64_st_buckets = 2048;
2863   u32 nat64_st_memory_size = 256 << 20;
2864   u8 static_mapping_only = 0;
2865   u8 static_mapping_connection_tracking = 0;
2866   snat_main_per_thread_data_t *tsm;
2867
2868   sm->deterministic = 0;
2869
2870   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2871     {
2872       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2873         ;
2874       else if (unformat (input, "translation hash memory %d",
2875                          &translation_memory_size));
2876       else if (unformat (input, "user hash buckets %d", &user_buckets))
2877         ;
2878       else if (unformat (input, "user hash memory %d",
2879                          &user_memory_size))
2880         ;
2881       else if (unformat (input, "max translations per user %d",
2882                          &max_translations_per_user))
2883         ;
2884       else if (unformat (input, "outside VRF id %d",
2885                          &outside_vrf_id))
2886         ;
2887       else if (unformat (input, "inside VRF id %d",
2888                          &inside_vrf_id))
2889         ;
2890       else if (unformat (input, "static mapping only"))
2891         {
2892           static_mapping_only = 1;
2893           if (unformat (input, "connection tracking"))
2894             static_mapping_connection_tracking = 1;
2895         }
2896       else if (unformat (input, "deterministic"))
2897         sm->deterministic = 1;
2898       else if (unformat (input, "nat64 bib hash buckets %d",
2899                          &nat64_bib_buckets))
2900         ;
2901       else if (unformat (input, "nat64 bib hash memory %d",
2902                          &nat64_bib_memory_size))
2903         ;
2904       else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets))
2905         ;
2906       else if (unformat (input, "nat64 st hash memory %d",
2907                          &nat64_st_memory_size))
2908         ;
2909       else
2910         return clib_error_return (0, "unknown input '%U'",
2911                                   format_unformat_error, input);
2912     }
2913
2914   /* for show commands, etc. */
2915   sm->translation_buckets = translation_buckets;
2916   sm->translation_memory_size = translation_memory_size;
2917   /* do not exceed load factor 10 */
2918   sm->max_translations = 10 * translation_buckets;
2919   sm->user_buckets = user_buckets;
2920   sm->user_memory_size = user_memory_size;
2921   sm->max_translations_per_user = max_translations_per_user;
2922   sm->outside_vrf_id = outside_vrf_id;
2923   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2924                                                              outside_vrf_id,
2925                                                              FIB_SOURCE_PLUGIN_HI);
2926   sm->inside_vrf_id = inside_vrf_id;
2927   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2928                                                             inside_vrf_id,
2929                                                             FIB_SOURCE_PLUGIN_HI);
2930   sm->static_mapping_only = static_mapping_only;
2931   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2932
2933   nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets,
2934                  nat64_st_memory_size);
2935
2936   if (sm->deterministic)
2937     {
2938       sm->in2out_node_index = snat_det_in2out_node.index;
2939       sm->in2out_output_node_index = ~0;
2940       sm->out2in_node_index = snat_det_out2in_node.index;
2941       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2942       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2943     }
2944   else
2945     {
2946       sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2947       sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2948       sm->in2out_node_index = snat_in2out_node.index;
2949       sm->in2out_output_node_index = snat_in2out_output_node.index;
2950       sm->out2in_node_index = snat_out2in_node.index;
2951       if (!static_mapping_only ||
2952           (static_mapping_only && static_mapping_connection_tracking))
2953         {
2954           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2955           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2956
2957           vec_foreach (tsm, sm->per_thread_data)
2958             {
2959               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2960                                     translation_memory_size);
2961
2962               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2963                                     translation_memory_size);
2964
2965               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2966                                     user_memory_size);
2967             }
2968
2969           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2970                                  translation_buckets, translation_memory_size);
2971
2972           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2973                                  translation_buckets, translation_memory_size);
2974         }
2975       else
2976         {
2977           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2978           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2979         }
2980       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2981                             "static_mapping_by_local", static_mapping_buckets,
2982                             static_mapping_memory_size);
2983
2984       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2985                             "static_mapping_by_external", static_mapping_buckets,
2986                             static_mapping_memory_size);
2987     }
2988
2989   return 0;
2990 }
2991
2992 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2993
2994 u8 * format_snat_session_state (u8 * s, va_list * args)
2995 {
2996   u32 i = va_arg (*args, u32);
2997   u8 *t = 0;
2998
2999   switch (i)
3000     {
3001 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
3002     foreach_snat_session_state
3003 #undef _
3004     default:
3005       t = format (t, "unknown");
3006     }
3007   s = format (s, "%s", t);
3008   return s;
3009 }
3010
3011 u8 * format_snat_key (u8 * s, va_list * args)
3012 {
3013   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
3014
3015   s = format (s, "%U proto %U port %d fib %d",
3016               format_ip4_address, &key->addr,
3017               format_snat_protocol, key->protocol,
3018               clib_net_to_host_u16 (key->port), key->fib_index);
3019   return s;
3020 }
3021
3022 u8 * format_snat_session (u8 * s, va_list * args)
3023 {
3024   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
3025   snat_session_t * sess = va_arg (*args, snat_session_t *);
3026
3027   if (snat_is_unk_proto_session (sess))
3028     {
3029       s = format (s, "  i2o %U proto %u fib %u\n",
3030                   format_ip4_address, &sess->in2out.addr,
3031                   clib_net_to_host_u16 (sess->in2out.port),
3032                   sess->in2out.fib_index);
3033       s = format (s, "    o2i %U proto %u fib %u\n",
3034                   format_ip4_address, &sess->out2in.addr,
3035                   clib_net_to_host_u16 (sess->out2in.port),
3036                   sess->out2in.fib_index);
3037     }
3038   else
3039     {
3040       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
3041       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
3042     }
3043   if (is_twice_nat_session (sess))
3044     {
3045       s = format (s, "       external host o2i %U:%d i2o %U:%d\n",
3046                   format_ip4_address, &sess->ext_host_addr,
3047                   clib_net_to_host_u16 (sess->ext_host_port),
3048                   format_ip4_address, &sess->ext_host_nat_addr,
3049                   clib_net_to_host_u16 (sess->ext_host_nat_port));
3050     }
3051   else
3052     {
3053       if (sess->ext_host_addr.as_u32)
3054           s = format (s, "       external host %U\n",
3055                       format_ip4_address, &sess->ext_host_addr);
3056     }
3057   s = format (s, "       last heard %.2f\n", sess->last_heard);
3058   s = format (s, "       total pkts %d, total bytes %lld\n",
3059               sess->total_pkts, sess->total_bytes);
3060   if (snat_is_session_static (sess))
3061     s = format (s, "       static translation\n");
3062   else
3063     s = format (s, "       dynamic translation\n");
3064   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
3065     s = format (s, "       load-balancing\n");
3066   if (is_twice_nat_session (sess))
3067     s = format (s, "       twice-nat\n");
3068
3069   return s;
3070 }
3071
3072 u8 * format_snat_user (u8 * s, va_list * args)
3073 {
3074   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
3075   snat_user_t * u = va_arg (*args, snat_user_t *);
3076   int verbose = va_arg (*args, int);
3077   dlist_elt_t * head, * elt;
3078   u32 elt_index, head_index;
3079   u32 session_index;
3080   snat_session_t * sess;
3081
3082   s = format (s, "%U: %d dynamic translations, %d static translations\n",
3083               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
3084
3085   if (verbose == 0)
3086     return s;
3087
3088   if (u->nsessions || u->nstaticsessions)
3089     {
3090       head_index = u->sessions_per_user_list_head_index;
3091       head = pool_elt_at_index (sm->list_pool, head_index);
3092
3093       elt_index = head->next;
3094       elt = pool_elt_at_index (sm->list_pool, elt_index);
3095       session_index = elt->value;
3096
3097       while (session_index != ~0)
3098         {
3099           sess = pool_elt_at_index (sm->sessions, session_index);
3100
3101           s = format (s, "  %U\n", format_snat_session, sm, sess);
3102
3103           elt_index = elt->next;
3104           elt = pool_elt_at_index (sm->list_pool, elt_index);
3105           session_index = elt->value;
3106         }
3107     }
3108
3109   return s;
3110 }
3111
3112 u8 * format_snat_static_mapping (u8 * s, va_list * args)
3113 {
3114   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
3115   nat44_lb_addr_port_t *local;
3116
3117   if (m->addr_only)
3118       s = format (s, "local %U external %U vrf %d %s",
3119                   format_ip4_address, &m->local_addr,
3120                   format_ip4_address, &m->external_addr,
3121                   m->vrf_id, m->twice_nat ? "twice-nat" : "");
3122   else
3123    {
3124       if (vec_len (m->locals))
3125         {
3126           s = format (s, "%U vrf %d external %U:%d %s",
3127                       format_snat_protocol, m->proto,
3128                       m->vrf_id,
3129                       format_ip4_address, &m->external_addr, m->external_port,
3130                       m->twice_nat ? "twice-nat" : "");
3131           vec_foreach (local, m->locals)
3132             s = format (s, "\n  local %U:%d probability %d\%",
3133                         format_ip4_address, &local->addr, local->port,
3134                         local->probability);
3135         }
3136       else
3137         s = format (s, "%U local %U:%d external %U:%d vrf %d %s",
3138                     format_snat_protocol, m->proto,
3139                     format_ip4_address, &m->local_addr, m->local_port,
3140                     format_ip4_address, &m->external_addr, m->external_port,
3141                     m->vrf_id, m->twice_nat ? "twice-nat" : "");
3142    }
3143   return s;
3144 }
3145
3146 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
3147 {
3148   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
3149   vnet_main_t *vnm = vnet_get_main();
3150
3151   if (m->addr_only)
3152       s = format (s, "local %U external %U vrf %d",
3153                   format_ip4_address, &m->l_addr,
3154                   format_vnet_sw_interface_name, vnm,
3155                   vnet_get_sw_interface (vnm, m->sw_if_index),
3156                   m->vrf_id);
3157   else
3158       s = format (s, "%U local %U:%d external %U:%d vrf %d",
3159                   format_snat_protocol, m->proto,
3160                   format_ip4_address, &m->l_addr, m->l_port,
3161                   format_vnet_sw_interface_name, vnm,
3162                   vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
3163                   m->vrf_id);
3164
3165   return s;
3166 }
3167
3168 u8 * format_det_map_ses (u8 * s, va_list * args)
3169 {
3170   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
3171   ip4_address_t in_addr, out_addr;
3172   u32 in_offset, out_offset;
3173   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
3174   u32 * i = va_arg (*args, u32 *);
3175
3176   u32 user_index = *i / SNAT_DET_SES_PER_USER;
3177   in_addr.as_u32 = clib_host_to_net_u32 (
3178     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
3179   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
3180     clib_net_to_host_u32(det_map->in_addr.as_u32);
3181   out_offset = in_offset / det_map->sharing_ratio;
3182   out_addr.as_u32 = clib_host_to_net_u32(
3183     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
3184   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
3185               format_ip4_address, &in_addr,
3186               clib_net_to_host_u16 (ses->in_port),
3187               format_ip4_address, &out_addr,
3188               clib_net_to_host_u16 (ses->out.out_port),
3189               format_ip4_address, &ses->out.ext_host_addr,
3190               clib_net_to_host_u16 (ses->out.ext_host_port),
3191               format_snat_session_state, ses->state,
3192               ses->expire);
3193
3194   return s;
3195 }
3196
3197 static clib_error_t *
3198 show_snat_command_fn (vlib_main_t * vm,
3199                  unformat_input_t * input,
3200                  vlib_cli_command_t * cmd)
3201 {
3202   int verbose = 0;
3203   snat_main_t * sm = &snat_main;
3204   snat_user_t * u;
3205   snat_static_mapping_t *m;
3206   snat_interface_t *i;
3207   snat_address_t * ap;
3208   vnet_main_t *vnm = vnet_get_main();
3209   snat_main_per_thread_data_t *tsm;
3210   u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
3211   uword j = 0;
3212   snat_static_map_resolve_t *rp;
3213   snat_det_map_t * dm;
3214   snat_det_session_t * ses;
3215
3216   if (unformat (input, "detail"))
3217     verbose = 1;
3218   else if (unformat (input, "verbose"))
3219     verbose = 2;
3220
3221   if (sm->static_mapping_only)
3222     {
3223       if (sm->static_mapping_connection_tracking)
3224         vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
3225                          "tracking");
3226       else
3227         vlib_cli_output (vm, "NAT plugin mode: static mapping only");
3228     }
3229   else if (sm->deterministic)
3230     {
3231       vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
3232     }
3233   else
3234     {
3235       vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
3236     }
3237
3238   if (verbose > 0)
3239     {
3240       pool_foreach (i, sm->interfaces,
3241       ({
3242         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
3243                          vnet_get_sw_interface (vnm, i->sw_if_index),
3244                          (nat_interface_is_inside(i) &&
3245                           nat_interface_is_outside(i)) ? "in out" :
3246                          (nat_interface_is_inside(i) ? "in" : "out"));
3247       }));
3248
3249       pool_foreach (i, sm->output_feature_interfaces,
3250       ({
3251         vlib_cli_output (vm, "%U output-feature %s",
3252                          format_vnet_sw_interface_name, vnm,
3253                          vnet_get_sw_interface (vnm, i->sw_if_index),
3254                          (nat_interface_is_inside(i) &&
3255                           nat_interface_is_outside(i)) ? "in out" :
3256                          (nat_interface_is_inside(i) ? "in" : "out"));
3257       }));
3258
3259       if (vec_len (sm->auto_add_sw_if_indices))
3260         {
3261           vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
3262           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
3263             {
3264               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
3265                                vnet_get_sw_interface (vnm, *sw_if_index));
3266             }
3267         }
3268
3269       if (vec_len (sm->auto_add_sw_if_indices_twice_nat))
3270         {
3271           vlib_cli_output (vm, "NAT44 twice-nat pool addresses interfaces:");
3272           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
3273             {
3274               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
3275                                vnet_get_sw_interface (vnm, *sw_if_index));
3276             }
3277         }
3278
3279       vlib_cli_output (vm, "NAT44 pool addresses:");
3280       vec_foreach (ap, sm->addresses)
3281         {
3282           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3283           if (ap->fib_index != ~0)
3284               vlib_cli_output (vm, "  tenant VRF: %u",
3285                                ip4_fib_get(ap->fib_index)->table_id);
3286           else
3287             vlib_cli_output (vm, "  tenant VRF independent");
3288 #define _(N, i, n, s) \
3289           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
3290           foreach_snat_protocol
3291 #undef _
3292         }
3293
3294       vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
3295       vec_foreach (ap, sm->twice_nat_addresses)
3296         {
3297           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
3298           if (ap->fib_index != ~0)
3299               vlib_cli_output (vm, "  tenant VRF: %u",
3300                                ip4_fib_get(ap->fib_index)->table_id);
3301           else
3302             vlib_cli_output (vm, "  tenant VRF independent");
3303 #define _(N, i, n, s) \
3304           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
3305           foreach_snat_protocol
3306 #undef _
3307         }
3308     }
3309
3310   if (sm->num_workers > 1)
3311     {
3312       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
3313       if (verbose > 0)
3314         {
3315           vec_foreach (worker, sm->workers)
3316             {
3317               vlib_worker_thread_t *w =
3318                 vlib_worker_threads + *worker + sm->first_worker_index;
3319               vlib_cli_output (vm, "  %s", w->name);
3320             }
3321         }
3322     }
3323
3324   if (sm->deterministic)
3325     {
3326       vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
3327       vlib_cli_output (vm, "tcp-established timeout: %dsec",
3328                        sm->tcp_established_timeout);
3329       vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
3330                        sm->tcp_transitory_timeout);
3331       vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
3332       vlib_cli_output (vm, "%d deterministic mappings",
3333                        pool_elts (sm->det_maps));
3334       if (verbose > 0)
3335         {
3336           pool_foreach (dm, sm->det_maps,
3337           ({
3338             vlib_cli_output (vm, "in %U/%d out %U/%d\n",
3339                              format_ip4_address, &dm->in_addr, dm->in_plen,
3340                              format_ip4_address, &dm->out_addr, dm->out_plen);
3341             vlib_cli_output (vm, " outside address sharing ratio: %d\n",
3342                              dm->sharing_ratio);
3343             vlib_cli_output (vm, " number of ports per inside host: %d\n",
3344                              dm->ports_per_host);
3345             vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
3346             if (verbose > 1)
3347               {
3348                 vec_foreach_index (j, dm->sessions)
3349                   {
3350                     ses = vec_elt_at_index (dm->sessions, j);
3351                     if (ses->in_port)
3352                       vlib_cli_output (vm, "  %U", format_det_map_ses, dm, ses,
3353                                        &j);
3354                   }
3355               }
3356           }));
3357         }
3358     }
3359   else
3360     {
3361       if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
3362         {
3363           vlib_cli_output (vm, "%d static mappings",
3364                            pool_elts (sm->static_mappings));
3365
3366           if (verbose > 0)
3367             {
3368               pool_foreach (m, sm->static_mappings,
3369               ({
3370                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3371               }));
3372             }
3373         }
3374       else
3375         {
3376           vec_foreach (tsm, sm->per_thread_data)
3377             {
3378               users_num += pool_elts (tsm->users);
3379               sessions_num += pool_elts (tsm->sessions);
3380             }
3381
3382           vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3383                            " %d static mappings, %d twice-nat addresses",
3384                            users_num,
3385                            vec_len (sm->addresses),
3386                            sessions_num,
3387                            pool_elts (sm->static_mappings),
3388                            vec_len (sm->twice_nat_addresses));
3389
3390           if (verbose > 0)
3391             {
3392               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3393                                verbose - 1);
3394               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3395                                verbose - 1);
3396               vec_foreach_index (j, sm->per_thread_data)
3397                 {
3398                   tsm = vec_elt_at_index (sm->per_thread_data, j);
3399
3400                   if (pool_elts (tsm->users) == 0)
3401                     continue;
3402
3403                   vlib_worker_thread_t *w = vlib_worker_threads + j;
3404                   vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3405                                    w->lcore_id);
3406                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->in2out,
3407                                    verbose - 1);
3408                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->out2in,
3409                                    verbose - 1);
3410                   vlib_cli_output (vm, "  %d list pool elements",
3411                                    pool_elts (tsm->list_pool));
3412
3413                   pool_foreach (u, tsm->users,
3414                   ({
3415                     vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
3416                                      verbose - 1);
3417                   }));
3418                 }
3419
3420               if (pool_elts (sm->static_mappings))
3421                 {
3422                   vlib_cli_output (vm, "static mappings:");
3423                   pool_foreach (m, sm->static_mappings,
3424                   ({
3425                     vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3426                   }));
3427                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3428                     {
3429                       rp = sm->to_resolve + j;
3430                       vlib_cli_output (vm, "%U",
3431                                        format_snat_static_map_to_resolve, rp);
3432                     }
3433                 }
3434             }
3435         }
3436     }
3437
3438   return 0;
3439 }
3440
3441 VLIB_CLI_COMMAND (show_snat_command, static) = {
3442     .path = "show nat44",
3443     .short_help = "show nat44",
3444     .function = show_snat_command_fn,
3445 };
3446
3447
3448 static void
3449 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3450                                        uword opaque,
3451                                        u32 sw_if_index,
3452                                        ip4_address_t * address,
3453                                        u32 address_length,
3454                                        u32 if_address_index,
3455                                        u32 is_delete)
3456 {
3457   snat_main_t *sm = &snat_main;
3458   snat_static_map_resolve_t *rp;
3459   u32 *indices_to_delete = 0;
3460   ip4_address_t l_addr;
3461   int i, j;
3462   int rv;
3463   u8 twice_nat = 0;
3464   snat_address_t *addresses = sm->addresses;
3465
3466   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3467     {
3468       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3469           goto match;
3470     }
3471
3472   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++)
3473     {
3474       twice_nat = 1;
3475       addresses = sm->twice_nat_addresses;
3476       if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i])
3477           goto match;
3478     }
3479
3480   return;
3481
3482 match:
3483   if (!is_delete)
3484     {
3485       /* Don't trip over lease renewal, static config */
3486       for (j = 0; j < vec_len(addresses); j++)
3487         if (addresses[j].addr.as_u32 == address->as_u32)
3488           return;
3489
3490       snat_add_address (sm, address, ~0, twice_nat);
3491       /* Scan static map resolution vector */
3492       for (j = 0; j < vec_len (sm->to_resolve); j++)
3493         {
3494           rp = sm->to_resolve + j;
3495           /* On this interface? */
3496           if (rp->sw_if_index == sw_if_index)
3497             {
3498               /* Indetity mapping? */
3499               if (rp->l_addr.as_u32 == 0)
3500                 l_addr.as_u32 = address[0].as_u32;
3501               else
3502                 l_addr.as_u32 = rp->l_addr.as_u32;
3503               /* Add the static mapping */
3504               rv = snat_add_static_mapping (l_addr,
3505                                             address[0],
3506                                             rp->l_port,
3507                                             rp->e_port,
3508                                             rp->vrf_id,
3509                                             rp->addr_only,
3510                                             ~0 /* sw_if_index */,
3511                                             rp->proto,
3512                                             rp->is_add,
3513                                             0);
3514               if (rv)
3515                 clib_warning ("snat_add_static_mapping returned %d",
3516                               rv);
3517               vec_add1 (indices_to_delete, j);
3518             }
3519         }
3520       /* If we resolved any of the outstanding static mappings */
3521       if (vec_len(indices_to_delete))
3522         {
3523           /* Delete them */
3524           for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3525             vec_delete(sm->to_resolve, 1, j);
3526           vec_free(indices_to_delete);
3527         }
3528       return;
3529     }
3530   else
3531     {
3532       (void) snat_del_address(sm, address[0], 1, twice_nat);
3533       return;
3534     }
3535 }
3536
3537
3538 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del,
3539                                 u8 twice_nat)
3540 {
3541   ip4_main_t * ip4_main = sm->ip4_main;
3542   ip4_address_t * first_int_addr;
3543   snat_static_map_resolve_t *rp;
3544   u32 *indices_to_delete = 0;
3545   int i, j;
3546   u32 *auto_add_sw_if_indices =
3547     twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices;
3548
3549   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3550                                                 0 /* just want the address*/);
3551
3552   for (i = 0; i < vec_len(auto_add_sw_if_indices); i++)
3553     {
3554       if (auto_add_sw_if_indices[i] == sw_if_index)
3555         {
3556           if (is_del)
3557             {
3558               /* if have address remove it */
3559               if (first_int_addr)
3560                   (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat);
3561               else
3562                 {
3563                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3564                     {
3565                       rp = sm->to_resolve + j;
3566                       if (rp->sw_if_index == sw_if_index)
3567                         vec_add1 (indices_to_delete, j);
3568                     }
3569                   if (vec_len(indices_to_delete))
3570                     {
3571                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3572                         vec_del1(sm->to_resolve, j);
3573                       vec_free(indices_to_delete);
3574                     }
3575                 }
3576               if (twice_nat)
3577                 vec_del1(sm->auto_add_sw_if_indices_twice_nat, i);
3578               else
3579                 vec_del1(sm->auto_add_sw_if_indices, i);
3580             }
3581           else
3582             return VNET_API_ERROR_VALUE_EXIST;
3583
3584           return 0;
3585         }
3586     }
3587
3588   if (is_del)
3589     return VNET_API_ERROR_NO_SUCH_ENTRY;
3590
3591   /* add to the auto-address list */
3592   if (twice_nat)
3593     vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index);
3594   else
3595     vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3596
3597   /* If the address is already bound - or static - add it now */
3598   if (first_int_addr)
3599       snat_add_address (sm, first_int_addr, ~0, twice_nat);
3600
3601   return 0;
3602 }
3603
3604 static clib_error_t *
3605 snat_add_interface_address_command_fn (vlib_main_t * vm,
3606                                        unformat_input_t * input,
3607                                        vlib_cli_command_t * cmd)
3608 {
3609   snat_main_t *sm = &snat_main;
3610   unformat_input_t _line_input, *line_input = &_line_input;
3611   u32 sw_if_index;
3612   int rv;
3613   int is_del = 0;
3614   clib_error_t *error = 0;
3615   u8 twice_nat = 0;
3616
3617   /* Get a line of input. */
3618   if (!unformat_user (input, unformat_line_input, line_input))
3619     return 0;
3620
3621   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3622     {
3623       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3624                     sm->vnet_main, &sw_if_index))
3625         ;
3626       else if (unformat (line_input, "twice-nat"))
3627         twice_nat = 1;
3628       else if (unformat (line_input, "del"))
3629         is_del = 1;
3630       else
3631         {
3632           error = clib_error_return (0, "unknown input '%U'",
3633                                      format_unformat_error, line_input);
3634           goto done;
3635         }
3636     }
3637
3638   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
3639
3640   switch (rv)
3641     {
3642     case 0:
3643       break;
3644
3645     default:
3646       error = clib_error_return (0, "snat_add_interface_address returned %d",
3647                                  rv);
3648       goto done;
3649     }
3650
3651 done:
3652   unformat_free (line_input);
3653
3654   return error;
3655 }
3656
3657 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3658     .path = "nat44 add interface address",
3659     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
3660     .function = snat_add_interface_address_command_fn,
3661 };
3662
3663 int
3664 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3665                    snat_protocol_t proto, u32 vrf_id, int is_in)
3666 {
3667   snat_main_per_thread_data_t *tsm;
3668   clib_bihash_kv_8_8_t kv, value;
3669   ip4_header_t ip;
3670   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3671   snat_session_key_t key;
3672   snat_session_t *s;
3673   clib_bihash_8_8_t *t;
3674   snat_user_key_t u_key;
3675   snat_user_t *u;
3676
3677   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3678   if (sm->num_workers)
3679     tsm =
3680       vec_elt_at_index (sm->per_thread_data,
3681                         sm->worker_in2out_cb (&ip, fib_index));
3682   else
3683     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3684
3685   key.addr.as_u32 = addr->as_u32;
3686   key.port = clib_host_to_net_u16 (port);
3687   key.protocol = proto;
3688   key.fib_index = fib_index;
3689   kv.key = key.as_u64;
3690   t = is_in ? &tsm->in2out : &tsm->out2in;
3691   if (!clib_bihash_search_8_8 (t, &kv, &value))
3692     {
3693       s = pool_elt_at_index (tsm->sessions, value.value);
3694       kv.key = s->in2out.as_u64;
3695       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3696       kv.key = s->out2in.as_u64;
3697       clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3698       u_key.addr = s->in2out.addr;
3699       u_key.fib_index = s->in2out.fib_index;
3700       kv.key = u_key.as_u64;
3701       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3702         {
3703           u = pool_elt_at_index (tsm->users, value.value);
3704           u->nsessions--;
3705         }
3706       clib_dlist_remove (tsm->list_pool, s->per_user_index);
3707       pool_put (tsm->sessions, s);
3708       return 0;
3709     }
3710
3711   return VNET_API_ERROR_NO_SUCH_ENTRY;
3712 }
3713
3714 static clib_error_t *
3715 nat44_del_session_command_fn (vlib_main_t * vm,
3716                               unformat_input_t * input,
3717                               vlib_cli_command_t * cmd)
3718 {
3719   snat_main_t *sm = &snat_main;
3720   unformat_input_t _line_input, *line_input = &_line_input;
3721   int is_in = 0;
3722   clib_error_t *error = 0;
3723   ip4_address_t addr;
3724   u32 port = 0, vrf_id = sm->outside_vrf_id;
3725   snat_protocol_t proto;
3726   int rv;
3727
3728   /* Get a line of input. */
3729   if (!unformat_user (input, unformat_line_input, line_input))
3730     return 0;
3731
3732   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3733     {
3734       if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3735           unformat_snat_protocol, &proto))
3736         ;
3737       else if (unformat (line_input, "in"))
3738         {
3739           is_in = 1;
3740           vrf_id = sm->inside_vrf_id;
3741         }
3742       else if (unformat (line_input, "vrf %u", &vrf_id))
3743         ;
3744       else
3745         {
3746           error = clib_error_return (0, "unknown input '%U'",
3747                                      format_unformat_error, line_input);
3748           goto done;
3749         }
3750     }
3751
3752   rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3753
3754   switch (rv)
3755     {
3756     case 0:
3757       break;
3758
3759     default:
3760       error = clib_error_return (0, "nat44_del_session returned %d", rv);
3761       goto done;
3762     }
3763
3764 done:
3765   unformat_free (line_input);
3766
3767   return error;
3768 }
3769
3770 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3771     .path = "nat44 del session",
3772     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3773     .function = nat44_del_session_command_fn,
3774 };
3775
3776 static clib_error_t *
3777 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
3778                                               unformat_input_t * input,
3779                                               vlib_cli_command_t * cmd)
3780 {
3781   snat_main_t *sm = &snat_main;
3782   unformat_input_t _line_input, *line_input = &_line_input;
3783   clib_error_t *error = 0;
3784   u32 psid, psid_offset, psid_length;
3785
3786   /* Get a line of input. */
3787   if (!unformat_user (input, unformat_line_input, line_input))
3788     return 0;
3789
3790   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3791     {
3792       if (unformat (line_input, "default"))
3793         sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3794       else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3795                &psid, &psid_offset, &psid_length))
3796         {
3797           sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3798           sm->psid = (u16) psid;
3799           sm->psid_offset = (u16) psid_offset;
3800           sm->psid_length = (u16) psid_length;
3801         }
3802       else
3803         {
3804           error = clib_error_return (0, "unknown input '%U'",
3805                                      format_unformat_error, line_input);
3806           goto done;
3807         }
3808     }
3809
3810 done:
3811   unformat_free (line_input);
3812
3813   return error;
3814 };
3815
3816 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3817     .path = "nat addr-port-assignment-alg",
3818     .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
3819     .function = nat44_set_alloc_addr_and_port_alg_command_fn,
3820 };
3821
3822 static clib_error_t *
3823 snat_det_map_command_fn (vlib_main_t * vm,
3824                          unformat_input_t * input,
3825                          vlib_cli_command_t * cmd)
3826 {
3827   snat_main_t *sm = &snat_main;
3828   unformat_input_t _line_input, *line_input = &_line_input;
3829   ip4_address_t in_addr, out_addr;
3830   u32 in_plen, out_plen;
3831   int is_add = 1, rv;
3832   clib_error_t *error = 0;
3833
3834   /* Get a line of input. */
3835   if (!unformat_user (input, unformat_line_input, line_input))
3836     return 0;
3837
3838   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3839     {
3840       if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3841         ;
3842       else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3843         ;
3844       else if (unformat (line_input, "del"))
3845         is_add = 0;
3846       else
3847         {
3848           error = clib_error_return (0, "unknown input '%U'",
3849                                      format_unformat_error, line_input);
3850           goto done;
3851         }
3852     }
3853
3854   rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3855                         is_add);
3856
3857   if (rv)
3858     {
3859       error = clib_error_return (0, "snat_det_add_map return %d", rv);
3860       goto done;
3861     }
3862
3863 done:
3864   unformat_free (line_input);
3865
3866   return error;
3867 }
3868
3869 /*?
3870  * @cliexpar
3871  * @cliexstart{snat deterministic add}
3872  * Create bijective mapping of inside address to outside address and port range
3873  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3874  * CGN deployments.
3875  * To create deterministic mapping between inside network 10.0.0.0/18 and
3876  * outside network 1.1.1.0/30 use:
3877  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3878  * @cliexend
3879 ?*/
3880 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3881     .path = "nat44 deterministic add",
3882     .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3883     .function = snat_det_map_command_fn,
3884 };
3885
3886 static clib_error_t *
3887 snat_det_forward_command_fn (vlib_main_t * vm,
3888                              unformat_input_t * input,
3889                              vlib_cli_command_t * cmd)
3890 {
3891   snat_main_t *sm = &snat_main;
3892   unformat_input_t _line_input, *line_input = &_line_input;
3893   ip4_address_t in_addr, out_addr;
3894   u16 lo_port;
3895   snat_det_map_t * dm;
3896   clib_error_t *error = 0;
3897
3898   /* Get a line of input. */
3899   if (!unformat_user (input, unformat_line_input, line_input))
3900     return 0;
3901
3902   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3903     {
3904       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3905         ;
3906       else
3907         {
3908           error = clib_error_return (0, "unknown input '%U'",
3909                                      format_unformat_error, line_input);
3910           goto done;
3911         }
3912     }
3913
3914   dm = snat_det_map_by_user(sm, &in_addr);
3915   if (!dm)
3916     vlib_cli_output (vm, "no match");
3917   else
3918     {
3919       snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3920       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3921                        lo_port, lo_port + dm->ports_per_host - 1);
3922     }
3923
3924 done:
3925   unformat_free (line_input);
3926
3927   return error;
3928 }
3929
3930 /*?
3931  * @cliexpar
3932  * @cliexstart{snat deterministic forward}
3933  * Return outside address and port range from inside address for deterministic
3934  * NAT.
3935  * To obtain outside address and port of inside host use:
3936  *  vpp# nat44 deterministic forward 10.0.0.2
3937  *  1.1.1.0:<1054-1068>
3938  * @cliexend
3939 ?*/
3940 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3941     .path = "nat44 deterministic forward",
3942     .short_help = "nat44 deterministic forward <addr>",
3943     .function = snat_det_forward_command_fn,
3944 };
3945
3946 static clib_error_t *
3947 snat_det_reverse_command_fn (vlib_main_t * vm,
3948                              unformat_input_t * input,
3949                              vlib_cli_command_t * cmd)
3950 {
3951   snat_main_t *sm = &snat_main;
3952   unformat_input_t _line_input, *line_input = &_line_input;
3953   ip4_address_t in_addr, out_addr;
3954   u32 out_port;
3955   snat_det_map_t * dm;
3956   clib_error_t *error = 0;
3957
3958   /* Get a line of input. */
3959   if (!unformat_user (input, unformat_line_input, line_input))
3960     return 0;
3961
3962   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3963     {
3964       if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3965         ;
3966       else
3967         {
3968           error =  clib_error_return (0, "unknown input '%U'",
3969                                       format_unformat_error, line_input);
3970         }
3971     }
3972
3973   if (out_port < 1024 || out_port > 65535)
3974     {
3975       error = clib_error_return (0, "wrong port, must be <1024-65535>");
3976       goto done;
3977     }
3978
3979   dm = snat_det_map_by_out(sm, &out_addr);
3980   if (!dm)
3981     vlib_cli_output (vm, "no match");
3982   else
3983     {
3984       snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3985       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3986     }
3987
3988 done:
3989   unformat_free (line_input);
3990
3991   return error;
3992 }
3993
3994 /*?
3995  * @cliexpar
3996  * @cliexstart{snat deterministic reverse}
3997  * Return inside address from outside address and port for deterministic NAT.
3998  * To obtain inside host address from outside address and port use:
3999  *  #vpp nat44 deterministic reverse 1.1.1.1:1276
4000  *  10.0.16.16
4001  * @cliexend
4002 ?*/
4003 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
4004     .path = "nat44 deterministic reverse",
4005     .short_help = "nat44 deterministic reverse <addr>:<port>",
4006     .function = snat_det_reverse_command_fn,
4007 };
4008
4009 static clib_error_t *
4010 set_timeout_command_fn (vlib_main_t * vm,
4011                         unformat_input_t * input,
4012                         vlib_cli_command_t * cmd)
4013 {
4014   snat_main_t *sm = &snat_main;
4015   unformat_input_t _line_input, *line_input = &_line_input;
4016   clib_error_t *error = 0;
4017
4018   /* Get a line of input. */
4019   if (!unformat_user (input, unformat_line_input, line_input))
4020     return 0;
4021
4022   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4023     {
4024       if (unformat (line_input, "udp %u", &sm->udp_timeout))
4025         ;
4026       else if (unformat (line_input, "tcp-established %u",
4027                &sm->tcp_established_timeout))
4028         ;
4029       else if (unformat (line_input, "tcp-transitory %u",
4030                &sm->tcp_transitory_timeout))
4031         ;
4032       else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
4033         ;
4034       else if (unformat (line_input, "reset"))
4035         {
4036           sm->udp_timeout = SNAT_UDP_TIMEOUT;
4037           sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
4038           sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
4039           sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
4040         }
4041       else
4042         {
4043           error = clib_error_return (0, "unknown input '%U'",
4044                                      format_unformat_error, line_input);
4045           goto done;
4046         }
4047     }
4048
4049 done:
4050   unformat_free (line_input);
4051
4052   return error;
4053 }
4054
4055 /*?
4056  * @cliexpar
4057  * @cliexstart{set snat deterministic timeout}
4058  * Set values of timeouts for deterministic NAT (in seconds), use:
4059  *  vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
4060  *  tcp-transitory 250 icmp 90
4061  * To reset default values use:
4062  *  vpp# set nat44 deterministic timeout reset
4063  * @cliexend
4064 ?*/
4065 VLIB_CLI_COMMAND (set_timeout_command, static) = {
4066   .path = "set nat44 deterministic timeout",
4067   .function = set_timeout_command_fn,
4068   .short_help =
4069     "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
4070     "tcp-transitory <sec> | icmp <sec> | reset]",
4071 };
4072
4073 static clib_error_t *
4074 snat_det_close_session_out_fn (vlib_main_t *vm,
4075                                unformat_input_t * input,
4076                                vlib_cli_command_t * cmd)
4077 {
4078   snat_main_t *sm = &snat_main;
4079   unformat_input_t _line_input, *line_input = &_line_input;
4080   ip4_address_t out_addr, ext_addr, in_addr;
4081   u32 out_port, ext_port;
4082   snat_det_map_t * dm;
4083   snat_det_session_t * ses;
4084   snat_det_out_key_t key;
4085   clib_error_t *error = 0;
4086
4087   /* Get a line of input. */
4088   if (!unformat_user (input, unformat_line_input, line_input))
4089     return 0;
4090
4091   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4092     {
4093       if (unformat (line_input, "%U:%d %U:%d",
4094                     unformat_ip4_address, &out_addr, &out_port,
4095                     unformat_ip4_address, &ext_addr, &ext_port))
4096         ;
4097       else
4098         {
4099           error = clib_error_return (0, "unknown input '%U'",
4100                                      format_unformat_error, line_input);
4101           goto done;
4102         }
4103     }
4104
4105   unformat_free (line_input);
4106
4107   dm = snat_det_map_by_out(sm, &out_addr);
4108   if (!dm)
4109     vlib_cli_output (vm, "no match");
4110   else
4111     {
4112       snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
4113       key.ext_host_addr = out_addr;
4114       key.ext_host_port = ntohs((u16)ext_port);
4115       key.out_port = ntohs((u16)out_port);
4116       ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
4117       if (!ses)
4118         vlib_cli_output (vm, "no match");
4119       else
4120        snat_det_ses_close(dm, ses);
4121     }
4122
4123 done:
4124   unformat_free (line_input);
4125
4126   return error;
4127 }
4128
4129 /*?
4130  * @cliexpar
4131  * @cliexstart{snat deterministic close session out}
4132  * Close session using outside ip address and port
4133  * and external ip address and port, use:
4134  *  vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
4135  * @cliexend
4136 ?*/
4137 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
4138   .path = "nat44 deterministic close session out",
4139   .short_help = "nat44 deterministic close session out "
4140                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
4141   .function = snat_det_close_session_out_fn,
4142 };
4143
4144 static clib_error_t *
4145 snat_det_close_session_in_fn (vlib_main_t *vm,
4146                               unformat_input_t * input,
4147                               vlib_cli_command_t * cmd)
4148 {
4149   snat_main_t *sm = &snat_main;
4150   unformat_input_t _line_input, *line_input = &_line_input;
4151   ip4_address_t in_addr, ext_addr;
4152   u32 in_port, ext_port;
4153   snat_det_map_t * dm;
4154   snat_det_session_t * ses;
4155   snat_det_out_key_t key;
4156   clib_error_t *error = 0;
4157
4158   /* Get a line of input. */
4159   if (!unformat_user (input, unformat_line_input, line_input))
4160     return 0;
4161
4162   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4163     {
4164       if (unformat (line_input, "%U:%d %U:%d",
4165                     unformat_ip4_address, &in_addr, &in_port,
4166                     unformat_ip4_address, &ext_addr, &ext_port))
4167         ;
4168       else
4169         {
4170           error = clib_error_return (0, "unknown input '%U'",
4171                                      format_unformat_error, line_input);
4172           goto done;
4173         }
4174     }
4175
4176   unformat_free (line_input);
4177
4178   dm = snat_det_map_by_user (sm, &in_addr);
4179   if (!dm)
4180     vlib_cli_output (vm, "no match");
4181   else
4182     {
4183       key.ext_host_addr = ext_addr;
4184       key.ext_host_port = ntohs ((u16)ext_port);
4185       ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
4186       if (!ses)
4187         vlib_cli_output (vm, "no match");
4188       else
4189         snat_det_ses_close(dm, ses);
4190     }
4191
4192 done:
4193   unformat_free(line_input);
4194
4195   return error;
4196 }
4197
4198 /*?
4199  * @cliexpar
4200  * @cliexstart{snat deterministic close_session_in}
4201  * Close session using inside ip address and port
4202  * and external ip address and port, use:
4203  *  vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
4204  * @cliexend
4205 ?*/
4206 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
4207   .path = "nat44 deterministic close session in",
4208   .short_help = "nat44 deterministic close session in "
4209                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
4210   .function = snat_det_close_session_in_fn,
4211 };
4212
4213 static clib_error_t *
4214 snat_forwarding_set_command_fn (vlib_main_t *vm,
4215                                 unformat_input_t * input,
4216                                 vlib_cli_command_t * cmd)
4217 {
4218   snat_main_t *sm = &snat_main;
4219   unformat_input_t _line_input, *line_input = &_line_input;
4220   u8 forwarding_enable;
4221   u8 forwarding_enable_set = 0;
4222   clib_error_t *error = 0;
4223
4224   /* Get a line of input. */
4225   if (!unformat_user (input, unformat_line_input, line_input))
4226       return clib_error_return (0, "'enable' or 'disable' expected");
4227
4228   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
4229     {
4230       if (!forwarding_enable_set && unformat (line_input, "enable"))
4231         {
4232           forwarding_enable = 1;
4233           forwarding_enable_set = 1;
4234         }
4235       else if (!forwarding_enable_set && unformat (line_input, "disable"))
4236         {
4237           forwarding_enable = 0;
4238           forwarding_enable_set = 1;
4239         }
4240       else
4241         {
4242           error = clib_error_return (0, "unknown input '%U'",
4243                                      format_unformat_error, line_input);
4244           goto done;
4245         }
4246     }
4247
4248   if (!forwarding_enable_set)
4249     {
4250       error = clib_error_return (0, "'enable' or 'disable' expected");
4251       goto done;
4252     }
4253
4254   sm->forwarding_enabled = forwarding_enable;
4255
4256 done:
4257   unformat_free(line_input);
4258
4259   return error;
4260 }
4261
4262 /*?
4263  * @cliexpar
4264  * @cliexstart{nat44 forwarding}
4265  * Enable or disable forwarding
4266  * Forward packets which don't match existing translation
4267  * or static mapping instead of dropping them.
4268  * To enable forwarding, use:
4269  *  vpp# nat44 forwarding enable
4270  * To disable forwarding, use:
4271  *  vpp# nat44 forwarding disable
4272  * @cliexend
4273 ?*/
4274 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
4275   .path = "nat44 forwarding",
4276   .short_help = "nat44 forwarding enable|disable",
4277   .function = snat_forwarding_set_command_fn,
4278 };