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