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