Repair Doxygen build infrastructure
[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/plugin/plugin.h>
20 #include <vlibapi/api.h>
21 #include <snat/snat.h>
22
23 #include <vlibapi/api.h>
24 #include <vlibmemory/api.h>
25 #include <vlibsocket/api.h>
26
27 snat_main_t snat_main;
28
29 /* define message IDs */
30 #include <snat/snat_msg_enum.h>
31
32 /* define message structures */
33 #define vl_typedefs
34 #include <snat/snat_all_api_h.h> 
35 #undef vl_typedefs
36
37 /* define generated endian-swappers */
38 #define vl_endianfun
39 #include <snat/snat_all_api_h.h> 
40 #undef vl_endianfun
41
42 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
43
44 /* Get the API version number */
45 #define vl_api_version(n,v) static u32 api_version=(v);
46 #include <snat/snat_all_api_h.h>
47 #undef vl_api_version
48
49 /* Macro to finish up custom dump fns */
50 #define FINISH                                  \
51     vec_add1 (s, 0);                            \
52     vl_print (handle, (char *)s);               \
53     vec_free (s);                               \
54     return handle;
55
56 /* 
57  * A handy macro to set up a message reply.
58  * Assumes that the following variables are available:
59  * mp - pointer to request message
60  * rmp - pointer to reply message type
61  * rv - return value
62  */
63
64 #define REPLY_MACRO(t)                                          \
65 do {                                                            \
66     unix_shared_memory_queue_t * q =                            \
67     vl_api_client_index_to_input_queue (mp->client_index);      \
68     if (!q)                                                     \
69         return;                                                 \
70                                                                 \
71     rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
72     rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base);               \
73     rmp->context = mp->context;                                 \
74     rmp->retval = ntohl(rv);                                    \
75                                                                 \
76     vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
77 } while(0);
78
79 #define REPLY_MACRO2(t, body)                                   \
80 do {                                                            \
81     unix_shared_memory_queue_t * q =                            \
82     vl_api_client_index_to_input_queue (mp->client_index);      \
83     if (!q)                                                     \
84         return;                                                 \
85                                                                 \
86     rmp = vl_msg_api_alloc (sizeof (*rmp));                     \
87     rmp->_vl_msg_id = ntohs((t)+sm->msg_id_base);               \
88     rmp->context = mp->context;                                 \
89     rmp->retval = ntohl(rv);                                    \
90     do {body;} while (0);                                       \
91     vl_msg_api_send_shmem (q, (u8 *)&rmp);                      \
92 } while(0);
93
94
95 /* Hook up input features */
96 VNET_FEATURE_INIT (ip4_snat_in2out, static) = {
97   .arc_name = "ip4-unicast",
98   .node_name = "snat-in2out",
99   .runs_before = VNET_FEATURES ("snat-out2in"),
100 };
101 VNET_FEATURE_INIT (ip4_snat_out2in, static) = {
102   .arc_name = "ip4-unicast",
103   .node_name = "snat-out2in",
104   .runs_before = VNET_FEATURES ("ip4-lookup"),
105 };
106 VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = {
107   .arc_name = "ip4-unicast",
108   .node_name = "snat-in2out-worker-handoff",
109   .runs_before = VNET_FEATURES ("snat-out2in-worker-handoff"),
110 };
111 VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = {
112   .arc_name = "ip4-unicast",
113   .node_name = "snat-out2in-worker-handoff",
114   .runs_before = VNET_FEATURES ("ip4-lookup"),
115 };
116 VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = {
117   .arc_name = "ip4-unicast",
118   .node_name = "snat-in2out-fast",
119   .runs_before = VNET_FEATURES ("snat-out2in-fast"),
120 };
121 VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = {
122   .arc_name = "ip4-unicast",
123   .node_name = "snat-out2in-fast",
124   .runs_before = VNET_FEATURES ("ip4-lookup"),
125 };
126
127
128 /* 
129  * This routine exists to convince the vlib plugin framework that
130  * we haven't accidentally copied a random .dll into the plugin directory.
131  *
132  * Also collects global variable pointers passed from the vpp engine
133  */
134
135 clib_error_t * 
136 vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
137                       int from_early_init)
138 {
139   snat_main_t * sm = &snat_main;
140   clib_error_t * error = 0;
141
142   sm->vlib_main = vm;
143   sm->vnet_main = h->vnet_main;
144   sm->ethernet_main = h->ethernet_main;
145
146   return error;
147 }
148
149 /*$$$$$ move to an installed header file */
150 #if (1 || CLIB_DEBUG > 0)       /* "trust, but verify" */
151
152 #define VALIDATE_SW_IF_INDEX(mp)                                \
153  do { u32 __sw_if_index = ntohl(mp->sw_if_index);               \
154     vnet_main_t *__vnm = vnet_get_main();                       \
155     if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
156                            __sw_if_index)) {                    \
157         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
158         goto bad_sw_if_index;                                   \
159     }                                                           \
160 } while(0);
161
162 #define BAD_SW_IF_INDEX_LABEL                   \
163 do {                                            \
164 bad_sw_if_index:                                \
165     ;                                           \
166 } while (0);
167
168 #define VALIDATE_RX_SW_IF_INDEX(mp)                             \
169  do { u32 __rx_sw_if_index = ntohl(mp->rx_sw_if_index);         \
170     vnet_main_t *__vnm = vnet_get_main();                       \
171     if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
172                            __rx_sw_if_index)) {                 \
173         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
174         goto bad_rx_sw_if_index;                                \
175     }                                                           \
176 } while(0);
177
178 #define BAD_RX_SW_IF_INDEX_LABEL                \
179 do {                                            \
180 bad_rx_sw_if_index:                             \
181     ;                                           \
182 } while (0);
183
184 #define VALIDATE_TX_SW_IF_INDEX(mp)                             \
185  do { u32 __tx_sw_if_index = ntohl(mp->tx_sw_if_index);         \
186     vnet_main_t *__vnm = vnet_get_main();                       \
187     if (pool_is_free_index(__vnm->interface_main.sw_interfaces, \
188                            __tx_sw_if_index)) {                 \
189         rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;                \
190         goto bad_tx_sw_if_index;                                \
191     }                                                           \
192 } while(0);
193
194 #define BAD_TX_SW_IF_INDEX_LABEL                \
195 do {                                            \
196 bad_tx_sw_if_index:                             \
197     ;                                           \
198 } while (0);
199
200 #else
201
202 #define VALIDATE_SW_IF_INDEX(mp)
203 #define BAD_SW_IF_INDEX_LABEL
204 #define VALIDATE_RX_SW_IF_INDEX(mp)
205 #define BAD_RX_SW_IF_INDEX_LABEL
206 #define VALIDATE_TX_SW_IF_INDEX(mp)
207 #define BAD_TX_SW_IF_INDEX_LABEL
208
209 #endif  /* CLIB_DEBUG > 0 */
210
211 void snat_add_address (snat_main_t *sm, ip4_address_t *addr)
212 {
213   snat_address_t * ap;
214
215   /* Check if address already exists */
216   vec_foreach (ap, sm->addresses)
217     {
218       if (ap->addr.as_u32 == addr->as_u32)
219         return;
220     }
221
222   vec_add2 (sm->addresses, ap, 1);
223   ap->addr = *addr;
224   clib_bitmap_alloc (ap->busy_port_bitmap, 65535);
225 }
226
227 static int is_snat_address_used_in_static_mapping (snat_main_t *sm,
228                                                    ip4_address_t addr)
229 {
230   snat_static_mapping_t *m;
231   pool_foreach (m, sm->static_mappings,
232   ({
233       if (m->external_addr.as_u32 == addr.as_u32)
234         return 1;
235   }));
236
237   return 0;
238 }
239
240 int snat_del_address (snat_main_t *sm, ip4_address_t addr)
241 {
242   snat_address_t *a = 0;
243   snat_session_t *ses;
244   u32 *ses_to_be_removed = 0, *ses_index;
245   clib_bihash_kv_8_8_t kv, value;
246   snat_user_key_t user_key;
247   snat_user_t *u;
248   snat_main_per_thread_data_t *tsm;
249
250   int i;
251
252   /* Find SNAT address */
253   for (i=0; i < vec_len (sm->addresses); i++)
254     {
255       if (sm->addresses[i].addr.as_u32 == addr.as_u32)
256         {
257           a = sm->addresses + i;
258           break;
259         }
260     }
261   if (!a)
262     return VNET_API_ERROR_NO_SUCH_ENTRY;
263
264   /* Check if address is used in some static mapping */
265   if (is_snat_address_used_in_static_mapping(sm, addr))
266     {
267       clib_warning ("address used in static mapping");
268       return VNET_API_ERROR_UNSPECIFIED;
269     }
270
271   /* Delete sessions using address */
272   if (a->busy_ports)
273     {
274       vec_foreach (tsm, sm->per_thread_data)
275         {
276           pool_foreach (ses, tsm->sessions, ({
277             if (ses->out2in.addr.as_u32 == addr.as_u32)
278               {
279                 vec_add1 (ses_to_be_removed, ses - tsm->sessions);
280                 kv.key = ses->in2out.as_u64;
281                 clib_bihash_add_del_8_8 (&sm->in2out, &kv, 0);
282                 kv.key = ses->out2in.as_u64;
283                 clib_bihash_add_del_8_8 (&sm->out2in, &kv, 0);
284                 clib_dlist_remove (tsm->list_pool, ses->per_user_index);
285                 user_key.addr = ses->in2out.addr;
286                 user_key.fib_index = ses->in2out.fib_index;
287                 kv.key = user_key.as_u64;
288                 if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
289                   {
290                     u = pool_elt_at_index (tsm->users, value.value);
291                     u->nsessions--;
292                   }
293               }
294           }));
295
296           vec_foreach (ses_index, ses_to_be_removed)
297             pool_put_index (tsm->sessions, ses_index[0]);
298
299           vec_free (ses_to_be_removed);
300        }
301     }
302
303   vec_del1 (sm->addresses, i);
304
305   return 0;
306 }
307
308 static void increment_v4_address (ip4_address_t * a)
309 {
310   u32 v;
311   
312   v = clib_net_to_host_u32(a->as_u32) + 1;
313   a->as_u32 = clib_host_to_net_u32(v);
314 }
315
316 /**
317  * @brief Add static mapping.
318  *
319  * Create static mapping between local addr+port and external addr+port.
320  *
321  * @param l_addr Local IPv4 address.
322  * @param e_addr External IPv4 address.
323  * @param l_port Local port number.
324  * @param e_port External port number.
325  * @param vrf_id VRF ID.
326  * @param addr_only If 0 address port and pair mapping, otherwise address only.
327  * @param is_add If 0 delete static mapping, otherwise add.
328  *
329  * @returns
330  */
331 int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr,
332                             u16 l_port, u16 e_port, u32 vrf_id, int addr_only,
333                             int is_add)
334 {
335   snat_main_t * sm = &snat_main;
336   snat_static_mapping_t *m;
337   snat_static_mapping_key_t m_key;
338   clib_bihash_kv_8_8_t kv, value;
339   snat_address_t *a = 0;
340   u32 fib_index = ~0;
341   uword * p;
342   int i;
343
344   /* If outside FIB index is not resolved yet */
345   if (sm->outside_fib_index == ~0)
346     {
347       p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->outside_vrf_id);
348       if (!p)
349         return VNET_API_ERROR_NO_SUCH_FIB;
350       sm->outside_fib_index = p[0];
351     }
352
353   m_key.addr = e_addr;
354   m_key.port = addr_only ? 0 : e_port;
355   m_key.fib_index = sm->outside_fib_index;
356   kv.key = m_key.as_u64;
357   if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value))
358     m = 0;
359   else
360     m = pool_elt_at_index (sm->static_mappings, value.value);
361
362   if (is_add)
363     {
364       if (m)
365         return VNET_API_ERROR_VALUE_EXIST;
366
367       /* Convert VRF id to FIB index */
368       if (vrf_id != ~0)
369         {
370           p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id);
371           if (!p)
372             return VNET_API_ERROR_NO_SUCH_FIB;
373           fib_index = p[0];
374         }
375       /* If not specified use inside VRF id from SNAT plugin startup config */
376       else
377         {
378           if (sm->inside_fib_index == ~0)
379             {
380               p = hash_get (sm->ip4_main->fib_index_by_table_id, sm->inside_vrf_id);
381               if (!p)
382                 return VNET_API_ERROR_NO_SUCH_FIB;
383               fib_index = p[0];
384               sm->inside_fib_index = fib_index;
385             }
386           else
387             fib_index = sm->inside_fib_index;
388
389           vrf_id = sm->inside_vrf_id;
390         }
391
392       /* Find external address in allocated addresses and reserve port for
393          address and port pair mapping when dynamic translations enabled */
394       if (!addr_only && !(sm->static_mapping_only))
395         {
396           for (i = 0; i < vec_len (sm->addresses); i++)
397             {
398               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
399                 {
400                   a = sm->addresses + i;
401                   /* External port must be unused */
402                   if (clib_bitmap_get_no_check (a->busy_port_bitmap, e_port))
403                     return VNET_API_ERROR_INVALID_VALUE;
404                   clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 1);
405                   if (e_port > 1024)
406                     a->busy_ports++;
407
408                   break;
409                 }
410             }
411           /* External address must be allocated */
412           if (!a)
413             return VNET_API_ERROR_NO_SUCH_ENTRY;
414         }
415
416       pool_get (sm->static_mappings, m);
417       memset (m, 0, sizeof (*m));
418       m->local_addr = l_addr;
419       m->external_addr = e_addr;
420       m->addr_only = addr_only;
421       m->vrf_id = vrf_id;
422       m->fib_index = fib_index;
423       if (!addr_only)
424         {
425           m->local_port = l_port;
426           m->external_port = e_port;
427         }
428
429       m_key.addr = m->local_addr;
430       m_key.port = m->local_port;
431       m_key.fib_index = m->fib_index;
432       kv.key = m_key.as_u64;
433       kv.value = m - sm->static_mappings;
434       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
435
436       m_key.addr = m->external_addr;
437       m_key.port = m->external_port;
438       m_key.fib_index = sm->outside_fib_index;
439       kv.key = m_key.as_u64;
440       kv.value = m - sm->static_mappings;
441       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
442
443       /* Assign worker */
444       if (sm->workers)
445         {
446           snat_user_key_t w_key0;
447           snat_static_mapping_key_t w_key1;
448
449           w_key0.addr = m->local_addr;
450           w_key0.fib_index = m->fib_index;
451           kv.key = w_key0.as_u64;
452
453           if (clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
454             {
455               kv.value = sm->first_worker_index +
456                 sm->workers[sm->next_worker++ % vec_len (sm->workers)];
457
458               clib_bihash_add_del_8_8 (&sm->worker_by_in, &kv, 1);
459             }
460           else
461             {
462               kv.value = value.value;
463             }
464
465           w_key1.addr = m->external_addr;
466           w_key1.port = clib_host_to_net_u16 (m->external_port);
467           w_key1.fib_index = sm->outside_fib_index;
468           kv.key = w_key1.as_u64;
469           clib_bihash_add_del_8_8 (&sm->worker_by_out, &kv, 1);
470         }
471     }
472   else
473     {
474       if (!m)
475         return VNET_API_ERROR_NO_SUCH_ENTRY;
476
477       /* Free external address port */
478       if (!addr_only && !(sm->static_mapping_only))
479         {
480           for (i = 0; i < vec_len (sm->addresses); i++)
481             {
482               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
483                 {
484                   a = sm->addresses + i;
485                   clib_bitmap_set_no_check (a->busy_port_bitmap, e_port, 0);
486                   a->busy_ports--;
487
488                   break;
489                 }
490             }
491         }
492
493       m_key.addr = m->local_addr;
494       m_key.port = m->local_port;
495       m_key.fib_index = m->fib_index;
496       kv.key = m_key.as_u64;
497       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
498
499       m_key.addr = m->external_addr;
500       m_key.port = m->external_port;
501       m_key.fib_index = sm->outside_fib_index;
502       kv.key = m_key.as_u64;
503       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
504
505       /* Delete session(s) for static mapping if exist */
506       if (!(sm->static_mapping_only) ||
507           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
508         {
509           snat_user_key_t u_key;
510           snat_user_t *u;
511           dlist_elt_t * head, * elt;
512           u32 elt_index, head_index, del_elt_index;
513           u32 ses_index;
514           u64 user_index;
515           snat_session_t * s;
516           snat_main_per_thread_data_t *tsm;
517
518           u_key.addr = m->local_addr;
519           u_key.fib_index = m->fib_index;
520           kv.key = u_key.as_u64;
521           if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
522             {
523               user_index = value.value;
524               if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
525                 tsm = vec_elt_at_index (sm->per_thread_data, value.value);
526               else
527                 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
528               u = pool_elt_at_index (tsm->users, user_index);
529               if (u->nstaticsessions)
530                 {
531                   head_index = u->sessions_per_user_list_head_index;
532                   head = pool_elt_at_index (tsm->list_pool, head_index);
533                   elt_index = head->next;
534                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
535                   ses_index = elt->value;
536                   while (ses_index != ~0)
537                     {
538                       s =  pool_elt_at_index (tsm->sessions, ses_index);
539                       del_elt_index = elt_index;
540                       elt_index = elt->next;
541                       elt = pool_elt_at_index (tsm->list_pool, elt_index);
542                       ses_index = elt->value;
543
544                       if (!addr_only)
545                         {
546                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
547                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
548                             continue;
549                         }
550
551                       value.key = s->in2out.as_u64;
552                       clib_bihash_add_del_8_8 (&sm->in2out, &value, 0);
553                       value.key = s->out2in.as_u64;
554                       clib_bihash_add_del_8_8 (&sm->out2in, &value, 0);
555                       pool_put (tsm->sessions, s);
556
557                       clib_dlist_remove (tsm->list_pool, del_elt_index);
558                       pool_put_index (tsm->list_pool, del_elt_index);
559                       u->nstaticsessions--;
560
561                       if (!addr_only)
562                         break;
563                     }
564                   if (addr_only)
565                     {
566                       pool_put (tsm->users, u);
567                       clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
568                     }
569                 }
570             }
571         }
572
573       /* Delete static mapping from pool */
574       pool_put (sm->static_mappings, m);
575     }
576
577   return 0;
578 }
579
580 static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
581 {
582   snat_main_t *sm = &snat_main;
583   snat_interface_t *i;
584   const char * feature_name;
585
586   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
587     feature_name = is_inside ?  "snat-in2out-fast" : "snat-out2in-fast";
588   else
589     {
590       if (sm->num_workers > 1)
591         feature_name = is_inside ?  "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff";
592       else
593         feature_name = is_inside ?  "snat-in2out" : "snat-out2in";
594     }
595
596   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
597                                !is_del, 0, 0);
598
599   if (sm->fq_in2out_index == ~0)
600     sm->fq_in2out_index = vlib_frame_queue_main_init (snat_in2out_node.index, 0);
601
602   if (sm->fq_out2in_index == ~0)
603     sm->fq_out2in_index = vlib_frame_queue_main_init (snat_out2in_node.index, 0);
604
605   pool_foreach (i, sm->interfaces,
606   ({
607     if (i->sw_if_index == sw_if_index)
608       {
609         if (is_del)
610           pool_put (sm->interfaces, i);
611         else
612           return VNET_API_ERROR_VALUE_EXIST;
613
614         return 0;
615       }
616   }));
617
618   if (is_del)
619     return VNET_API_ERROR_NO_SUCH_ENTRY;
620
621   pool_get (sm->interfaces, i);
622   i->sw_if_index = sw_if_index;
623   i->is_inside = is_inside;
624
625   return 0;
626 }
627
628 static int snat_set_workers (uword * bitmap)
629 {
630   snat_main_t *sm = &snat_main;
631   int i;
632
633   if (sm->num_workers < 2)
634     return VNET_API_ERROR_FEATURE_DISABLED;
635
636   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
637     return VNET_API_ERROR_INVALID_WORKER;
638
639   vec_free (sm->workers);
640   clib_bitmap_foreach (i, bitmap,
641     ({
642       vec_add1(sm->workers, i);
643     }));
644
645   return 0;
646 }
647
648 static void 
649 vl_api_snat_add_address_range_t_handler
650 (vl_api_snat_add_address_range_t * mp)
651 {
652   snat_main_t * sm = &snat_main;
653   vl_api_snat_add_address_range_reply_t * rmp;
654   ip4_address_t this_addr;
655   u32 start_host_order, end_host_order;
656   int i, count;
657   int rv = 0;
658   u32 * tmp;
659
660   if (mp->is_ip4 != 1)
661     {
662       rv = VNET_API_ERROR_UNIMPLEMENTED;
663       goto send_reply;
664     }
665
666   if (sm->static_mapping_only)
667     {
668       rv = VNET_API_ERROR_FEATURE_DISABLED;
669       goto send_reply;
670     }
671
672   tmp = (u32 *) mp->first_ip_address;
673   start_host_order = clib_host_to_net_u32 (tmp[0]);
674   tmp = (u32 *) mp->last_ip_address;
675   end_host_order = clib_host_to_net_u32 (tmp[0]);
676
677   count = (end_host_order - start_host_order) + 1;
678
679   if (count > 1024)
680     clib_warning ("%U - %U, %d addresses...",
681                   format_ip4_address, mp->first_ip_address,
682                   format_ip4_address, mp->last_ip_address,
683                   count);
684   
685   memcpy (&this_addr.as_u8, mp->first_ip_address, 4);
686
687   for (i = 0; i < count; i++)
688     {
689       if (mp->is_add)
690         snat_add_address (sm, &this_addr);
691       else
692         rv = snat_del_address (sm, this_addr);
693
694       if (rv)
695         goto send_reply;
696
697       increment_v4_address (&this_addr);
698     }
699
700  send_reply:
701   REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
702 }
703
704 static void *vl_api_snat_add_address_range_t_print
705 (vl_api_snat_add_address_range_t *mp, void * handle)
706 {
707   u8 * s;
708
709   s = format (0, "SCRIPT: snat_add_address_range ");
710   s = format (s, "%U ", format_ip4_address, mp->first_ip_address);
711   if (memcmp (mp->first_ip_address, mp->last_ip_address, 4))
712     {
713       s = format (s, " - %U ", format_ip4_address, mp->last_ip_address);
714     }
715   FINISH;
716 }
717
718 static void
719 send_snat_address_details
720 (snat_address_t * a, unix_shared_memory_queue_t * q, u32 context)
721 {
722   vl_api_snat_address_details_t *rmp;
723   snat_main_t * sm = &snat_main;
724
725   rmp = vl_msg_api_alloc (sizeof (*rmp));
726   memset (rmp, 0, sizeof (*rmp));
727   rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base);
728   rmp->is_ip4 = 1;
729   clib_memcpy (rmp->ip_address, &(a->addr), 4);
730   rmp->context = context;
731
732   vl_msg_api_send_shmem (q, (u8 *) & rmp);
733 }
734
735 static void
736 vl_api_snat_address_dump_t_handler
737 (vl_api_snat_address_dump_t * mp)
738 {
739   unix_shared_memory_queue_t *q;
740   snat_main_t * sm = &snat_main;
741   snat_address_t * a;
742
743   q = vl_api_client_index_to_input_queue (mp->client_index);
744   if (q == 0)
745     return;
746
747   vec_foreach (a, sm->addresses)
748     send_snat_address_details (a, q, mp->context);
749 }
750
751 static void *vl_api_snat_address_dump_t_print
752 (vl_api_snat_address_dump_t *mp, void * handle)
753 {
754   u8 *s;
755
756   s = format (0, "SCRIPT: snat_address_dump ");
757
758   FINISH;
759 }
760
761 static void
762 vl_api_snat_interface_add_del_feature_t_handler
763 (vl_api_snat_interface_add_del_feature_t * mp)
764 {
765   snat_main_t * sm = &snat_main;
766   vl_api_snat_interface_add_del_feature_reply_t * rmp;
767   u8 is_del = mp->is_add == 0;
768   u32 sw_if_index = ntohl(mp->sw_if_index);
769   int rv = 0;
770
771   VALIDATE_SW_IF_INDEX(mp);
772
773   rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del);
774   
775   BAD_SW_IF_INDEX_LABEL;
776
777   REPLY_MACRO(VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY);
778 }
779
780 static void *vl_api_snat_interface_add_del_feature_t_print
781 (vl_api_snat_interface_add_del_feature_t * mp, void *handle)
782 {
783   u8 * s;
784
785   s = format (0, "SCRIPT: snat_interface_add_del_feature ");
786   s = format (s, "sw_if_index %d %s %s",
787               clib_host_to_net_u32(mp->sw_if_index),
788               mp->is_inside ? "in":"out",
789               mp->is_add ? "" : "del");
790
791   FINISH;
792 }
793
794 static void
795 send_snat_interface_details
796 (snat_interface_t * i, unix_shared_memory_queue_t * q, u32 context)
797 {
798   vl_api_snat_interface_details_t *rmp;
799   snat_main_t * sm = &snat_main;
800
801   rmp = vl_msg_api_alloc (sizeof (*rmp));
802   memset (rmp, 0, sizeof (*rmp));
803   rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_DETAILS+sm->msg_id_base);
804   rmp->sw_if_index = ntohl (i->sw_if_index);
805   rmp->is_inside = i->is_inside;
806   rmp->context = context;
807
808   vl_msg_api_send_shmem (q, (u8 *) & rmp);
809 }
810
811 static void
812 vl_api_snat_interface_dump_t_handler
813 (vl_api_snat_interface_dump_t * mp)
814 {
815   unix_shared_memory_queue_t *q;
816   snat_main_t * sm = &snat_main;
817   snat_interface_t * i;
818
819   q = vl_api_client_index_to_input_queue (mp->client_index);
820   if (q == 0)
821     return;
822
823   pool_foreach (i, sm->interfaces,
824   ({
825     send_snat_interface_details(i, q, mp->context);
826   }));
827 }
828
829 static void *vl_api_snat_interface_dump_t_print
830 (vl_api_snat_interface_dump_t *mp, void * handle)
831 {
832   u8 *s;
833
834   s = format (0, "SCRIPT: snat_interface_dump ");
835
836   FINISH;
837 }static void
838
839 vl_api_snat_add_static_mapping_t_handler
840 (vl_api_snat_add_static_mapping_t * mp)
841 {
842   snat_main_t * sm = &snat_main;
843   vl_api_snat_add_static_mapping_reply_t * rmp;
844   ip4_address_t local_addr, external_addr;
845   u16 local_port = 0, external_port = 0;
846   u32 vrf_id;
847   int rv = 0;
848
849   if (mp->is_ip4 != 1)
850     {
851       rv = VNET_API_ERROR_UNIMPLEMENTED;
852       goto send_reply;
853     }
854
855   memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
856   memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
857   if (mp->addr_only == 0)
858     {
859       local_port = clib_net_to_host_u16 (mp->local_port);
860       external_port = clib_net_to_host_u16 (mp->external_port);
861     }
862   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
863
864   rv = snat_add_static_mapping(local_addr, external_addr, local_port,
865                                external_port, vrf_id, mp->addr_only,
866                                mp->is_add);
867
868  send_reply:
869   REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
870 }
871
872 static void *vl_api_snat_add_static_mapping_t_print
873 (vl_api_snat_add_static_mapping_t *mp, void * handle)
874 {
875   u8 * s;
876
877   s = format (0, "SCRIPT: snat_add_static_mapping ");
878   s = format (s, "local_addr %U external_addr %U ",
879               format_ip4_address, mp->local_ip_address,
880               format_ip4_address, mp->external_ip_address);
881
882   if (mp->addr_only == 0)
883     s = format (s, "local_port %d external_port %d ",
884                 clib_net_to_host_u16 (mp->local_port),
885                 clib_net_to_host_u16 (mp->external_port));
886
887   if (mp->vrf_id != ~0)
888     s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
889
890   FINISH;
891 }
892
893 static void
894 send_snat_static_mapping_details
895 (snat_static_mapping_t * m, unix_shared_memory_queue_t * q, u32 context)
896 {
897   vl_api_snat_static_mapping_details_t *rmp;
898   snat_main_t * sm = &snat_main;
899
900   rmp = vl_msg_api_alloc (sizeof (*rmp));
901   memset (rmp, 0, sizeof (*rmp));
902   rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base);
903   rmp->is_ip4 = 1;
904   rmp->addr_only = m->addr_only;
905   clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4);
906   clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4);
907   rmp->local_port = htons (m->local_port);
908   rmp->external_port = htons (m->external_port);
909   rmp->vrf_id = htonl (m->vrf_id);
910   rmp->context = context;
911
912   vl_msg_api_send_shmem (q, (u8 *) & rmp);
913 }
914
915 static void
916 vl_api_snat_static_mapping_dump_t_handler
917 (vl_api_snat_static_mapping_dump_t * mp)
918 {
919   unix_shared_memory_queue_t *q;
920   snat_main_t * sm = &snat_main;
921   snat_static_mapping_t * m;
922
923   q = vl_api_client_index_to_input_queue (mp->client_index);
924   if (q == 0)
925     return;
926
927   pool_foreach (m, sm->static_mappings,
928   ({
929       send_snat_static_mapping_details (m, q, mp->context);
930   }));
931 }
932
933 static void *vl_api_snat_static_mapping_dump_t_print
934 (vl_api_snat_static_mapping_dump_t *mp, void * handle)
935 {
936   u8 *s;
937
938   s = format (0, "SCRIPT: snat_static_mapping_dump ");
939
940   FINISH;
941 }
942
943 static void
944 vl_api_snat_control_ping_t_handler
945 (vl_api_snat_control_ping_t * mp)
946 {
947   vl_api_snat_control_ping_reply_t *rmp;
948   snat_main_t * sm = &snat_main;
949   int rv = 0;
950
951   REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY,
952   ({
953     rmp->vpe_pid = ntohl (getpid());
954   }));
955 }
956
957 static void *vl_api_snat_control_ping_t_print
958 (vl_api_snat_control_ping_t *mp, void * handle)
959 {
960   u8 *s;
961
962   s = format (0, "SCRIPT: snat_control_ping ");
963
964   FINISH;
965 }
966
967 static void
968 vl_api_snat_show_config_t_handler
969 (vl_api_snat_show_config_t * mp)
970 {
971   vl_api_snat_show_config_reply_t *rmp;
972   snat_main_t * sm = &snat_main;
973   int rv = 0;
974
975   REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY,
976   ({
977     rmp->translation_buckets = htonl (sm->translation_buckets);
978     rmp->translation_memory_size = htonl (sm->translation_memory_size);
979     rmp->user_buckets = htonl (sm->user_buckets);
980     rmp->user_memory_size = htonl (sm->user_memory_size);
981     rmp->max_translations_per_user = htonl (sm->max_translations_per_user);
982     rmp->outside_vrf_id = htonl (sm->outside_vrf_id);
983     rmp->inside_vrf_id = htonl (sm->inside_vrf_id);
984     rmp->static_mapping_only = sm->static_mapping_only;
985     rmp->static_mapping_connection_tracking =
986       sm->static_mapping_connection_tracking;
987   }));
988 }
989
990 static void *vl_api_snat_show_config_t_print
991 (vl_api_snat_show_config_t *mp, void * handle)
992 {
993   u8 *s;
994
995   s = format (0, "SCRIPT: snat_show_config ");
996
997   FINISH;
998 }
999
1000 static void 
1001 vl_api_snat_set_workers_t_handler
1002 (vl_api_snat_set_workers_t * mp)
1003 {
1004   snat_main_t * sm = &snat_main;
1005   vl_api_snat_set_workers_reply_t * rmp;
1006   int rv = 0;
1007   uword *bitmap = 0;
1008   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1009
1010   if (sm->num_workers < 2)
1011     {
1012       rv = VNET_API_ERROR_FEATURE_DISABLED;
1013       goto send_reply;
1014     }
1015
1016   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
1017   rv = snat_set_workers(bitmap);
1018   clib_bitmap_free (bitmap);
1019
1020  send_reply:
1021   REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY);
1022 }
1023
1024 static void *vl_api_snat_set_workers_t_print
1025 (vl_api_snat_set_workers_t *mp, void * handle)
1026 {
1027   u8 * s;
1028   uword *bitmap = 0;
1029   u8 first = 1;
1030   int i;
1031   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1032
1033   s = format (0, "SCRIPT: snat_set_workers ");
1034   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
1035   clib_bitmap_foreach (i, bitmap,
1036     ({
1037       if (first)
1038         s = format (s, "%d", i);
1039       else
1040         s = format (s, ",%d", i);
1041       first = 0;
1042     }));
1043   clib_bitmap_free (bitmap);
1044   FINISH;
1045 }
1046
1047 static void
1048 send_snat_worker_details
1049 (u32 worker_index, unix_shared_memory_queue_t * q, u32 context)
1050 {
1051   vl_api_snat_worker_details_t *rmp;
1052   snat_main_t * sm = &snat_main;
1053   vlib_worker_thread_t *w =
1054     vlib_worker_threads + worker_index + sm->first_worker_index;
1055
1056   rmp = vl_msg_api_alloc (sizeof (*rmp));
1057   memset (rmp, 0, sizeof (*rmp));
1058   rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base);
1059   rmp->context = context;
1060   rmp->worker_index = htonl (worker_index);
1061   rmp->lcore_id = htonl (w->lcore_id);
1062   strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
1063
1064   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1065 }
1066
1067 static void
1068 vl_api_snat_worker_dump_t_handler
1069 (vl_api_snat_worker_dump_t * mp)
1070 {
1071   unix_shared_memory_queue_t *q;
1072   snat_main_t * sm = &snat_main;
1073   u32 * worker_index;
1074
1075   q = vl_api_client_index_to_input_queue (mp->client_index);
1076   if (q == 0)
1077     return;
1078
1079   vec_foreach (worker_index, sm->workers)
1080     {
1081       send_snat_worker_details(*worker_index, q, mp->context);
1082     }
1083 }
1084
1085 static void *vl_api_snat_worker_dump_t_print
1086 (vl_api_snat_worker_dump_t *mp, void * handle)
1087 {
1088   u8 *s;
1089
1090   s = format (0, "SCRIPT: snat_worker_dump ");
1091
1092   FINISH;
1093 }
1094
1095 /* List of message types that this plugin understands */
1096 #define foreach_snat_plugin_api_msg                                     \
1097 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range)                       \
1098 _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature)       \
1099 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping)                     \
1100 _(SNAT_CONTROL_PING, snat_control_ping)                                 \
1101 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump)                   \
1102 _(SNAT_SHOW_CONFIG, snat_show_config)                                   \
1103 _(SNAT_ADDRESS_DUMP, snat_address_dump)                                 \
1104 _(SNAT_INTERFACE_DUMP, snat_interface_dump)                             \
1105 _(SNAT_SET_WORKERS, snat_set_workers)                                   \
1106 _(SNAT_WORKER_DUMP, snat_worker_dump)
1107
1108 /* Set up the API message handling tables */
1109 static clib_error_t *
1110 snat_plugin_api_hookup (vlib_main_t *vm)
1111 {
1112    snat_main_t * sm __attribute__ ((unused)) = &snat_main;
1113 #define _(N,n)                                                  \
1114     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
1115                            #n,                                  \
1116                            vl_api_##n##_t_handler,              \
1117                            vl_noop_handler,                     \
1118                            vl_api_##n##_t_endian,               \
1119                            vl_api_##n##_t_print,                \
1120                            sizeof(vl_api_##n##_t), 1); 
1121     foreach_snat_plugin_api_msg;
1122 #undef _
1123
1124     return 0;
1125 }
1126
1127 #define vl_msg_name_crc_list
1128 #include <snat/snat_all_api_h.h>
1129 #undef vl_msg_name_crc_list
1130
1131 static void
1132 setup_message_id_table (snat_main_t * sm, api_main_t * am)
1133 {
1134 #define _(id,n,crc) \
1135   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1136   foreach_vl_msg_name_crc_snat;
1137 #undef _
1138 }
1139
1140 static void plugin_custom_dump_configure (snat_main_t * sm) 
1141 {
1142 #define _(n,f) sm->api_main->msg_print_handlers \
1143   [VL_API_##n + sm->msg_id_base]                \
1144     = (void *) vl_api_##f##_t_print;
1145   foreach_snat_plugin_api_msg;
1146 #undef _
1147 }
1148
1149 static clib_error_t * snat_init (vlib_main_t * vm)
1150 {
1151   snat_main_t * sm = &snat_main;
1152   clib_error_t * error = 0;
1153   ip4_main_t * im = &ip4_main;
1154   ip_lookup_main_t * lm = &im->lookup_main;
1155   u8 * name;
1156   uword *p;
1157   vlib_thread_registration_t *tr;
1158   vlib_thread_main_t *tm = vlib_get_thread_main ();
1159   uword *bitmap = 0;
1160   u32 i;
1161
1162   name = format (0, "snat_%08x%c", api_version, 0);
1163
1164   /* Ask for a correctly-sized block of API message decode slots */
1165   sm->msg_id_base = vl_msg_api_get_msg_ids 
1166       ((char *) name, VL_MSG_FIRST_AVAILABLE);
1167
1168   sm->vlib_main = vm;
1169   sm->vnet_main = vnet_get_main();
1170   sm->ip4_main = im;
1171   sm->ip4_lookup_main = lm;
1172   sm->api_main = &api_main;
1173   sm->first_worker_index = 0;
1174   sm->next_worker = 0;
1175   sm->num_workers = 0;
1176   sm->workers = 0;
1177   sm->fq_in2out_index = ~0;
1178   sm->fq_out2in_index = ~0;
1179
1180   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1181   if (p)
1182     {
1183       tr = (vlib_thread_registration_t *) p[0];
1184       if (tr)
1185         {
1186           sm->num_workers = tr->count;
1187           sm->first_worker_index = tr->first_index;
1188         }
1189     }
1190
1191   /* Use all available workers by default */
1192   if (sm->num_workers > 1)
1193     {
1194       for (i=0; i < sm->num_workers; i++)
1195         bitmap = clib_bitmap_set (bitmap, i, 1);
1196       snat_set_workers(bitmap);
1197       clib_bitmap_free (bitmap);
1198     }
1199
1200   error = snat_plugin_api_hookup (vm);
1201
1202   /* Add our API messages to the global name_crc hash table */
1203   setup_message_id_table (sm, &api_main);
1204
1205   plugin_custom_dump_configure (sm);
1206   vec_free(name);
1207
1208   return error;
1209 }
1210
1211 VLIB_INIT_FUNCTION (snat_init);
1212
1213 void snat_free_outside_address_and_port (snat_main_t * sm, 
1214                                          snat_session_key_t * k, 
1215                                          u32 address_index)
1216 {
1217   snat_address_t *a;
1218   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1219   
1220   ASSERT (address_index < vec_len (sm->addresses));
1221
1222   a = sm->addresses + address_index;
1223
1224   ASSERT (clib_bitmap_get_no_check (a->busy_port_bitmap,
1225     port_host_byte_order) == 1);
1226
1227   clib_bitmap_set_no_check (a->busy_port_bitmap, port_host_byte_order, 0);
1228   a->busy_ports--;
1229 }  
1230
1231 /**
1232  * @brief Match SNAT static mapping.
1233  *
1234  * @param sm          SNAT main.
1235  * @param match       Address and port to match.
1236  * @param mapping     External or local address and port of the matched mapping.
1237  * @param by_external If 0 match by local address otherwise match by external
1238  *                    address.
1239  *
1240  * @returns 0 if match found otherwise 1.
1241  */
1242 int snat_static_mapping_match (snat_main_t * sm,
1243                                snat_session_key_t match,
1244                                snat_session_key_t * mapping,
1245                                u8 by_external)
1246 {
1247   clib_bihash_kv_8_8_t kv, value;
1248   snat_static_mapping_t *m;
1249   snat_static_mapping_key_t m_key;
1250   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1251
1252   if (by_external)
1253     mapping_hash = &sm->static_mapping_by_external;
1254
1255   m_key.addr = match.addr;
1256   m_key.port = clib_net_to_host_u16 (match.port);
1257   m_key.fib_index = match.fib_index;
1258
1259   kv.key = m_key.as_u64;
1260
1261   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1262     {
1263       /* Try address only mapping */
1264       m_key.port = 0;
1265       kv.key = m_key.as_u64;
1266       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1267         return 1;
1268     }
1269
1270   m = pool_elt_at_index (sm->static_mappings, value.value);
1271
1272   if (by_external)
1273     {
1274       mapping->addr = m->local_addr;
1275       /* Address only mapping doesn't change port */
1276       mapping->port = m->addr_only ? match.port
1277         : clib_host_to_net_u16 (m->local_port);
1278       mapping->fib_index = m->fib_index;
1279     }
1280   else
1281     {
1282       mapping->addr = m->external_addr;
1283       /* Address only mapping doesn't change port */
1284       mapping->port = m->addr_only ? match.port
1285         : clib_host_to_net_u16 (m->external_port);
1286       mapping->fib_index = sm->outside_fib_index;
1287     }
1288
1289   return 0;
1290 }
1291
1292 int snat_alloc_outside_address_and_port (snat_main_t * sm, 
1293                                          snat_session_key_t * k,
1294                                          u32 * address_indexp)
1295 {
1296   int i;
1297   snat_address_t *a;
1298   u32 portnum;
1299
1300   for (i = 0; i < vec_len (sm->addresses); i++)
1301     {
1302       if (sm->addresses[i].busy_ports < (65535-1024))
1303         {
1304           a = sm->addresses + i;
1305
1306           while (1)
1307             {
1308               portnum = random_u32 (&sm->random_seed);
1309               portnum &= 0xFFFF;
1310               if (portnum < 1024)
1311                 continue;
1312               if (clib_bitmap_get_no_check (a->busy_port_bitmap, portnum))
1313                 continue;
1314               clib_bitmap_set_no_check (a->busy_port_bitmap, portnum, 1);
1315               a->busy_ports++;
1316               /* Caller sets protocol and fib index */
1317               k->addr = a->addr;
1318               k->port = clib_host_to_net_u16(portnum);
1319               *address_indexp = i;
1320               return 0;
1321             }
1322         }
1323     }
1324   /* Totally out of translations to use... */
1325   return 1;
1326 }
1327
1328
1329 static clib_error_t *
1330 add_address_command_fn (vlib_main_t * vm,
1331                         unformat_input_t * input,
1332                         vlib_cli_command_t * cmd)
1333 {
1334   unformat_input_t _line_input, *line_input = &_line_input;
1335   snat_main_t * sm = &snat_main;
1336   ip4_address_t start_addr, end_addr, this_addr;
1337   u32 start_host_order, end_host_order;
1338   int i, count;
1339   int is_add = 1;
1340   int rv = 0;
1341
1342   /* Get a line of input. */
1343   if (!unformat_user (input, unformat_line_input, line_input))
1344     return 0;
1345
1346   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1347     {
1348       if (unformat (line_input, "%U - %U",
1349                     unformat_ip4_address, &start_addr,
1350                     unformat_ip4_address, &end_addr))
1351         ;
1352       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1353         end_addr = start_addr;
1354       else if (unformat (line_input, "del"))
1355         is_add = 0;
1356       else
1357         return clib_error_return (0, "unknown input '%U'",
1358           format_unformat_error, input);
1359      }
1360   unformat_free (line_input);
1361
1362   if (sm->static_mapping_only)
1363     return clib_error_return (0, "static mapping only mode");
1364
1365   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1366   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1367   
1368   if (end_host_order < start_host_order)
1369     return clib_error_return (0, "end address less than start address");
1370
1371   count = (end_host_order - start_host_order) + 1;
1372
1373   if (count > 1024)
1374     clib_warning ("%U - %U, %d addresses...",
1375                   format_ip4_address, &start_addr,
1376                   format_ip4_address, &end_addr,
1377                   count);
1378   
1379   this_addr = start_addr;
1380
1381   for (i = 0; i < count; i++)
1382     {
1383       if (is_add)
1384         snat_add_address (sm, &this_addr);
1385       else
1386         rv = snat_del_address (sm, this_addr);
1387
1388       switch (rv)
1389         {
1390         case VNET_API_ERROR_NO_SUCH_ENTRY:
1391           return clib_error_return (0, "S-NAT address not exist.");
1392           break;
1393         case VNET_API_ERROR_UNSPECIFIED:
1394           return clib_error_return (0, "S-NAT address used in static mapping.");
1395           break;
1396         default:
1397           break;
1398         }
1399
1400       increment_v4_address (&this_addr);
1401     }
1402
1403   return 0;
1404 }
1405
1406 VLIB_CLI_COMMAND (add_address_command, static) = {
1407   .path = "snat add address",
1408   .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
1409   .function = add_address_command_fn,
1410 };
1411
1412 static clib_error_t *
1413 snat_feature_command_fn (vlib_main_t * vm,
1414                           unformat_input_t * input,
1415                           vlib_cli_command_t * cmd)
1416 {
1417   unformat_input_t _line_input, *line_input = &_line_input;
1418   vnet_main_t * vnm = vnet_get_main();
1419   clib_error_t * error = 0;
1420   u32 sw_if_index;
1421   u32 * inside_sw_if_indices = 0;
1422   u32 * outside_sw_if_indices = 0;
1423   int is_del = 0;
1424   int i;
1425
1426   sw_if_index = ~0;
1427
1428   /* Get a line of input. */
1429   if (!unformat_user (input, unformat_line_input, line_input))
1430     return 0;
1431
1432   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1433     {
1434       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1435                     vnm, &sw_if_index))
1436         vec_add1 (inside_sw_if_indices, sw_if_index);
1437       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1438                          vnm, &sw_if_index))
1439         vec_add1 (outside_sw_if_indices, sw_if_index);
1440       else if (unformat (line_input, "del"))
1441         is_del = 1;
1442       else
1443         return clib_error_return (0, "unknown input '%U'",
1444           format_unformat_error, input);
1445     }
1446   unformat_free (line_input);
1447
1448   if (vec_len (inside_sw_if_indices))
1449     {
1450       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1451         {
1452           sw_if_index = inside_sw_if_indices[i];
1453           snat_interface_add_del (sw_if_index, 1, is_del);
1454         }
1455     }
1456
1457   if (vec_len (outside_sw_if_indices))
1458     {
1459       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1460         {
1461           sw_if_index = outside_sw_if_indices[i];
1462           snat_interface_add_del (sw_if_index, 0, is_del);
1463         }
1464     }
1465
1466   vec_free (inside_sw_if_indices);
1467   vec_free (outside_sw_if_indices);
1468
1469   return error;
1470 }
1471
1472 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1473   .path = "set interface snat",
1474   .function = snat_feature_command_fn,
1475   .short_help = "set interface snat in <intfc> out <intfc> [del]",
1476 };
1477
1478 static clib_error_t *
1479 add_static_mapping_command_fn (vlib_main_t * vm,
1480                                unformat_input_t * input,
1481                                vlib_cli_command_t * cmd)
1482 {
1483   unformat_input_t _line_input, *line_input = &_line_input;
1484   clib_error_t * error = 0;
1485   ip4_address_t l_addr, e_addr;
1486   u32 l_port = 0, e_port = 0, vrf_id = ~0;
1487   int is_add = 1;
1488   int addr_only = 1;
1489   int rv;
1490
1491   /* Get a line of input. */
1492   if (!unformat_user (input, unformat_line_input, line_input))
1493     return 0;
1494
1495   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1496     {
1497       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1498                     &l_port))
1499         addr_only = 0;
1500       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1501         ;
1502       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1503                          &e_addr, &e_port))
1504         addr_only = 0;
1505       else if (unformat (line_input, "external %U", unformat_ip4_address,
1506                          &e_addr))
1507         ;
1508       else if (unformat (line_input, "vrf %u", &vrf_id))
1509         ;
1510       else if (unformat (line_input, "del"))
1511         is_add = 0;
1512       else
1513         return clib_error_return (0, "unknown input: '%U'",
1514           format_unformat_error, line_input);
1515     }
1516   unformat_free (line_input);
1517
1518   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1519                                vrf_id, addr_only, is_add);
1520
1521   switch (rv)
1522     {
1523     case VNET_API_ERROR_INVALID_VALUE:
1524       return clib_error_return (0, "External port already in use.");
1525       break;
1526     case VNET_API_ERROR_NO_SUCH_ENTRY:
1527       if (is_add)
1528         return clib_error_return (0, "External addres must be allocated.");
1529       else
1530         return clib_error_return (0, "Mapping not exist.");
1531       break;
1532     case VNET_API_ERROR_NO_SUCH_FIB:
1533       return clib_error_return (0, "No such VRF id.");
1534     case VNET_API_ERROR_VALUE_EXIST:
1535       return clib_error_return (0, "Mapping already exist.");
1536     default:
1537       break;
1538     }
1539
1540   return error;
1541 }
1542
1543 /*?
1544  * @cliexpar
1545  * @cliexstart{snat add static mapping}
1546  * Static mapping allows hosts on the external network to initiate connection
1547  * to to the local network host.
1548  * To create static mapping between local host address 10.0.0.3 port 6303 and
1549  * external address 4.4.4.4 port 3606 use:
1550  *  vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606
1551  * If not runnig "static mapping only" S-NAT plugin mode use before:
1552  *  vpp# snat add address 4.4.4.4
1553  * To create static mapping between local and external address use:
1554  *  vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
1555  * @cliexend
1556 ?*/
1557 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1558   .path = "snat add static mapping",
1559   .function = add_static_mapping_command_fn,
1560   .short_help =
1561     "snat add static mapping local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1562 };
1563
1564 static clib_error_t *
1565 set_workers_command_fn (vlib_main_t * vm,
1566                         unformat_input_t * input,
1567                         vlib_cli_command_t * cmd)
1568 {
1569   unformat_input_t _line_input, *line_input = &_line_input;
1570   uword *bitmap = 0;
1571   int rv = 0;
1572
1573   /* Get a line of input. */
1574   if (!unformat_user (input, unformat_line_input, line_input))
1575     return 0;
1576
1577   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1578     {
1579       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1580         ;
1581       else
1582         return clib_error_return (0, "unknown input '%U'",
1583           format_unformat_error, input);
1584      }
1585   unformat_free (line_input);
1586
1587   if (bitmap == 0)
1588     return clib_error_return (0, "List of workers must be specified.");
1589
1590   rv = snat_set_workers(bitmap);
1591
1592   clib_bitmap_free (bitmap);
1593
1594   switch (rv)
1595     {
1596     case VNET_API_ERROR_INVALID_WORKER:
1597       return clib_error_return (0, "Invalid worker(s).");
1598       break;
1599     case VNET_API_ERROR_FEATURE_DISABLED:
1600       return clib_error_return (0,
1601         "Supported only if 2 or more workes available.");
1602       break;
1603     default:
1604       break;
1605     }
1606
1607   return 0;
1608 }
1609
1610 /*?
1611  * @cliexpar
1612  * @cliexstart{set snat workers}
1613  * Set SNAT workers if 2 or more workers available, use:
1614  *  vpp# set snat workers 0-2,5
1615  * @cliexend
1616 ?*/
1617 VLIB_CLI_COMMAND (set_workers_command, static) = {
1618   .path = "set snat workers",
1619   .function = set_workers_command_fn,
1620   .short_help =
1621     "set snat workers <workers-list>",
1622 };
1623
1624 static clib_error_t *
1625 snat_config (vlib_main_t * vm, unformat_input_t * input)
1626 {
1627   snat_main_t * sm = &snat_main;
1628   u32 translation_buckets = 1024;
1629   u32 translation_memory_size = 128<<20;
1630   u32 user_buckets = 128;
1631   u32 user_memory_size = 64<<20;
1632   u32 max_translations_per_user = 100;
1633   u32 outside_vrf_id = 0;
1634   u32 inside_vrf_id = 0;
1635   u32 static_mapping_buckets = 1024;
1636   u32 static_mapping_memory_size = 64<<20;
1637   u8 static_mapping_only = 0;
1638   u8 static_mapping_connection_tracking = 0;
1639   vlib_thread_main_t *tm = vlib_get_thread_main ();
1640
1641   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1642     {
1643       if (unformat (input, "translation hash buckets %d", &translation_buckets))
1644         ;
1645       else if (unformat (input, "translation hash memory %d",
1646                          &translation_memory_size));
1647       else if (unformat (input, "user hash buckets %d", &user_buckets))
1648         ;
1649       else if (unformat (input, "user hash memory %d",
1650                          &user_memory_size))
1651         ;
1652       else if (unformat (input, "max translations per user %d",
1653                          &max_translations_per_user))
1654         ;
1655       else if (unformat (input, "outside VRF id %d",
1656                          &outside_vrf_id))
1657         ;
1658       else if (unformat (input, "inside VRF id %d",
1659                          &inside_vrf_id))
1660         ;
1661       else if (unformat (input, "static mapping only"))
1662         {
1663           static_mapping_only = 1;
1664           if (unformat (input, "connection tracking"))
1665             static_mapping_connection_tracking = 1;
1666         }
1667       else 
1668         return clib_error_return (0, "unknown input '%U'",
1669                                   format_unformat_error, input);
1670     }
1671
1672   /* for show commands, etc. */
1673   sm->translation_buckets = translation_buckets;
1674   sm->translation_memory_size = translation_memory_size;
1675   sm->user_buckets = user_buckets;
1676   sm->user_memory_size = user_memory_size;
1677   sm->max_translations_per_user = max_translations_per_user;
1678   sm->outside_vrf_id = outside_vrf_id;
1679   sm->outside_fib_index = ~0;
1680   sm->inside_vrf_id = inside_vrf_id;
1681   sm->inside_fib_index = ~0;
1682   sm->static_mapping_only = static_mapping_only;
1683   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
1684
1685   if (!static_mapping_only ||
1686       (static_mapping_only && static_mapping_connection_tracking))
1687     {
1688       clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
1689                             user_memory_size);
1690
1691       clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
1692                             user_memory_size);
1693
1694       vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1695
1696       clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
1697                             translation_memory_size);
1698
1699       clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
1700                             translation_memory_size);
1701
1702       clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
1703                             user_memory_size);
1704     }
1705   clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1706                         "static_mapping_by_local", static_mapping_buckets,
1707                         static_mapping_memory_size);
1708
1709   clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1710                         "static_mapping_by_external", static_mapping_buckets,
1711                         static_mapping_memory_size);
1712   return 0;
1713 }
1714
1715 VLIB_CONFIG_FUNCTION (snat_config, "snat");
1716
1717 u8 * format_snat_key (u8 * s, va_list * args)
1718 {
1719   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
1720   char * protocol_string = "unknown";
1721   static char *protocol_strings[] = {
1722       "UDP",
1723       "TCP",
1724       "ICMP",
1725   };
1726
1727   if (key->protocol < ARRAY_LEN(protocol_strings))
1728       protocol_string = protocol_strings[key->protocol];
1729
1730   s = format (s, "%U proto %s port %d fib %d",
1731               format_ip4_address, &key->addr, protocol_string,
1732               clib_net_to_host_u16 (key->port), key->fib_index);
1733   return s;
1734 }
1735
1736 u8 * format_snat_session (u8 * s, va_list * args)
1737 {
1738   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
1739   snat_session_t * sess = va_arg (*args, snat_session_t *);
1740
1741   s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
1742   s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
1743   s = format (s, "       last heard %.2f\n", sess->last_heard);
1744   s = format (s, "       total pkts %d, total bytes %lld\n",
1745               sess->total_pkts, sess->total_bytes);
1746   if (snat_is_session_static (sess))
1747     s = format (s, "       static translation\n");
1748   else
1749     s = format (s, "       dynamic translation\n");
1750
1751   return s;
1752 }
1753
1754 u8 * format_snat_user (u8 * s, va_list * args)
1755 {
1756   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
1757   snat_user_t * u = va_arg (*args, snat_user_t *);
1758   int verbose = va_arg (*args, int);
1759   dlist_elt_t * head, * elt;
1760   u32 elt_index, head_index;
1761   u32 session_index;
1762   snat_session_t * sess;
1763
1764   s = format (s, "%U: %d dynamic translations, %d static translations\n",
1765               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
1766
1767   if (verbose == 0)
1768     return s;
1769
1770   if (u->nsessions || u->nstaticsessions)
1771     {
1772       head_index = u->sessions_per_user_list_head_index;
1773       head = pool_elt_at_index (sm->list_pool, head_index);
1774
1775       elt_index = head->next;
1776       elt = pool_elt_at_index (sm->list_pool, elt_index);
1777       session_index = elt->value;
1778
1779       while (session_index != ~0)
1780         {
1781           sess = pool_elt_at_index (sm->sessions, session_index);
1782
1783           s = format (s, "  %U\n", format_snat_session, sm, sess);
1784
1785           elt_index = elt->next;
1786           elt = pool_elt_at_index (sm->list_pool, elt_index);
1787           session_index = elt->value;
1788         }
1789     }
1790
1791   return s;
1792 }
1793
1794 u8 * format_snat_static_mapping (u8 * s, va_list * args)
1795 {
1796   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
1797
1798   if (m->addr_only)
1799       s = format (s, "local %U external %U vrf %d",
1800                   format_ip4_address, &m->local_addr,
1801                   format_ip4_address, &m->external_addr,
1802                   m->vrf_id);
1803   else
1804       s = format (s, "local %U:%d external %U:%d vrf %d",
1805                   format_ip4_address, &m->local_addr, m->local_port,
1806                   format_ip4_address, &m->external_addr, m->external_port,
1807                   m->vrf_id);
1808
1809   return s;
1810 }
1811
1812 static clib_error_t *
1813 show_snat_command_fn (vlib_main_t * vm,
1814                  unformat_input_t * input,
1815                  vlib_cli_command_t * cmd)
1816 {
1817   int verbose = 0;
1818   snat_main_t * sm = &snat_main;
1819   snat_user_t * u;
1820   snat_static_mapping_t *m;
1821   snat_interface_t *i;
1822   snat_address_t * ap;
1823   vnet_main_t *vnm = vnet_get_main();
1824   snat_main_per_thread_data_t *tsm;
1825   u32 users_num = 0, sessions_num = 0, *worker;
1826   uword j = 0;
1827
1828   if (unformat (input, "detail"))
1829     verbose = 1;
1830   else if (unformat (input, "verbose"))
1831     verbose = 2;
1832
1833   if (sm->static_mapping_only)
1834     {
1835       if (sm->static_mapping_connection_tracking)
1836         vlib_cli_output (vm, "SNAT mode: static mapping only connection "
1837                          "tracking");
1838       else
1839         vlib_cli_output (vm, "SNAT mode: static mapping only");
1840     }
1841   else
1842     {
1843       vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
1844     }
1845
1846   if (verbose > 0)
1847     {
1848       pool_foreach (i, sm->interfaces,
1849       ({
1850         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
1851                          vnet_get_sw_interface (vnm, i->sw_if_index),
1852                          i->is_inside ? "in" : "out");
1853       }));
1854
1855       vec_foreach (ap, sm->addresses)
1856         {
1857           u8 * s = format (0, "");
1858           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
1859           clib_bitmap_foreach (j, ap->busy_port_bitmap,
1860             ({
1861               s = format (s, " %d", j);
1862             }));
1863           vlib_cli_output (vm, "  %d busy ports:%v", ap->busy_ports, s);
1864         }
1865     }
1866
1867   if (sm->num_workers > 1)
1868     {
1869       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
1870       if (verbose > 0)
1871         {
1872           vec_foreach (worker, sm->workers)
1873             {
1874               vlib_worker_thread_t *w =
1875                 vlib_worker_threads + *worker + sm->first_worker_index;
1876               vlib_cli_output (vm, "  %v", w->name);
1877             }
1878         }
1879     }
1880
1881   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1882     {
1883       vlib_cli_output (vm, "%d static mappings",
1884                        pool_elts (sm->static_mappings));
1885
1886       if (verbose > 0)
1887         {
1888           pool_foreach (m, sm->static_mappings,
1889           ({
1890             vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1891           }));
1892         }
1893     }
1894   else
1895     {
1896       vec_foreach (tsm, sm->per_thread_data)
1897         {
1898           users_num += pool_elts (tsm->users);
1899           sessions_num += pool_elts (tsm->sessions);
1900         }
1901
1902       vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
1903                        " %d static mappings",
1904                        users_num,
1905                        vec_len (sm->addresses),
1906                        sessions_num,
1907                        pool_elts (sm->static_mappings));
1908
1909       if (verbose > 0)
1910         {
1911           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
1912                            verbose - 1);
1913           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
1914                            verbose - 1);
1915           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
1916                            verbose - 1);
1917           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
1918                            verbose - 1);
1919           vec_foreach_index (j, sm->per_thread_data)
1920             {
1921               tsm = vec_elt_at_index (sm->per_thread_data, j);
1922
1923               if (pool_elts (tsm->users) == 0)
1924                 continue;
1925
1926               vlib_worker_thread_t *w = vlib_worker_threads + j;
1927               vlib_cli_output (vm, "Thread %d (%v at lcore %u):", j, w->name,
1928                                w->lcore_id);
1929               vlib_cli_output (vm, "  %d list pool elements",
1930                                pool_elts (tsm->list_pool));
1931
1932               pool_foreach (u, tsm->users,
1933               ({
1934                 vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
1935                                  verbose - 1);
1936               }));
1937             }
1938
1939           if (pool_elts (sm->static_mappings))
1940             {
1941               vlib_cli_output (vm, "static mappings:");
1942               pool_foreach (m, sm->static_mappings,
1943               ({
1944                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1945               }));
1946             }
1947         }
1948     }
1949
1950   return 0;
1951 }
1952
1953 VLIB_CLI_COMMAND (show_snat_command, static) = {
1954     .path = "show snat",
1955     .short_help = "show snat",
1956     .function = show_snat_command_fn,
1957 };