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