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