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