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