call unformat_free in some flow, remove unnecessary calls
[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 || (l_addr.as_u32 == e_addr.as_u32))
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) || (m->local_addr.as_u32 == m->external_addr.as_u32))
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 = ~0;
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_identity_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 addr;
2100   u32 port = 0, vrf_id = ~0;
2101   int is_add = 1;
2102   int addr_only = 1;
2103   u32 sw_if_index = ~0;
2104   vnet_main_t * vnm = vnet_get_main();
2105   int rv;
2106   snat_protocol_t proto;
2107
2108   addr.as_u32 = 0;
2109
2110   /* Get a line of input. */
2111   if (!unformat_user (input, unformat_line_input, line_input))
2112     return 0;
2113
2114   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2115     {
2116       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
2117         ;
2118       else if (unformat (line_input, "external %U",
2119                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2120         ;
2121       else if (unformat (line_input, "vrf %u", &vrf_id))
2122         ;
2123       else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
2124                          &port))
2125         addr_only = 0;
2126       else if (unformat (line_input, "del"))
2127         is_add = 0;
2128       else
2129         {
2130           error = clib_error_return (0, "unknown input: '%U'",
2131             format_unformat_error, line_input);
2132           goto done;
2133         }
2134     }
2135
2136   rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port,
2137                                vrf_id, addr_only, sw_if_index, proto, is_add);
2138
2139   switch (rv)
2140     {
2141     case VNET_API_ERROR_INVALID_VALUE:
2142       error = clib_error_return (0, "External port already in use.");
2143       goto done;
2144     case VNET_API_ERROR_NO_SUCH_ENTRY:
2145       if (is_add)
2146         error = clib_error_return (0, "External addres must be allocated.");
2147       else
2148         error = clib_error_return (0, "Mapping not exist.");
2149       goto done;
2150     case VNET_API_ERROR_NO_SUCH_FIB:
2151       error = clib_error_return (0, "No such VRF id.");
2152       goto done;
2153     case VNET_API_ERROR_VALUE_EXIST:
2154       error = clib_error_return (0, "Mapping already exist.");
2155       goto done;
2156     default:
2157       break;
2158     }
2159
2160 done:
2161   unformat_free (line_input);
2162
2163   return error;
2164 }
2165
2166 /*?
2167  * @cliexpar
2168  * @cliexstart{snat add identity mapping}
2169  * Identity mapping translate an IP address to itself.
2170  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2171  * use:
2172  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2173  * To create identity mapping for address 10.0.0.3 use:
2174  *  vpp# nat44 add identity mapping 10.0.0.3
2175  * To create identity mapping for DHCP addressed interface use:
2176  *  vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
2177  * @cliexend
2178 ?*/
2179 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2180   .path = "nat44 add identity mapping",
2181   .function = add_identity_mapping_command_fn,
2182   .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
2183     "[<protocol> <port>] [vrf <table-id>] [del]",
2184 };
2185
2186 static clib_error_t *
2187 add_lb_static_mapping_command_fn (vlib_main_t * vm,
2188                                   unformat_input_t * input,
2189                                   vlib_cli_command_t * cmd)
2190 {
2191   unformat_input_t _line_input, *line_input = &_line_input;
2192   clib_error_t * error = 0;
2193   ip4_address_t l_addr, e_addr;
2194   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
2195   int is_add = 1;
2196   int rv;
2197   snat_protocol_t proto;
2198   u8 proto_set = 0;
2199   nat44_lb_addr_port_t *locals = 0, local;
2200
2201   /* Get a line of input. */
2202   if (!unformat_user (input, unformat_line_input, line_input))
2203     return 0;
2204
2205   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2206     {
2207       if (unformat (line_input, "local %U:%u probability %u",
2208                     unformat_ip4_address, &l_addr, &l_port, &probability))
2209         {
2210           memset (&local, 0, sizeof (local));
2211           local.addr = l_addr;
2212           local.port = (u16) l_port;
2213           local.probability = (u8) probability;
2214           vec_add1 (locals, local);
2215         }
2216       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
2217                          &e_addr, &e_port))
2218         ;
2219       else if (unformat (line_input, "vrf %u", &vrf_id))
2220         ;
2221       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
2222                          &proto))
2223         proto_set = 1;
2224       else if (unformat (line_input, "del"))
2225         is_add = 0;
2226       else
2227         {
2228           error = clib_error_return (0, "unknown input: '%U'",
2229             format_unformat_error, line_input);
2230           goto done;
2231         }
2232     }
2233
2234   if (vec_len (locals) < 2)
2235     {
2236       error = clib_error_return (0, "at least two local must be set");
2237       goto done;
2238     }
2239
2240   if (!proto_set)
2241     {
2242       error = clib_error_return (0, "missing protocol");
2243       goto done;
2244     }
2245
2246   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id,
2247                                         locals, is_add);
2248
2249   switch (rv)
2250     {
2251     case VNET_API_ERROR_INVALID_VALUE:
2252       error = clib_error_return (0, "External port already in use.");
2253       goto done;
2254     case VNET_API_ERROR_NO_SUCH_ENTRY:
2255       if (is_add)
2256         error = clib_error_return (0, "External addres must be allocated.");
2257       else
2258         error = clib_error_return (0, "Mapping not exist.");
2259       goto done;
2260     case VNET_API_ERROR_VALUE_EXIST:
2261       error = clib_error_return (0, "Mapping already exist.");
2262       goto done;
2263     default:
2264       break;
2265     }
2266
2267 done:
2268   unformat_free (line_input);
2269   vec_free (locals);
2270
2271   return error;
2272 }
2273
2274 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2275   .path = "nat44 add load-balancing static mapping",
2276   .function = add_lb_static_mapping_command_fn,
2277   .short_help =
2278     "nat44 add load-balancing static mapping protocol tcp|udp external <addr>:<port> local <addr>:<port> probability <n> [vrf <table-id>] [del]",
2279 };
2280
2281 static clib_error_t *
2282 set_workers_command_fn (vlib_main_t * vm,
2283                         unformat_input_t * input,
2284                         vlib_cli_command_t * cmd)
2285 {
2286   unformat_input_t _line_input, *line_input = &_line_input;
2287   uword *bitmap = 0;
2288   int rv = 0;
2289   clib_error_t *error = 0;
2290
2291   /* Get a line of input. */
2292   if (!unformat_user (input, unformat_line_input, line_input))
2293     return 0;
2294
2295   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2296     {
2297       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2298         ;
2299       else
2300         {
2301           error = clib_error_return (0, "unknown input '%U'",
2302             format_unformat_error, line_input);
2303           goto done;
2304         }
2305      }
2306
2307   if (bitmap == 0)
2308     {
2309       error = clib_error_return (0, "List of workers must be specified.");
2310       goto done;
2311     }
2312
2313   rv = snat_set_workers(bitmap);
2314
2315   clib_bitmap_free (bitmap);
2316
2317   switch (rv)
2318     {
2319     case VNET_API_ERROR_INVALID_WORKER:
2320       error = clib_error_return (0, "Invalid worker(s).");
2321       goto done;
2322     case VNET_API_ERROR_FEATURE_DISABLED:
2323       error = clib_error_return (0,
2324         "Supported only if 2 or more workes available.");
2325       goto done;
2326     default:
2327       break;
2328     }
2329
2330 done:
2331   unformat_free (line_input);
2332
2333   return error;
2334 }
2335
2336 /*?
2337  * @cliexpar
2338  * @cliexstart{set snat workers}
2339  * Set NAT workers if 2 or more workers available, use:
2340  *  vpp# set snat workers 0-2,5
2341  * @cliexend
2342 ?*/
2343 VLIB_CLI_COMMAND (set_workers_command, static) = {
2344   .path = "set nat workers",
2345   .function = set_workers_command_fn,
2346   .short_help =
2347     "set nat workers <workers-list>",
2348 };
2349
2350 static clib_error_t *
2351 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2352                                               unformat_input_t * input,
2353                                               vlib_cli_command_t * cmd)
2354 {
2355   unformat_input_t _line_input, *line_input = &_line_input;
2356   u32 domain_id = 0;
2357   u32 src_port = 0;
2358   u8 enable = 1;
2359   int rv = 0;
2360   clib_error_t *error = 0;
2361
2362   /* Get a line of input. */
2363   if (!unformat_user (input, unformat_line_input, line_input))
2364     return 0;
2365
2366   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2367     {
2368       if (unformat (line_input, "domain %d", &domain_id))
2369         ;
2370       else if (unformat (line_input, "src-port %d", &src_port))
2371         ;
2372       else if (unformat (line_input, "disable"))
2373         enable = 0;
2374       else
2375         {
2376           error = clib_error_return (0, "unknown input '%U'",
2377             format_unformat_error, line_input);
2378           goto done;
2379         }
2380      }
2381
2382   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2383
2384   if (rv)
2385     {
2386       error = clib_error_return (0, "ipfix logging enable failed");
2387       goto done;
2388     }
2389
2390 done:
2391   unformat_free (line_input);
2392
2393   return error;
2394 }
2395
2396 /*?
2397  * @cliexpar
2398  * @cliexstart{snat ipfix logging}
2399  * To enable NAT IPFIX logging use:
2400  *  vpp# nat ipfix logging
2401  * To set IPFIX exporter use:
2402  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2403  * @cliexend
2404 ?*/
2405 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2406   .path = "nat ipfix logging",
2407   .function = snat_ipfix_logging_enable_disable_command_fn,
2408   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2409 };
2410
2411 static u32
2412 snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2413 {
2414   snat_main_t *sm = &snat_main;
2415   u32 next_worker_index = 0;
2416   u32 hash;
2417
2418   next_worker_index = sm->first_worker_index;
2419   hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) +
2420          (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24);
2421
2422   if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers))))
2423     next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)];
2424   else
2425     next_worker_index += sm->workers[hash % _vec_len (sm->workers)];
2426
2427   return next_worker_index;
2428 }
2429
2430 static u32
2431 snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0)
2432 {
2433   snat_main_t *sm = &snat_main;
2434   udp_header_t *udp;
2435   u16 port;
2436   snat_session_key_t m_key;
2437   clib_bihash_kv_8_8_t kv, value;
2438   snat_static_mapping_t *m;
2439   nat_ed_ses_key_t key;
2440   clib_bihash_kv_16_8_t s_kv, s_value;
2441   snat_main_per_thread_data_t *tsm;
2442   snat_session_t *s;
2443   int i;
2444   u32 proto;
2445
2446   /* first try static mappings without port */
2447   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2448     {
2449       m_key.addr = ip0->dst_address;
2450       m_key.port = 0;
2451       m_key.protocol = 0;
2452       m_key.fib_index = rx_fib_index0;
2453       kv.key = m_key.as_u64;
2454       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2455         {
2456           m = pool_elt_at_index (sm->static_mappings, value.value);
2457           return m->worker_index;
2458         }
2459     }
2460
2461   proto = ip_proto_to_snat_proto (ip0->protocol);
2462   udp = ip4_next_header (ip0);
2463   port = udp->dst_port;
2464
2465   /* unknown protocol */
2466   if (PREDICT_FALSE (proto == ~0))
2467     {
2468       key.l_addr = ip0->dst_address;
2469       key.r_addr = ip0->src_address;
2470       key.fib_index = rx_fib_index0;
2471       key.proto = ip0->protocol;
2472       key.rsvd = 0;
2473       key.l_port = 0;
2474       s_kv.key[0] = key.as_u64[0];
2475       s_kv.key[1] = key.as_u64[1];
2476
2477       if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
2478         {
2479           for (i = 0; i < _vec_len (sm->per_thread_data); i++)
2480             {
2481               tsm = vec_elt_at_index (sm->per_thread_data, i);
2482               if (!pool_is_free_index(tsm->sessions, s_value.value))
2483                 {
2484                   s = pool_elt_at_index (tsm->sessions, s_value.value);
2485                   if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 &&
2486                       s->out2in.port == ip0->protocol &&
2487                       snat_is_unk_proto_session (s))
2488                     return i;
2489                 }
2490             }
2491          }
2492
2493       /* if no session use current thread */
2494       return vlib_get_thread_index ();
2495     }
2496
2497   if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP))
2498     {
2499       icmp46_header_t * icmp = (icmp46_header_t *) udp;
2500       icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1);
2501       if (!icmp_is_error_message (icmp))
2502         port = echo->identifier;
2503       else
2504         {
2505           ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1);
2506           proto = ip_proto_to_snat_proto (inner_ip->protocol);
2507           void *l4_header = ip4_next_header (inner_ip);
2508           switch (proto)
2509             {
2510             case SNAT_PROTOCOL_ICMP:
2511               icmp = (icmp46_header_t*)l4_header;
2512               echo = (icmp_echo_header_t *)(icmp + 1);
2513               port = echo->identifier;
2514               break;
2515             case SNAT_PROTOCOL_UDP:
2516             case SNAT_PROTOCOL_TCP:
2517               port = ((tcp_udp_header_t*)l4_header)->src_port;
2518               break;
2519             default:
2520               return vlib_get_thread_index ();
2521             }
2522         }
2523     }
2524
2525   /* try static mappings with port */
2526   if (PREDICT_FALSE (pool_elts (sm->static_mappings)))
2527     {
2528       m_key.addr = ip0->dst_address;
2529       m_key.port = clib_net_to_host_u16 (port);
2530       m_key.protocol = proto;
2531       m_key.fib_index = rx_fib_index0;
2532       kv.key = m_key.as_u64;
2533       if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
2534         {
2535           m = pool_elt_at_index (sm->static_mappings, value.value);
2536           return m->worker_index;
2537         }
2538     }
2539
2540   /* worker by outside port */
2541   return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread);
2542 }
2543
2544 static clib_error_t *
2545 snat_config (vlib_main_t * vm, unformat_input_t * input)
2546 {
2547   snat_main_t * sm = &snat_main;
2548   u32 translation_buckets = 1024;
2549   u32 translation_memory_size = 128<<20;
2550   u32 user_buckets = 128;
2551   u32 user_memory_size = 64<<20;
2552   u32 max_translations_per_user = 100;
2553   u32 outside_vrf_id = 0;
2554   u32 inside_vrf_id = 0;
2555   u32 static_mapping_buckets = 1024;
2556   u32 static_mapping_memory_size = 64<<20;
2557   u8 static_mapping_only = 0;
2558   u8 static_mapping_connection_tracking = 0;
2559   snat_main_per_thread_data_t *tsm;
2560
2561   sm->deterministic = 0;
2562
2563   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2564     {
2565       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2566         ;
2567       else if (unformat (input, "translation hash memory %d",
2568                          &translation_memory_size));
2569       else if (unformat (input, "user hash buckets %d", &user_buckets))
2570         ;
2571       else if (unformat (input, "user hash memory %d",
2572                          &user_memory_size))
2573         ;
2574       else if (unformat (input, "max translations per user %d",
2575                          &max_translations_per_user))
2576         ;
2577       else if (unformat (input, "outside VRF id %d",
2578                          &outside_vrf_id))
2579         ;
2580       else if (unformat (input, "inside VRF id %d",
2581                          &inside_vrf_id))
2582         ;
2583       else if (unformat (input, "static mapping only"))
2584         {
2585           static_mapping_only = 1;
2586           if (unformat (input, "connection tracking"))
2587             static_mapping_connection_tracking = 1;
2588         }
2589       else if (unformat (input, "deterministic"))
2590         sm->deterministic = 1;
2591       else
2592         return clib_error_return (0, "unknown input '%U'",
2593                                   format_unformat_error, input);
2594     }
2595
2596   /* for show commands, etc. */
2597   sm->translation_buckets = translation_buckets;
2598   sm->translation_memory_size = translation_memory_size;
2599   /* do not exceed load factor 10 */
2600   sm->max_translations = 10 * translation_buckets;
2601   sm->user_buckets = user_buckets;
2602   sm->user_memory_size = user_memory_size;
2603   sm->max_translations_per_user = max_translations_per_user;
2604   sm->outside_vrf_id = outside_vrf_id;
2605   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2606                                                              outside_vrf_id,
2607                                                              FIB_SOURCE_PLUGIN_HI);
2608   sm->inside_vrf_id = inside_vrf_id;
2609   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2610                                                             inside_vrf_id,
2611                                                             FIB_SOURCE_PLUGIN_HI);
2612   sm->static_mapping_only = static_mapping_only;
2613   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2614
2615   if (sm->deterministic)
2616     {
2617       sm->in2out_node_index = snat_det_in2out_node.index;
2618       sm->in2out_output_node_index = ~0;
2619       sm->out2in_node_index = snat_det_out2in_node.index;
2620       sm->icmp_match_in2out_cb = icmp_match_in2out_det;
2621       sm->icmp_match_out2in_cb = icmp_match_out2in_det;
2622     }
2623   else
2624     {
2625       sm->worker_in2out_cb = snat_get_worker_in2out_cb;
2626       sm->worker_out2in_cb = snat_get_worker_out2in_cb;
2627       sm->in2out_node_index = snat_in2out_node.index;
2628       sm->in2out_output_node_index = snat_in2out_output_node.index;
2629       sm->out2in_node_index = snat_out2in_node.index;
2630       if (!static_mapping_only ||
2631           (static_mapping_only && static_mapping_connection_tracking))
2632         {
2633           sm->icmp_match_in2out_cb = icmp_match_in2out_slow;
2634           sm->icmp_match_out2in_cb = icmp_match_out2in_slow;
2635
2636           vec_foreach (tsm, sm->per_thread_data)
2637             {
2638               clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets,
2639                                     translation_memory_size);
2640
2641               clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets,
2642                                     translation_memory_size);
2643
2644               clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets,
2645                                     user_memory_size);
2646             }
2647
2648           clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed",
2649                                  translation_buckets, translation_memory_size);
2650
2651           clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed",
2652                                  translation_buckets, translation_memory_size);
2653         }
2654       else
2655         {
2656           sm->icmp_match_in2out_cb = icmp_match_in2out_fast;
2657           sm->icmp_match_out2in_cb = icmp_match_out2in_fast;
2658         }
2659       clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2660                             "static_mapping_by_local", static_mapping_buckets,
2661                             static_mapping_memory_size);
2662
2663       clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2664                             "static_mapping_by_external", static_mapping_buckets,
2665                             static_mapping_memory_size);
2666     }
2667
2668   return 0;
2669 }
2670
2671 VLIB_CONFIG_FUNCTION (snat_config, "nat");
2672
2673 u8 * format_snat_session_state (u8 * s, va_list * args)
2674 {
2675   u32 i = va_arg (*args, u32);
2676   u8 *t = 0;
2677
2678   switch (i)
2679     {
2680 #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break;
2681     foreach_snat_session_state
2682 #undef _
2683     default:
2684       t = format (t, "unknown");
2685     }
2686   s = format (s, "%s", t);
2687   return s;
2688 }
2689
2690 u8 * format_snat_key (u8 * s, va_list * args)
2691 {
2692   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2693
2694   s = format (s, "%U proto %U port %d fib %d",
2695               format_ip4_address, &key->addr,
2696               format_snat_protocol, key->protocol,
2697               clib_net_to_host_u16 (key->port), key->fib_index);
2698   return s;
2699 }
2700
2701 u8 * format_snat_session (u8 * s, va_list * args)
2702 {
2703   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2704   snat_session_t * sess = va_arg (*args, snat_session_t *);
2705
2706   if (snat_is_unk_proto_session (sess))
2707     {
2708       s = format (s, "  i2o %U proto %u fib %u\n",
2709                   format_ip4_address, &sess->in2out.addr, sess->in2out.port,
2710                   sess->in2out.fib_index);
2711       s = format (s, "    o2i %U proto %u fib %u\n",
2712                   format_ip4_address, &sess->out2in.addr, sess->out2in.port,
2713                   sess->out2in.fib_index);
2714     }
2715   else
2716     {
2717       s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2718       s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2719     }
2720   if (sess->ext_host_addr.as_u32)
2721       s = format (s, "       external host %U\n",
2722                   format_ip4_address, &sess->ext_host_addr);
2723   s = format (s, "       last heard %.2f\n", sess->last_heard);
2724   s = format (s, "       total pkts %d, total bytes %lld\n",
2725               sess->total_pkts, sess->total_bytes);
2726   if (snat_is_session_static (sess))
2727     s = format (s, "       static translation\n");
2728   else
2729     s = format (s, "       dynamic translation\n");
2730   if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING)
2731     s = format (s, "       load-balancing\n");
2732
2733   return s;
2734 }
2735
2736 u8 * format_snat_user (u8 * s, va_list * args)
2737 {
2738   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2739   snat_user_t * u = va_arg (*args, snat_user_t *);
2740   int verbose = va_arg (*args, int);
2741   dlist_elt_t * head, * elt;
2742   u32 elt_index, head_index;
2743   u32 session_index;
2744   snat_session_t * sess;
2745
2746   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2747               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2748
2749   if (verbose == 0)
2750     return s;
2751
2752   if (u->nsessions || u->nstaticsessions)
2753     {
2754       head_index = u->sessions_per_user_list_head_index;
2755       head = pool_elt_at_index (sm->list_pool, head_index);
2756
2757       elt_index = head->next;
2758       elt = pool_elt_at_index (sm->list_pool, elt_index);
2759       session_index = elt->value;
2760
2761       while (session_index != ~0)
2762         {
2763           sess = pool_elt_at_index (sm->sessions, session_index);
2764
2765           s = format (s, "  %U\n", format_snat_session, sm, sess);
2766
2767           elt_index = elt->next;
2768           elt = pool_elt_at_index (sm->list_pool, elt_index);
2769           session_index = elt->value;
2770         }
2771     }
2772
2773   return s;
2774 }
2775
2776 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2777 {
2778   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2779   nat44_lb_addr_port_t *local;
2780
2781   if (m->addr_only)
2782       s = format (s, "local %U external %U vrf %d",
2783                   format_ip4_address, &m->local_addr,
2784                   format_ip4_address, &m->external_addr,
2785                   m->vrf_id);
2786   else
2787    {
2788       if (vec_len (m->locals))
2789         {
2790           s = format (s, "%U vrf %d external %U:%d",
2791                       format_snat_protocol, m->proto,
2792                       m->vrf_id,
2793                       format_ip4_address, &m->external_addr, m->external_port);
2794           vec_foreach (local, m->locals)
2795             s = format (s, "\n  local %U:%d probability %d\%",
2796                         format_ip4_address, &local->addr, local->port,
2797                         local->probability);
2798         }
2799       else
2800         s = format (s, "%U local %U:%d external %U:%d vrf %d",
2801                     format_snat_protocol, m->proto,
2802                     format_ip4_address, &m->local_addr, m->local_port,
2803                     format_ip4_address, &m->external_addr, m->external_port,
2804                     m->vrf_id);
2805    }
2806   return s;
2807 }
2808
2809 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2810 {
2811   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2812   vnet_main_t *vnm = vnet_get_main();
2813
2814   if (m->addr_only)
2815       s = format (s, "local %U external %U vrf %d",
2816                   format_ip4_address, &m->l_addr,
2817                   format_vnet_sw_interface_name, vnm,
2818                   vnet_get_sw_interface (vnm, m->sw_if_index),
2819                   m->vrf_id);
2820   else
2821       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2822                   format_snat_protocol, m->proto,
2823                   format_ip4_address, &m->l_addr, m->l_port,
2824                   format_vnet_sw_interface_name, vnm,
2825                   vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2826                   m->vrf_id);
2827
2828   return s;
2829 }
2830
2831 u8 * format_det_map_ses (u8 * s, va_list * args)
2832 {
2833   snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *);
2834   ip4_address_t in_addr, out_addr;
2835   u32 in_offset, out_offset;
2836   snat_det_session_t * ses = va_arg (*args, snat_det_session_t *);
2837   u32 * i = va_arg (*args, u32 *);
2838
2839   u32 user_index = *i / SNAT_DET_SES_PER_USER;
2840   in_addr.as_u32 = clib_host_to_net_u32 (
2841     clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index);
2842   in_offset = clib_net_to_host_u32(in_addr.as_u32) -
2843     clib_net_to_host_u32(det_map->in_addr.as_u32);
2844   out_offset = in_offset / det_map->sharing_ratio;
2845   out_addr.as_u32 = clib_host_to_net_u32(
2846     clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset);
2847   s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n",
2848               format_ip4_address, &in_addr,
2849               clib_net_to_host_u16 (ses->in_port),
2850               format_ip4_address, &out_addr,
2851               clib_net_to_host_u16 (ses->out.out_port),
2852               format_ip4_address, &ses->out.ext_host_addr,
2853               clib_net_to_host_u16 (ses->out.ext_host_port),
2854               format_snat_session_state, ses->state,
2855               ses->expire);
2856
2857   return s;
2858 }
2859
2860 static clib_error_t *
2861 show_snat_command_fn (vlib_main_t * vm,
2862                  unformat_input_t * input,
2863                  vlib_cli_command_t * cmd)
2864 {
2865   int verbose = 0;
2866   snat_main_t * sm = &snat_main;
2867   snat_user_t * u;
2868   snat_static_mapping_t *m;
2869   snat_interface_t *i;
2870   snat_address_t * ap;
2871   vnet_main_t *vnm = vnet_get_main();
2872   snat_main_per_thread_data_t *tsm;
2873   u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2874   uword j = 0;
2875   snat_static_map_resolve_t *rp;
2876   snat_det_map_t * dm;
2877   snat_det_session_t * ses;
2878
2879   if (unformat (input, "detail"))
2880     verbose = 1;
2881   else if (unformat (input, "verbose"))
2882     verbose = 2;
2883
2884   if (sm->static_mapping_only)
2885     {
2886       if (sm->static_mapping_connection_tracking)
2887         vlib_cli_output (vm, "NAT plugin mode: static mapping only connection "
2888                          "tracking");
2889       else
2890         vlib_cli_output (vm, "NAT plugin mode: static mapping only");
2891     }
2892   else if (sm->deterministic)
2893     {
2894       vlib_cli_output (vm, "NAT plugin mode: deterministic mapping");
2895     }
2896   else
2897     {
2898       vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled");
2899     }
2900
2901   if (verbose > 0)
2902     {
2903       pool_foreach (i, sm->interfaces,
2904       ({
2905         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2906                          vnet_get_sw_interface (vnm, i->sw_if_index),
2907                          (nat_interface_is_inside(i) &&
2908                           nat_interface_is_outside(i)) ? "in out" :
2909                          (nat_interface_is_inside(i) ? "in" : "out"));
2910       }));
2911
2912       pool_foreach (i, sm->output_feature_interfaces,
2913       ({
2914         vlib_cli_output (vm, "%U output-feature %s",
2915                          format_vnet_sw_interface_name, vnm,
2916                          vnet_get_sw_interface (vnm, i->sw_if_index),
2917                          (nat_interface_is_inside(i) &&
2918                           nat_interface_is_outside(i)) ? "in out" :
2919                          (nat_interface_is_inside(i) ? "in" : "out"));
2920       }));
2921
2922       if (vec_len (sm->auto_add_sw_if_indices))
2923         {
2924           vlib_cli_output (vm, "NAT44 pool addresses interfaces:");
2925           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2926             {
2927               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2928                                vnet_get_sw_interface (vnm, *sw_if_index));
2929             }
2930         }
2931
2932       vec_foreach (ap, sm->addresses)
2933         {
2934           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2935           if (ap->fib_index != ~0)
2936               vlib_cli_output (vm, "  tenant VRF: %u",
2937                                ip4_fib_get(ap->fib_index)->table_id);
2938           else
2939             vlib_cli_output (vm, "  tenant VRF independent");
2940 #define _(N, i, n, s) \
2941           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
2942           foreach_snat_protocol
2943 #undef _
2944         }
2945     }
2946
2947   if (sm->num_workers > 1)
2948     {
2949       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2950       if (verbose > 0)
2951         {
2952           vec_foreach (worker, sm->workers)
2953             {
2954               vlib_worker_thread_t *w =
2955                 vlib_worker_threads + *worker + sm->first_worker_index;
2956               vlib_cli_output (vm, "  %s", w->name);
2957             }
2958         }
2959     }
2960
2961   if (sm->deterministic)
2962     {
2963       vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
2964       vlib_cli_output (vm, "tcp-established timeout: %dsec",
2965                        sm->tcp_established_timeout);
2966       vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
2967                        sm->tcp_transitory_timeout);
2968       vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
2969       vlib_cli_output (vm, "%d deterministic mappings",
2970                        pool_elts (sm->det_maps));
2971       if (verbose > 0)
2972         {
2973           pool_foreach (dm, sm->det_maps,
2974           ({
2975             vlib_cli_output (vm, "in %U/%d out %U/%d\n",
2976                              format_ip4_address, &dm->in_addr, dm->in_plen,
2977                              format_ip4_address, &dm->out_addr, dm->out_plen);
2978             vlib_cli_output (vm, " outside address sharing ratio: %d\n",
2979                              dm->sharing_ratio);
2980             vlib_cli_output (vm, " number of ports per inside host: %d\n",
2981                              dm->ports_per_host);
2982             vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num);
2983             if (verbose > 1)
2984               {
2985                 vec_foreach_index (j, dm->sessions)
2986                   {
2987                     ses = vec_elt_at_index (dm->sessions, j);
2988                     if (ses->in_port)
2989                       vlib_cli_output (vm, "  %U", format_det_map_ses, dm, ses,
2990                                        &j);
2991                   }
2992               }
2993           }));
2994         }
2995     }
2996   else
2997     {
2998       if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2999         {
3000           vlib_cli_output (vm, "%d static mappings",
3001                            pool_elts (sm->static_mappings));
3002
3003           if (verbose > 0)
3004             {
3005               pool_foreach (m, sm->static_mappings,
3006               ({
3007                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3008               }));
3009             }
3010         }
3011       else
3012         {
3013           vec_foreach (tsm, sm->per_thread_data)
3014             {
3015               users_num += pool_elts (tsm->users);
3016               sessions_num += pool_elts (tsm->sessions);
3017             }
3018
3019           vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
3020                            " %d static mappings",
3021                            users_num,
3022                            vec_len (sm->addresses),
3023                            sessions_num,
3024                            pool_elts (sm->static_mappings));
3025
3026           if (verbose > 0)
3027             {
3028               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed,
3029                                verbose - 1);
3030               vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed,
3031                                verbose - 1);
3032               vec_foreach_index (j, sm->per_thread_data)
3033                 {
3034                   tsm = vec_elt_at_index (sm->per_thread_data, j);
3035
3036                   if (pool_elts (tsm->users) == 0)
3037                     continue;
3038
3039                   vlib_worker_thread_t *w = vlib_worker_threads + j;
3040                   vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
3041                                    w->lcore_id);
3042                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->in2out,
3043                                    verbose - 1);
3044                   vlib_cli_output (vm, "  %U", format_bihash_8_8, &tsm->out2in,
3045                                    verbose - 1);
3046                   vlib_cli_output (vm, "  %d list pool elements",
3047                                    pool_elts (tsm->list_pool));
3048
3049                   pool_foreach (u, tsm->users,
3050                   ({
3051                     vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
3052                                      verbose - 1);
3053                   }));
3054                 }
3055
3056               if (pool_elts (sm->static_mappings))
3057                 {
3058                   vlib_cli_output (vm, "static mappings:");
3059                   pool_foreach (m, sm->static_mappings,
3060                   ({
3061                     vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
3062                   }));
3063                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3064                     {
3065                       rp = sm->to_resolve + j;
3066                       vlib_cli_output (vm, "%U",
3067                                        format_snat_static_map_to_resolve, rp);
3068                     }
3069                 }
3070             }
3071         }
3072     }
3073
3074   return 0;
3075 }
3076
3077 VLIB_CLI_COMMAND (show_snat_command, static) = {
3078     .path = "show nat44",
3079     .short_help = "show nat44",
3080     .function = show_snat_command_fn,
3081 };
3082
3083
3084 static void
3085 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
3086                                        uword opaque,
3087                                        u32 sw_if_index,
3088                                        ip4_address_t * address,
3089                                        u32 address_length,
3090                                        u32 if_address_index,
3091                                        u32 is_delete)
3092 {
3093   snat_main_t *sm = &snat_main;
3094   snat_static_map_resolve_t *rp;
3095   u32 *indices_to_delete = 0;
3096   ip4_address_t l_addr;
3097   int i, j;
3098   int rv;
3099
3100   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3101     {
3102       if (sw_if_index == sm->auto_add_sw_if_indices[i])
3103         {
3104           if (!is_delete)
3105             {
3106               /* Don't trip over lease renewal, static config */
3107               for (j = 0; j < vec_len(sm->addresses); j++)
3108                 if (sm->addresses[j].addr.as_u32 == address->as_u32)
3109                   return;
3110
3111               snat_add_address (sm, address, ~0);
3112               /* Scan static map resolution vector */
3113               for (j = 0; j < vec_len (sm->to_resolve); j++)
3114                 {
3115                   rp = sm->to_resolve + j;
3116                   /* On this interface? */
3117                   if (rp->sw_if_index == sw_if_index)
3118                     {
3119                       /* Indetity mapping? */
3120                       if (rp->l_addr.as_u32 == 0)
3121                         l_addr.as_u32 = address[0].as_u32;
3122                       else
3123                         l_addr.as_u32 = rp->l_addr.as_u32;
3124                       /* Add the static mapping */
3125                       rv = snat_add_static_mapping (l_addr,
3126                                                     address[0],
3127                                                     rp->l_port,
3128                                                     rp->e_port,
3129                                                     rp->vrf_id,
3130                                                     rp->addr_only,
3131                                                     ~0 /* sw_if_index */,
3132                                                     rp->proto,
3133                                                     rp->is_add);
3134                       if (rv)
3135                         clib_warning ("snat_add_static_mapping returned %d",
3136                                       rv);
3137                       vec_add1 (indices_to_delete, j);
3138                     }
3139                 }
3140               /* If we resolved any of the outstanding static mappings */
3141               if (vec_len(indices_to_delete))
3142                 {
3143                   /* Delete them */
3144                   for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3145                     vec_delete(sm->to_resolve, 1, j);
3146                   vec_free(indices_to_delete);
3147                 }
3148               return;
3149             }
3150           else
3151             {
3152               (void) snat_del_address(sm, address[0], 1);
3153               return;
3154             }
3155         }
3156     }
3157 }
3158
3159
3160 int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del)
3161 {
3162   ip4_main_t * ip4_main = sm->ip4_main;
3163   ip4_address_t * first_int_addr;
3164   snat_static_map_resolve_t *rp;
3165   u32 *indices_to_delete = 0;
3166   int i, j;
3167
3168   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
3169                                                 0 /* just want the address*/);
3170
3171   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
3172     {
3173       if (sm->auto_add_sw_if_indices[i] == sw_if_index)
3174         {
3175           if (is_del)
3176             {
3177               /* if have address remove it */
3178               if (first_int_addr)
3179                   (void) snat_del_address (sm, first_int_addr[0], 1);
3180               else
3181                 {
3182                   for (j = 0; j < vec_len (sm->to_resolve); j++)
3183                     {
3184                       rp = sm->to_resolve + j;
3185                       if (rp->sw_if_index == sw_if_index)
3186                         vec_add1 (indices_to_delete, j);
3187                     }
3188                   if (vec_len(indices_to_delete))
3189                     {
3190                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
3191                         vec_del1(sm->to_resolve, j);
3192                       vec_free(indices_to_delete);
3193                     }
3194                 }
3195               vec_del1(sm->auto_add_sw_if_indices, i);
3196             }
3197           else
3198             return VNET_API_ERROR_VALUE_EXIST;
3199
3200           return 0;
3201         }
3202     }
3203
3204   if (is_del)
3205     return VNET_API_ERROR_NO_SUCH_ENTRY;
3206
3207   /* add to the auto-address list */
3208   vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
3209
3210   /* If the address is already bound - or static - add it now */
3211   if (first_int_addr)
3212       snat_add_address (sm, first_int_addr, ~0);
3213
3214   return 0;
3215 }
3216
3217 static clib_error_t *
3218 snat_add_interface_address_command_fn (vlib_main_t * vm,
3219                                        unformat_input_t * input,
3220                                        vlib_cli_command_t * cmd)
3221 {
3222   snat_main_t *sm = &snat_main;
3223   unformat_input_t _line_input, *line_input = &_line_input;
3224   u32 sw_if_index;
3225   int rv;
3226   int is_del = 0;
3227   clib_error_t *error = 0;
3228
3229   /* Get a line of input. */
3230   if (!unformat_user (input, unformat_line_input, line_input))
3231     return 0;
3232
3233   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3234     {
3235       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
3236                     sm->vnet_main, &sw_if_index))
3237         ;
3238       else if (unformat (line_input, "del"))
3239         is_del = 1;
3240       else
3241         {
3242           error = clib_error_return (0, "unknown input '%U'",
3243                                      format_unformat_error, line_input);
3244           goto done;
3245         }
3246     }
3247
3248   rv = snat_add_interface_address (sm, sw_if_index, is_del);
3249
3250   switch (rv)
3251     {
3252     case 0:
3253       break;
3254
3255     default:
3256       error = clib_error_return (0, "snat_add_interface_address returned %d",
3257                                  rv);
3258       goto done;
3259     }
3260
3261 done:
3262   unformat_free (line_input);
3263
3264   return error;
3265 }
3266
3267 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
3268     .path = "nat44 add interface address",
3269     .short_help = "nat44 add interface address <interface> [del]",
3270     .function = snat_add_interface_address_command_fn,
3271 };
3272
3273 int
3274 nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port,
3275                    snat_protocol_t proto, u32 vrf_id, int is_in)
3276 {
3277   snat_main_per_thread_data_t *tsm;
3278   clib_bihash_kv_8_8_t kv, value;
3279   ip4_header_t ip;
3280   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id);
3281   snat_session_key_t key;
3282   snat_session_t *s;
3283   clib_bihash_8_8_t *t;
3284   snat_user_key_t u_key;
3285   snat_user_t *u;
3286
3287   ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32;
3288   if (sm->num_workers)
3289     tsm =
3290       vec_elt_at_index (sm->per_thread_data,
3291                         sm->worker_in2out_cb (&ip, fib_index));
3292   else
3293     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
3294
3295   key.addr.as_u32 = addr->as_u32;
3296   key.port = clib_host_to_net_u16 (port);
3297   key.protocol = proto;
3298   key.fib_index = fib_index;
3299   kv.key = key.as_u64;
3300   t = is_in ? &tsm->in2out : &tsm->out2in;
3301   if (!clib_bihash_search_8_8 (t, &kv, &value))
3302     {
3303       s = pool_elt_at_index (tsm->sessions, value.value);
3304       kv.key = s->in2out.as_u64;
3305       clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0);
3306       kv.key = s->out2in.as_u64;
3307       clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0);
3308       u_key.addr = s->in2out.addr;
3309       u_key.fib_index = s->in2out.fib_index;
3310       kv.key = u_key.as_u64;
3311       if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
3312         {
3313           u = pool_elt_at_index (tsm->users, value.value);
3314           u->nsessions--;
3315         }
3316       clib_dlist_remove (tsm->list_pool, s->per_user_index);
3317       pool_put (tsm->sessions, s);
3318       return 0;
3319     }
3320
3321   return VNET_API_ERROR_NO_SUCH_ENTRY;
3322 }
3323
3324 static clib_error_t *
3325 nat44_del_session_command_fn (vlib_main_t * vm,
3326                               unformat_input_t * input,
3327                               vlib_cli_command_t * cmd)
3328 {
3329   snat_main_t *sm = &snat_main;
3330   unformat_input_t _line_input, *line_input = &_line_input;
3331   int is_in = 0;
3332   clib_error_t *error = 0;
3333   ip4_address_t addr;
3334   u32 port = 0, vrf_id = sm->outside_vrf_id;
3335   snat_protocol_t proto;
3336   int rv;
3337
3338   /* Get a line of input. */
3339   if (!unformat_user (input, unformat_line_input, line_input))
3340     return 0;
3341
3342   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3343     {
3344       if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
3345           unformat_snat_protocol, &proto))
3346         ;
3347       else if (unformat (line_input, "in"))
3348         {
3349           is_in = 1;
3350           vrf_id = sm->inside_vrf_id;
3351         }
3352       else if (unformat (line_input, "vrf %u", &vrf_id))
3353         ;
3354       else
3355         {
3356           error = clib_error_return (0, "unknown input '%U'",
3357                                      format_unformat_error, line_input);
3358           goto done;
3359         }
3360     }
3361
3362   rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in);
3363
3364   switch (rv)
3365     {
3366     case 0:
3367       break;
3368
3369     default:
3370       error = clib_error_return (0, "nat44_del_session returned %d", rv);
3371       goto done;
3372     }
3373
3374 done:
3375   unformat_free (line_input);
3376
3377   return error;
3378 }
3379
3380 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
3381     .path = "nat44 del session",
3382     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]",
3383     .function = nat44_del_session_command_fn,
3384 };
3385
3386 static clib_error_t *
3387 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
3388                                               unformat_input_t * input,
3389                                               vlib_cli_command_t * cmd)
3390 {
3391   snat_main_t *sm = &snat_main;
3392   unformat_input_t _line_input, *line_input = &_line_input;
3393   clib_error_t *error = 0;
3394   u32 psid, psid_offset, psid_length;
3395
3396   /* Get a line of input. */
3397   if (!unformat_user (input, unformat_line_input, line_input))
3398     return 0;
3399
3400   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3401     {
3402       if (unformat (line_input, "default"))
3403         sm->alloc_addr_and_port = nat_alloc_addr_and_port_default;
3404       else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d",
3405                &psid, &psid_offset, &psid_length))
3406         {
3407           sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape;
3408           sm->psid = (u16) psid;
3409           sm->psid_offset = (u16) psid_offset;
3410           sm->psid_length = (u16) psid_length;
3411         }
3412       else
3413         {
3414           error = clib_error_return (0, "unknown input '%U'",
3415                                      format_unformat_error, line_input);
3416           goto done;
3417         }
3418     }
3419
3420 done:
3421   unformat_free (line_input);
3422
3423   return error;
3424 };
3425
3426 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
3427     .path = "nat44 addr-port-assignment-alg",
3428     .short_help = "nat44 addr-port-assignment-alg <alg-name> [<alg-params>]",
3429     .function = nat44_set_alloc_addr_and_port_alg_command_fn,
3430 };
3431
3432 static clib_error_t *
3433 snat_det_map_command_fn (vlib_main_t * vm,
3434                          unformat_input_t * input,
3435                          vlib_cli_command_t * cmd)
3436 {
3437   snat_main_t *sm = &snat_main;
3438   unformat_input_t _line_input, *line_input = &_line_input;
3439   ip4_address_t in_addr, out_addr;
3440   u32 in_plen, out_plen;
3441   int is_add = 1, rv;
3442   clib_error_t *error = 0;
3443
3444   /* Get a line of input. */
3445   if (!unformat_user (input, unformat_line_input, line_input))
3446     return 0;
3447
3448   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3449     {
3450       if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
3451         ;
3452       else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen))
3453         ;
3454       else if (unformat (line_input, "del"))
3455         is_add = 0;
3456       else
3457         {
3458           error = clib_error_return (0, "unknown input '%U'",
3459                                      format_unformat_error, line_input);
3460           goto done;
3461         }
3462     }
3463
3464   rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen,
3465                         is_add);
3466
3467   if (rv)
3468     {
3469       error = clib_error_return (0, "snat_det_add_map return %d", rv);
3470       goto done;
3471     }
3472
3473 done:
3474   unformat_free (line_input);
3475
3476   return error;
3477 }
3478
3479 /*?
3480  * @cliexpar
3481  * @cliexstart{snat deterministic add}
3482  * Create bijective mapping of inside address to outside address and port range
3483  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
3484  * CGN deployments.
3485  * To create deterministic mapping between inside network 10.0.0.0/18 and
3486  * outside network 1.1.1.0/30 use:
3487  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
3488  * @cliexend
3489 ?*/
3490 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
3491     .path = "nat44 deterministic add",
3492     .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
3493     .function = snat_det_map_command_fn,
3494 };
3495
3496 static clib_error_t *
3497 snat_det_forward_command_fn (vlib_main_t * vm,
3498                              unformat_input_t * input,
3499                              vlib_cli_command_t * cmd)
3500 {
3501   snat_main_t *sm = &snat_main;
3502   unformat_input_t _line_input, *line_input = &_line_input;
3503   ip4_address_t in_addr, out_addr;
3504   u16 lo_port;
3505   snat_det_map_t * dm;
3506   clib_error_t *error = 0;
3507
3508   /* Get a line of input. */
3509   if (!unformat_user (input, unformat_line_input, line_input))
3510     return 0;
3511
3512   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3513     {
3514       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
3515         ;
3516       else
3517         {
3518           error = clib_error_return (0, "unknown input '%U'",
3519                                      format_unformat_error, line_input);
3520           goto done;
3521         }
3522     }
3523
3524   dm = snat_det_map_by_user(sm, &in_addr);
3525   if (!dm)
3526     vlib_cli_output (vm, "no match");
3527   else
3528     {
3529       snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
3530       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
3531                        lo_port, lo_port + dm->ports_per_host - 1);
3532     }
3533
3534 done:
3535   unformat_free (line_input);
3536
3537   return error;
3538 }
3539
3540 /*?
3541  * @cliexpar
3542  * @cliexstart{snat deterministic forward}
3543  * Return outside address and port range from inside address for deterministic
3544  * NAT.
3545  * To obtain outside address and port of inside host use:
3546  *  vpp# nat44 deterministic forward 10.0.0.2
3547  *  1.1.1.0:<1054-1068>
3548  * @cliexend
3549 ?*/
3550 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
3551     .path = "nat44 deterministic forward",
3552     .short_help = "nat44 deterministic forward <addr>",
3553     .function = snat_det_forward_command_fn,
3554 };
3555
3556 static clib_error_t *
3557 snat_det_reverse_command_fn (vlib_main_t * vm,
3558                              unformat_input_t * input,
3559                              vlib_cli_command_t * cmd)
3560 {
3561   snat_main_t *sm = &snat_main;
3562   unformat_input_t _line_input, *line_input = &_line_input;
3563   ip4_address_t in_addr, out_addr;
3564   u32 out_port;
3565   snat_det_map_t * dm;
3566   clib_error_t *error = 0;
3567
3568   /* Get a line of input. */
3569   if (!unformat_user (input, unformat_line_input, line_input))
3570     return 0;
3571
3572   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3573     {
3574       if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
3575         ;
3576       else
3577         {
3578           error =  clib_error_return (0, "unknown input '%U'",
3579                                       format_unformat_error, line_input);
3580         }
3581     }
3582
3583   if (out_port < 1024 || out_port > 65535)
3584     {
3585       error = clib_error_return (0, "wrong port, must be <1024-65535>");
3586       goto done;
3587     }
3588
3589   dm = snat_det_map_by_out(sm, &out_addr);
3590   if (!dm)
3591     vlib_cli_output (vm, "no match");
3592   else
3593     {
3594       snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
3595       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
3596     }
3597
3598 done:
3599   unformat_free (line_input);
3600
3601   return error;
3602 }
3603
3604 /*?
3605  * @cliexpar
3606  * @cliexstart{snat deterministic reverse}
3607  * Return inside address from outside address and port for deterministic NAT.
3608  * To obtain inside host address from outside address and port use:
3609  *  #vpp nat44 deterministic reverse 1.1.1.1:1276
3610  *  10.0.16.16
3611  * @cliexend
3612 ?*/
3613 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
3614     .path = "nat44 deterministic reverse",
3615     .short_help = "nat44 deterministic reverse <addr>:<port>",
3616     .function = snat_det_reverse_command_fn,
3617 };
3618
3619 static clib_error_t *
3620 set_timeout_command_fn (vlib_main_t * vm,
3621                         unformat_input_t * input,
3622                         vlib_cli_command_t * cmd)
3623 {
3624   snat_main_t *sm = &snat_main;
3625   unformat_input_t _line_input, *line_input = &_line_input;
3626   clib_error_t *error = 0;
3627
3628   /* Get a line of input. */
3629   if (!unformat_user (input, unformat_line_input, line_input))
3630     return 0;
3631
3632   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3633     {
3634       if (unformat (line_input, "udp %u", &sm->udp_timeout))
3635         ;
3636       else if (unformat (line_input, "tcp-established %u",
3637                &sm->tcp_established_timeout))
3638         ;
3639       else if (unformat (line_input, "tcp-transitory %u",
3640                &sm->tcp_transitory_timeout))
3641         ;
3642       else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
3643         ;
3644       else if (unformat (line_input, "reset"))
3645         {
3646           sm->udp_timeout = SNAT_UDP_TIMEOUT;
3647           sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
3648           sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
3649           sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
3650         }
3651       else
3652         {
3653           error = clib_error_return (0, "unknown input '%U'",
3654                                      format_unformat_error, line_input);
3655           goto done;
3656         }
3657     }
3658
3659 done:
3660   unformat_free (line_input);
3661
3662   return error;
3663 }
3664
3665 /*?
3666  * @cliexpar
3667  * @cliexstart{set snat deterministic timeout}
3668  * Set values of timeouts for deterministic NAT (in seconds), use:
3669  *  vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
3670  *  tcp-transitory 250 icmp 90
3671  * To reset default values use:
3672  *  vpp# set nat44 deterministic timeout reset
3673  * @cliexend
3674 ?*/
3675 VLIB_CLI_COMMAND (set_timeout_command, static) = {
3676   .path = "set nat44 deterministic timeout",
3677   .function = set_timeout_command_fn,
3678   .short_help =
3679     "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
3680     "tcp-transitory <sec> | icmp <sec> | reset]",
3681 };
3682
3683 static clib_error_t *
3684 snat_det_close_session_out_fn (vlib_main_t *vm,
3685                                unformat_input_t * input,
3686                                vlib_cli_command_t * cmd)
3687 {
3688   snat_main_t *sm = &snat_main;
3689   unformat_input_t _line_input, *line_input = &_line_input;
3690   ip4_address_t out_addr, ext_addr, in_addr;
3691   u32 out_port, ext_port;
3692   snat_det_map_t * dm;
3693   snat_det_session_t * ses;
3694   snat_det_out_key_t key;
3695   clib_error_t *error = 0;
3696
3697   /* Get a line of input. */
3698   if (!unformat_user (input, unformat_line_input, line_input))
3699     return 0;
3700
3701   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3702     {
3703       if (unformat (line_input, "%U:%d %U:%d",
3704                     unformat_ip4_address, &out_addr, &out_port,
3705                     unformat_ip4_address, &ext_addr, &ext_port))
3706         ;
3707       else
3708         {
3709           error = clib_error_return (0, "unknown input '%U'",
3710                                      format_unformat_error, line_input);
3711           goto done;
3712         }
3713     }
3714
3715   unformat_free (line_input);
3716
3717   dm = snat_det_map_by_out(sm, &out_addr);
3718   if (!dm)
3719     vlib_cli_output (vm, "no match");
3720   else
3721     {
3722       snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr);
3723       key.ext_host_addr = out_addr;
3724       key.ext_host_port = ntohs((u16)ext_port);
3725       key.out_port = ntohs((u16)out_port);
3726       ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64);
3727       if (!ses)
3728         vlib_cli_output (vm, "no match");
3729       else
3730        snat_det_ses_close(dm, ses);
3731     }
3732
3733 done:
3734   unformat_free (line_input);
3735
3736   return error;
3737 }
3738
3739 /*?
3740  * @cliexpar
3741  * @cliexstart{snat deterministic close session out}
3742  * Close session using outside ip address and port
3743  * and external ip address and port, use:
3744  *  vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
3745  * @cliexend
3746 ?*/
3747 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
3748   .path = "nat44 deterministic close session out",
3749   .short_help = "nat44 deterministic close session out "
3750                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
3751   .function = snat_det_close_session_out_fn,
3752 };
3753
3754 static clib_error_t *
3755 snat_det_close_session_in_fn (vlib_main_t *vm,
3756                               unformat_input_t * input,
3757                               vlib_cli_command_t * cmd)
3758 {
3759   snat_main_t *sm = &snat_main;
3760   unformat_input_t _line_input, *line_input = &_line_input;
3761   ip4_address_t in_addr, ext_addr;
3762   u32 in_port, ext_port;
3763   snat_det_map_t * dm;
3764   snat_det_session_t * ses;
3765   snat_det_out_key_t key;
3766   clib_error_t *error = 0;
3767
3768   /* Get a line of input. */
3769   if (!unformat_user (input, unformat_line_input, line_input))
3770     return 0;
3771
3772   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3773     {
3774       if (unformat (line_input, "%U:%d %U:%d",
3775                     unformat_ip4_address, &in_addr, &in_port,
3776                     unformat_ip4_address, &ext_addr, &ext_port))
3777         ;
3778       else
3779         {
3780           error = clib_error_return (0, "unknown input '%U'",
3781                                      format_unformat_error, line_input);
3782           goto done;
3783         }
3784     }
3785
3786   unformat_free (line_input);
3787
3788   dm = snat_det_map_by_user (sm, &in_addr);
3789   if (!dm)
3790     vlib_cli_output (vm, "no match");
3791   else
3792     {
3793       key.ext_host_addr = ext_addr;
3794       key.ext_host_port = ntohs ((u16)ext_port);
3795       ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key);
3796       if (!ses)
3797         vlib_cli_output (vm, "no match");
3798       else
3799         snat_det_ses_close(dm, ses);
3800     }
3801
3802 done:
3803   unformat_free(line_input);
3804
3805   return error;
3806 }
3807
3808 /*?
3809  * @cliexpar
3810  * @cliexstart{snat deterministic close_session_in}
3811  * Close session using inside ip address and port
3812  * and external ip address and port, use:
3813  *  vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
3814  * @cliexend
3815 ?*/
3816 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
3817   .path = "nat44 deterministic close session in",
3818   .short_help = "nat44 deterministic close session in "
3819                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
3820   .function = snat_det_close_session_in_fn,
3821 };