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