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