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