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