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