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