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