snat: fix coverity issues
[vpp.git] / plugins / snat-plugin / 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
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 (a->busy_port_bitmap, e_port))
403                     return VNET_API_ERROR_INVALID_VALUE;
404                   a->busy_port_bitmap = clib_bitmap_set (a->busy_port_bitmap,
405                                                          e_port, 1);
406                   if (e_port > 1024)
407                     a->busy_ports++;
408
409                   break;
410                 }
411             }
412           /* External address must be allocated */
413           if (!a)
414             return VNET_API_ERROR_NO_SUCH_ENTRY;
415         }
416
417       pool_get (sm->static_mappings, m);
418       memset (m, 0, sizeof (*m));
419       m->local_addr = l_addr;
420       m->external_addr = e_addr;
421       m->addr_only = addr_only;
422       m->vrf_id = vrf_id;
423       m->fib_index = fib_index;
424       if (!addr_only)
425         {
426           m->local_port = l_port;
427           m->external_port = e_port;
428         }
429
430       m_key.addr = m->local_addr;
431       m_key.port = m->local_port;
432       m_key.fib_index = m->fib_index;
433       kv.key = m_key.as_u64;
434       kv.value = m - sm->static_mappings;
435       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1);
436
437       m_key.addr = m->external_addr;
438       m_key.port = m->external_port;
439       m_key.fib_index = sm->outside_fib_index;
440       kv.key = m_key.as_u64;
441       kv.value = m - sm->static_mappings;
442       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1);
443     }
444   else
445     {
446       if (!m)
447         return VNET_API_ERROR_NO_SUCH_ENTRY;
448
449       /* Free external address port */
450       if (!addr_only && !(sm->static_mapping_only))
451         {
452           for (i = 0; i < vec_len (sm->addresses); i++)
453             {
454               if (sm->addresses[i].addr.as_u32 == e_addr.as_u32)
455                 {
456                   a = sm->addresses + i;
457                   a->busy_port_bitmap = clib_bitmap_set (a->busy_port_bitmap,
458                                                          e_port, 0);
459                   a->busy_ports--;
460
461                   break;
462                 }
463             }
464         }
465
466       m_key.addr = m->local_addr;
467       m_key.port = m->local_port;
468       m_key.fib_index = m->fib_index;
469       kv.key = m_key.as_u64;
470       clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0);
471
472       m_key.addr = m->external_addr;
473       m_key.port = m->external_port;
474       m_key.fib_index = sm->outside_fib_index;
475       kv.key = m_key.as_u64;
476       clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0);
477
478       /* Delete session(s) for static mapping if exist */
479       if (!(sm->static_mapping_only) ||
480           (sm->static_mapping_only && sm->static_mapping_connection_tracking))
481         {
482           snat_user_key_t u_key;
483           snat_user_t *u;
484           dlist_elt_t * head, * elt;
485           u32 elt_index, head_index, del_elt_index;
486           u32 ses_index;
487           u64 user_index;
488           snat_session_t * s;
489           snat_main_per_thread_data_t *tsm;
490
491           u_key.addr = m->local_addr;
492           u_key.fib_index = m->fib_index;
493           kv.key = u_key.as_u64;
494           if (!clib_bihash_search_8_8 (&sm->user_hash, &kv, &value))
495             {
496               user_index = value.value;
497               if (!clib_bihash_search_8_8 (&sm->worker_by_in, &kv, &value))
498                 tsm = vec_elt_at_index (sm->per_thread_data, value.value);
499               else
500                 tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
501               u = pool_elt_at_index (tsm->users, user_index);
502               if (u->nstaticsessions)
503                 {
504                   head_index = u->sessions_per_user_list_head_index;
505                   head = pool_elt_at_index (tsm->list_pool, head_index);
506                   elt_index = head->next;
507                   elt = pool_elt_at_index (tsm->list_pool, elt_index);
508                   ses_index = elt->value;
509                   while (ses_index != ~0)
510                     {
511                       s =  pool_elt_at_index (tsm->sessions, ses_index);
512                       del_elt_index = elt_index;
513                       elt_index = elt->next;
514                       elt = pool_elt_at_index (tsm->list_pool, elt_index);
515                       ses_index = elt->value;
516
517                       if (!addr_only)
518                         {
519                           if ((s->out2in.addr.as_u32 != e_addr.as_u32) &&
520                               (clib_net_to_host_u16 (s->out2in.port) != e_port))
521                             continue;
522                         }
523
524                       value.key = s->in2out.as_u64;
525                       clib_bihash_add_del_8_8 (&sm->in2out, &value, 0);
526                       value.key = s->out2in.as_u64;
527                       clib_bihash_add_del_8_8 (&sm->out2in, &value, 0);
528                       pool_put (tsm->sessions, s);
529
530                       clib_dlist_remove (tsm->list_pool, del_elt_index);
531                       pool_put_index (tsm->list_pool, del_elt_index);
532                       u->nstaticsessions--;
533
534                       if (!addr_only)
535                         break;
536                     }
537                   if (addr_only)
538                     {
539                       pool_put (tsm->users, u);
540                       clib_bihash_add_del_8_8 (&sm->user_hash, &kv, 0);
541                     }
542                 }
543             }
544         }
545
546       /* Delete static mapping from pool */
547       pool_put (sm->static_mappings, m);
548     }
549
550   return 0;
551 }
552
553 static int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del)
554 {
555   snat_main_t *sm = &snat_main;
556   snat_interface_t *i;
557   const char * feature_name;
558
559   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
560     feature_name = is_inside ?  "snat-in2out-fast" : "snat-out2in-fast";
561   else
562     {
563       if (sm->num_workers > 1)
564         feature_name = is_inside ?  "snat-in2out-worker-handoff" : "snat-out2in-worker-handoff";
565       else
566         feature_name = is_inside ?  "snat-in2out" : "snat-out2in";
567     }
568
569   vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index,
570                                !is_del, 0, 0);
571
572   if (sm->fq_in2out_index == ~0)
573     sm->fq_in2out_index = vlib_frame_queue_main_init (snat_in2out_node.index, 0);
574
575   if (sm->fq_out2in_index == ~0)
576     sm->fq_out2in_index = vlib_frame_queue_main_init (snat_out2in_node.index, 0);
577
578   pool_foreach (i, sm->interfaces,
579   ({
580     if (i->sw_if_index == sw_if_index)
581       {
582         if (is_del)
583           pool_put (sm->interfaces, i);
584         else
585           return VNET_API_ERROR_VALUE_EXIST;
586
587         return 0;
588       }
589   }));
590
591   if (is_del)
592     return VNET_API_ERROR_NO_SUCH_ENTRY;
593
594   pool_get (sm->interfaces, i);
595   i->sw_if_index = sw_if_index;
596   i->is_inside = is_inside;
597
598   return 0;
599 }
600
601 static int snat_set_workers (uword * bitmap)
602 {
603   snat_main_t *sm = &snat_main;
604   int i;
605
606   if (sm->num_workers < 2)
607     return VNET_API_ERROR_FEATURE_DISABLED;
608
609   if (clib_bitmap_last_set (bitmap) >= sm->num_workers)
610     return VNET_API_ERROR_INVALID_WORKER;
611
612   vec_free (sm->workers);
613   clib_bitmap_foreach (i, bitmap,
614     ({
615       vec_add1(sm->workers, i);
616     }));
617
618   return 0;
619 }
620
621 static void 
622 vl_api_snat_add_address_range_t_handler
623 (vl_api_snat_add_address_range_t * mp)
624 {
625   snat_main_t * sm = &snat_main;
626   vl_api_snat_add_address_range_reply_t * rmp;
627   ip4_address_t this_addr;
628   u32 start_host_order, end_host_order;
629   int i, count;
630   int rv = 0;
631   u32 * tmp;
632
633   if (mp->is_ip4 != 1)
634     {
635       rv = VNET_API_ERROR_UNIMPLEMENTED;
636       goto send_reply;
637     }
638
639   if (sm->static_mapping_only)
640     {
641       rv = VNET_API_ERROR_FEATURE_DISABLED;
642       goto send_reply;
643     }
644
645   tmp = (u32 *) mp->first_ip_address;
646   start_host_order = clib_host_to_net_u32 (tmp[0]);
647   tmp = (u32 *) mp->last_ip_address;
648   end_host_order = clib_host_to_net_u32 (tmp[0]);
649
650   count = (end_host_order - start_host_order) + 1;
651
652   if (count > 1024)
653     clib_warning ("%U - %U, %d addresses...",
654                   format_ip4_address, mp->first_ip_address,
655                   format_ip4_address, mp->last_ip_address,
656                   count);
657   
658   memcpy (&this_addr.as_u8, mp->first_ip_address, 4);
659
660   for (i = 0; i < count; i++)
661     {
662       if (mp->is_add)
663         snat_add_address (sm, &this_addr);
664       else
665         rv = snat_del_address (sm, this_addr);
666
667       if (rv)
668         goto send_reply;
669
670       increment_v4_address (&this_addr);
671     }
672
673  send_reply:
674   REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
675 }
676
677 static void *vl_api_snat_add_address_range_t_print
678 (vl_api_snat_add_address_range_t *mp, void * handle)
679 {
680   u8 * s;
681
682   s = format (0, "SCRIPT: snat_add_address_range ");
683   s = format (s, "%U ", format_ip4_address, mp->first_ip_address);
684   if (memcmp (mp->first_ip_address, mp->last_ip_address, 4))
685     {
686       s = format (s, " - %U ", format_ip4_address, mp->last_ip_address);
687     }
688   FINISH;
689 }
690
691 static void
692 send_snat_address_details
693 (snat_address_t * a, unix_shared_memory_queue_t * q, u32 context)
694 {
695   vl_api_snat_address_details_t *rmp;
696   snat_main_t * sm = &snat_main;
697
698   rmp = vl_msg_api_alloc (sizeof (*rmp));
699   memset (rmp, 0, sizeof (*rmp));
700   rmp->_vl_msg_id = ntohs (VL_API_SNAT_ADDRESS_DETAILS+sm->msg_id_base);
701   rmp->is_ip4 = 1;
702   clib_memcpy (rmp->ip_address, &(a->addr), 4);
703   rmp->context = context;
704
705   vl_msg_api_send_shmem (q, (u8 *) & rmp);
706 }
707
708 static void
709 vl_api_snat_address_dump_t_handler
710 (vl_api_snat_address_dump_t * mp)
711 {
712   unix_shared_memory_queue_t *q;
713   snat_main_t * sm = &snat_main;
714   snat_address_t * a;
715
716   q = vl_api_client_index_to_input_queue (mp->client_index);
717   if (q == 0)
718     return;
719
720   vec_foreach (a, sm->addresses)
721     send_snat_address_details (a, q, mp->context);
722 }
723
724 static void *vl_api_snat_address_dump_t_print
725 (vl_api_snat_address_dump_t *mp, void * handle)
726 {
727   u8 *s;
728
729   s = format (0, "SCRIPT: snat_address_dump ");
730
731   FINISH;
732 }
733
734 static void
735 vl_api_snat_interface_add_del_feature_t_handler
736 (vl_api_snat_interface_add_del_feature_t * mp)
737 {
738   snat_main_t * sm = &snat_main;
739   vl_api_snat_interface_add_del_feature_reply_t * rmp;
740   u8 is_del = mp->is_add == 0;
741   u32 sw_if_index = ntohl(mp->sw_if_index);
742   int rv = 0;
743
744   VALIDATE_SW_IF_INDEX(mp);
745
746   rv = snat_interface_add_del (sw_if_index, mp->is_inside, is_del);
747   
748   BAD_SW_IF_INDEX_LABEL;
749
750   REPLY_MACRO(VL_API_SNAT_INTERFACE_ADD_DEL_FEATURE_REPLY);
751 }
752
753 static void *vl_api_snat_interface_add_del_feature_t_print
754 (vl_api_snat_interface_add_del_feature_t * mp, void *handle)
755 {
756   u8 * s;
757
758   s = format (0, "SCRIPT: snat_interface_add_del_feature ");
759   s = format (s, "sw_if_index %d %s %s",
760               clib_host_to_net_u32(mp->sw_if_index),
761               mp->is_inside ? "in":"out",
762               mp->is_add ? "" : "del");
763
764   FINISH;
765 }
766
767 static void
768 send_snat_interface_details
769 (snat_interface_t * i, unix_shared_memory_queue_t * q, u32 context)
770 {
771   vl_api_snat_interface_details_t *rmp;
772   snat_main_t * sm = &snat_main;
773
774   rmp = vl_msg_api_alloc (sizeof (*rmp));
775   memset (rmp, 0, sizeof (*rmp));
776   rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_DETAILS+sm->msg_id_base);
777   rmp->sw_if_index = ntohl (i->sw_if_index);
778   rmp->is_inside = i->is_inside;
779   rmp->context = context;
780
781   vl_msg_api_send_shmem (q, (u8 *) & rmp);
782 }
783
784 static void
785 vl_api_snat_interface_dump_t_handler
786 (vl_api_snat_interface_dump_t * mp)
787 {
788   unix_shared_memory_queue_t *q;
789   snat_main_t * sm = &snat_main;
790   snat_interface_t * i;
791
792   q = vl_api_client_index_to_input_queue (mp->client_index);
793   if (q == 0)
794     return;
795
796   pool_foreach (i, sm->interfaces,
797   ({
798     send_snat_interface_details(i, q, mp->context);
799   }));
800 }
801
802 static void *vl_api_snat_interface_dump_t_print
803 (vl_api_snat_interface_dump_t *mp, void * handle)
804 {
805   u8 *s;
806
807   s = format (0, "SCRIPT: snat_interface_dump ");
808
809   FINISH;
810 }static void
811
812 vl_api_snat_add_static_mapping_t_handler
813 (vl_api_snat_add_static_mapping_t * mp)
814 {
815   snat_main_t * sm = &snat_main;
816   vl_api_snat_add_static_mapping_reply_t * rmp;
817   ip4_address_t local_addr, external_addr;
818   u16 local_port = 0, external_port = 0;
819   u32 vrf_id;
820   int rv = 0;
821
822   if (mp->is_ip4 != 1)
823     {
824       rv = VNET_API_ERROR_UNIMPLEMENTED;
825       goto send_reply;
826     }
827
828   memcpy (&local_addr.as_u8, mp->local_ip_address, 4);
829   memcpy (&external_addr.as_u8, mp->external_ip_address, 4);
830   if (mp->addr_only == 0)
831     {
832       local_port = clib_net_to_host_u16 (mp->local_port);
833       external_port = clib_net_to_host_u16 (mp->external_port);
834     }
835   vrf_id = clib_net_to_host_u32 (mp->vrf_id);
836
837   rv = snat_add_static_mapping(local_addr, external_addr, local_port,
838                                external_port, vrf_id, mp->addr_only,
839                                mp->is_add);
840
841  send_reply:
842   REPLY_MACRO (VL_API_SNAT_ADD_ADDRESS_RANGE_REPLY);
843 }
844
845 static void *vl_api_snat_add_static_mapping_t_print
846 (vl_api_snat_add_static_mapping_t *mp, void * handle)
847 {
848   u8 * s;
849
850   s = format (0, "SCRIPT: snat_add_static_mapping ");
851   s = format (s, "local_addr %U external_addr %U ",
852               format_ip4_address, mp->local_ip_address,
853               format_ip4_address, mp->external_ip_address);
854
855   if (mp->addr_only == 0)
856     s = format (s, "local_port %d external_port %d ",
857                 clib_net_to_host_u16 (mp->local_port),
858                 clib_net_to_host_u16 (mp->external_port));
859
860   if (mp->vrf_id != ~0)
861     s = format (s, "vrf %d", clib_net_to_host_u32 (mp->vrf_id));
862
863   FINISH;
864 }
865
866 static void
867 send_snat_static_mapping_details
868 (snat_static_mapping_t * m, unix_shared_memory_queue_t * q, u32 context)
869 {
870   vl_api_snat_static_mapping_details_t *rmp;
871   snat_main_t * sm = &snat_main;
872
873   rmp = vl_msg_api_alloc (sizeof (*rmp));
874   memset (rmp, 0, sizeof (*rmp));
875   rmp->_vl_msg_id = ntohs (VL_API_SNAT_STATIC_MAPPING_DETAILS+sm->msg_id_base);
876   rmp->is_ip4 = 1;
877   rmp->addr_only = m->addr_only;
878   clib_memcpy (rmp->local_ip_address, &(m->local_addr), 4);
879   clib_memcpy (rmp->external_ip_address, &(m->external_addr), 4);
880   rmp->local_port = htons (m->local_port);
881   rmp->external_port = htons (m->external_port);
882   rmp->vrf_id = htonl (m->vrf_id);
883   rmp->context = context;
884
885   vl_msg_api_send_shmem (q, (u8 *) & rmp);
886 }
887
888 static void
889 vl_api_snat_static_mapping_dump_t_handler
890 (vl_api_snat_static_mapping_dump_t * mp)
891 {
892   unix_shared_memory_queue_t *q;
893   snat_main_t * sm = &snat_main;
894   snat_static_mapping_t * m;
895
896   q = vl_api_client_index_to_input_queue (mp->client_index);
897   if (q == 0)
898     return;
899
900   pool_foreach (m, sm->static_mappings,
901   ({
902       send_snat_static_mapping_details (m, q, mp->context);
903   }));
904 }
905
906 static void *vl_api_snat_static_mapping_dump_t_print
907 (vl_api_snat_static_mapping_dump_t *mp, void * handle)
908 {
909   u8 *s;
910
911   s = format (0, "SCRIPT: snat_static_mapping_dump ");
912
913   FINISH;
914 }
915
916 static void
917 vl_api_snat_control_ping_t_handler
918 (vl_api_snat_control_ping_t * mp)
919 {
920   vl_api_snat_control_ping_reply_t *rmp;
921   snat_main_t * sm = &snat_main;
922   int rv = 0;
923
924   REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY,
925   ({
926     rmp->vpe_pid = ntohl (getpid());
927   }));
928 }
929
930 static void *vl_api_snat_control_ping_t_print
931 (vl_api_snat_control_ping_t *mp, void * handle)
932 {
933   u8 *s;
934
935   s = format (0, "SCRIPT: snat_control_ping ");
936
937   FINISH;
938 }
939
940 static void
941 vl_api_snat_show_config_t_handler
942 (vl_api_snat_show_config_t * mp)
943 {
944   vl_api_snat_show_config_reply_t *rmp;
945   snat_main_t * sm = &snat_main;
946   int rv = 0;
947
948   REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY,
949   ({
950     rmp->translation_buckets = htons (sm->translation_buckets);
951     rmp->translation_memory_size = htons (sm->translation_memory_size);
952     rmp->user_buckets = htons (sm->user_buckets);
953     rmp->user_memory_size = htons (sm->user_memory_size);
954     rmp->max_translations_per_user = htons (sm->max_translations_per_user);
955     rmp->outside_vrf_id = htons (sm->outside_vrf_id);
956     rmp->inside_vrf_id = htons (sm->inside_vrf_id);
957     rmp->static_mapping_only = sm->static_mapping_only;
958     rmp->static_mapping_connection_tracking =
959       sm->static_mapping_connection_tracking;
960   }));
961 }
962
963 static void *vl_api_snat_show_config_t_print
964 (vl_api_snat_show_config_t *mp, void * handle)
965 {
966   u8 *s;
967
968   s = format (0, "SCRIPT: snat_show_config ");
969
970   FINISH;
971 }
972
973 static void 
974 vl_api_snat_set_workers_t_handler
975 (vl_api_snat_set_workers_t * mp)
976 {
977   snat_main_t * sm = &snat_main;
978   vl_api_snat_set_workers_reply_t * rmp;
979   int rv = 0;
980   uword *bitmap = 0;
981   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
982
983   if (sm->num_workers < 2)
984     {
985       rv = VNET_API_ERROR_FEATURE_DISABLED;
986       goto send_reply;
987     }
988
989   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
990   rv = snat_set_workers(bitmap);
991   clib_bitmap_free (bitmap);
992
993  send_reply:
994   REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY);
995 }
996
997 static void *vl_api_snat_set_workers_t_print
998 (vl_api_snat_set_workers_t *mp, void * handle)
999 {
1000   u8 * s;
1001   uword *bitmap = 0;
1002   u8 first = 1;
1003   int i;
1004   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1005
1006   s = format (0, "SCRIPT: snat_set_workers ");
1007   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
1008   clib_bitmap_foreach (i, bitmap,
1009     ({
1010       if (first)
1011         s = format (s, "%d", i);
1012       else
1013         s = format (s, ",%d", i);
1014       first = 0;
1015     }));
1016   clib_bitmap_free (bitmap);
1017   FINISH;
1018 }
1019
1020 static void
1021 send_snat_worker_details
1022 (u32 worker_index, unix_shared_memory_queue_t * q, u32 context)
1023 {
1024   vl_api_snat_worker_details_t *rmp;
1025   snat_main_t * sm = &snat_main;
1026   vlib_worker_thread_t *w =
1027     vlib_worker_threads + worker_index + sm->first_worker_index;
1028
1029   rmp = vl_msg_api_alloc (sizeof (*rmp));
1030   memset (rmp, 0, sizeof (*rmp));
1031   rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base);
1032   rmp->context = context;
1033   rmp->worker_index = htonl (worker_index);
1034   rmp->lcore_id = htonl (w->lcore_id);
1035   strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
1036
1037   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1038 }
1039
1040 static void
1041 vl_api_snat_worker_dump_t_handler
1042 (vl_api_snat_worker_dump_t * mp)
1043 {
1044   unix_shared_memory_queue_t *q;
1045   snat_main_t * sm = &snat_main;
1046   u32 * worker_index;
1047
1048   q = vl_api_client_index_to_input_queue (mp->client_index);
1049   if (q == 0)
1050     return;
1051
1052   vec_foreach (worker_index, sm->workers)
1053     {
1054       send_snat_worker_details(*worker_index, q, mp->context);
1055     }
1056 }
1057
1058 static void *vl_api_snat_worker_dump_t_print
1059 (vl_api_snat_worker_dump_t *mp, void * handle)
1060 {
1061   u8 *s;
1062
1063   s = format (0, "SCRIPT: snat_worker_dump ");
1064
1065   FINISH;
1066 }
1067
1068 /* List of message types that this plugin understands */
1069 #define foreach_snat_plugin_api_msg                                     \
1070 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range)                       \
1071 _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature)       \
1072 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping)                     \
1073 _(SNAT_CONTROL_PING, snat_control_ping)                                 \
1074 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump)                   \
1075 _(SNAT_SHOW_CONFIG, snat_show_config)                                   \
1076 _(SNAT_ADDRESS_DUMP, snat_address_dump)                                 \
1077 _(SNAT_INTERFACE_DUMP, snat_interface_dump)                             \
1078 _(SNAT_SET_WORKERS, snat_set_workers)                                   \
1079 _(SNAT_WORKER_DUMP, snat_worker_dump)
1080
1081 /* Set up the API message handling tables */
1082 static clib_error_t *
1083 snat_plugin_api_hookup (vlib_main_t *vm)
1084 {
1085    snat_main_t * sm __attribute__ ((unused)) = &snat_main;
1086 #define _(N,n)                                                  \
1087     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
1088                            #n,                                  \
1089                            vl_api_##n##_t_handler,              \
1090                            vl_noop_handler,                     \
1091                            vl_api_##n##_t_endian,               \
1092                            vl_api_##n##_t_print,                \
1093                            sizeof(vl_api_##n##_t), 1); 
1094     foreach_snat_plugin_api_msg;
1095 #undef _
1096
1097     return 0;
1098 }
1099
1100 #define vl_msg_name_crc_list
1101 #include <snat/snat_all_api_h.h>
1102 #undef vl_msg_name_crc_list
1103
1104 static void
1105 setup_message_id_table (snat_main_t * sm, api_main_t * am)
1106 {
1107 #define _(id,n,crc) \
1108   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1109   foreach_vl_msg_name_crc_snat;
1110 #undef _
1111 }
1112
1113 static void plugin_custom_dump_configure (snat_main_t * sm) 
1114 {
1115 #define _(n,f) sm->api_main->msg_print_handlers \
1116   [VL_API_##n + sm->msg_id_base]                \
1117     = (void *) vl_api_##f##_t_print;
1118   foreach_snat_plugin_api_msg;
1119 #undef _
1120 }
1121
1122 static clib_error_t * snat_init (vlib_main_t * vm)
1123 {
1124   snat_main_t * sm = &snat_main;
1125   clib_error_t * error = 0;
1126   ip4_main_t * im = &ip4_main;
1127   ip_lookup_main_t * lm = &im->lookup_main;
1128   u8 * name;
1129   uword *p;
1130   vlib_thread_registration_t *tr;
1131   vlib_thread_main_t *tm = vlib_get_thread_main ();
1132   uword *bitmap = 0;
1133   u32 i;
1134
1135   name = format (0, "snat_%08x%c", api_version, 0);
1136
1137   /* Ask for a correctly-sized block of API message decode slots */
1138   sm->msg_id_base = vl_msg_api_get_msg_ids 
1139       ((char *) name, VL_MSG_FIRST_AVAILABLE);
1140
1141   sm->vlib_main = vm;
1142   sm->vnet_main = vnet_get_main();
1143   sm->ip4_main = im;
1144   sm->ip4_lookup_main = lm;
1145   sm->api_main = &api_main;
1146   sm->first_worker_index = 0;
1147   sm->next_worker = 0;
1148   sm->num_workers = 0;
1149   sm->workers = 0;
1150   sm->fq_in2out_index = ~0;
1151   sm->fq_out2in_index = ~0;
1152
1153   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1154   if (p)
1155     {
1156       tr = (vlib_thread_registration_t *) p[0];
1157       if (tr)
1158         {
1159           sm->num_workers = tr->count;
1160           sm->first_worker_index = tr->first_index;
1161         }
1162     }
1163
1164   /* Use all available workers by default */
1165   if (sm->num_workers > 1)
1166     {
1167       for (i=0; i < sm->num_workers; i++)
1168         bitmap = clib_bitmap_set (bitmap, i, 1);
1169       snat_set_workers(bitmap);
1170       clib_bitmap_free (bitmap);
1171     }
1172
1173   error = snat_plugin_api_hookup (vm);
1174
1175   /* Add our API messages to the global name_crc hash table */
1176   setup_message_id_table (sm, &api_main);
1177
1178   plugin_custom_dump_configure (sm);
1179   vec_free(name);
1180
1181   return error;
1182 }
1183
1184 VLIB_INIT_FUNCTION (snat_init);
1185
1186 void snat_free_outside_address_and_port (snat_main_t * sm, 
1187                                          snat_session_key_t * k, 
1188                                          u32 address_index)
1189 {
1190   snat_address_t *a;
1191   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1192   
1193   ASSERT (address_index < vec_len (sm->addresses));
1194
1195   a = sm->addresses + address_index;
1196
1197   ASSERT (clib_bitmap_get (a->busy_port_bitmap, port_host_byte_order) == 1);
1198
1199   a->busy_port_bitmap = clib_bitmap_set (a->busy_port_bitmap, 
1200                                          port_host_byte_order, 0);
1201   a->busy_ports--;
1202 }  
1203
1204 /**
1205  * @brief Match SNAT static mapping.
1206  *
1207  * @param sm          SNAT main.
1208  * @param match       Address and port to match.
1209  * @param mapping     External or local address and port of the matched mapping.
1210  * @param by_external If 0 match by local address otherwise match by external
1211  *                    address.
1212  *
1213  * @returns 0 if match found otherwise 1.
1214  */
1215 int snat_static_mapping_match (snat_main_t * sm,
1216                                snat_session_key_t match,
1217                                snat_session_key_t * mapping,
1218                                u8 by_external)
1219 {
1220   clib_bihash_kv_8_8_t kv, value;
1221   snat_static_mapping_t *m;
1222   snat_static_mapping_key_t m_key;
1223   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1224
1225   if (by_external)
1226     mapping_hash = &sm->static_mapping_by_external;
1227
1228   m_key.addr = match.addr;
1229   m_key.port = clib_net_to_host_u16 (match.port);
1230   m_key.fib_index = match.fib_index;
1231
1232   kv.key = m_key.as_u64;
1233
1234   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1235     {
1236       /* Try address only mapping */
1237       m_key.port = 0;
1238       kv.key = m_key.as_u64;
1239       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1240         return 1;
1241     }
1242
1243   m = pool_elt_at_index (sm->static_mappings, value.value);
1244
1245   if (by_external)
1246     {
1247       mapping->addr = m->local_addr;
1248       /* Address only mapping doesn't change port */
1249       mapping->port = m->addr_only ? match.port
1250         : clib_host_to_net_u16 (m->local_port);
1251       mapping->fib_index = m->fib_index;
1252     }
1253   else
1254     {
1255       mapping->addr = m->external_addr;
1256       /* Address only mapping doesn't change port */
1257       mapping->port = m->addr_only ? match.port
1258         : clib_host_to_net_u16 (m->external_port);
1259       mapping->fib_index = sm->outside_fib_index;
1260     }
1261
1262   return 0;
1263 }
1264
1265 int snat_alloc_outside_address_and_port (snat_main_t * sm, 
1266                                          snat_session_key_t * k,
1267                                          u32 * address_indexp)
1268 {
1269   int i;
1270   snat_address_t *a;
1271   u32 portnum;
1272
1273   for (i = 0; i < vec_len (sm->addresses); i++)
1274     {
1275       if (sm->addresses[i].busy_ports < (65535-1024))
1276         {
1277           a = sm->addresses + i;
1278
1279           while (1)
1280             {
1281               portnum = random_u32 (&sm->random_seed);
1282               portnum &= 0xFFFF;
1283               if (portnum < 1024)
1284                 continue;
1285               if (clib_bitmap_get (a->busy_port_bitmap, portnum))
1286                 continue;
1287               a->busy_port_bitmap = clib_bitmap_set (a->busy_port_bitmap,
1288                                                      portnum, 1);
1289               a->busy_ports++;
1290               /* Caller sets protocol and fib index */
1291               k->addr = a->addr;
1292               k->port = clib_host_to_net_u16(portnum);
1293               *address_indexp = i;
1294               return 0;
1295             }
1296         }
1297     }
1298   /* Totally out of translations to use... */
1299   return 1;
1300 }
1301
1302
1303 static clib_error_t *
1304 add_address_command_fn (vlib_main_t * vm,
1305                         unformat_input_t * input,
1306                         vlib_cli_command_t * cmd)
1307 {
1308   unformat_input_t _line_input, *line_input = &_line_input;
1309   snat_main_t * sm = &snat_main;
1310   ip4_address_t start_addr, end_addr, this_addr;
1311   u32 start_host_order, end_host_order;
1312   int i, count;
1313   int is_add = 1;
1314   int rv = 0;
1315
1316   /* Get a line of input. */
1317   if (!unformat_user (input, unformat_line_input, line_input))
1318     return 0;
1319
1320   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1321     {
1322       if (unformat (line_input, "%U - %U",
1323                     unformat_ip4_address, &start_addr,
1324                     unformat_ip4_address, &end_addr))
1325         ;
1326       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1327         end_addr = start_addr;
1328       else if (unformat (line_input, "del"))
1329         is_add = 0;
1330       else
1331         return clib_error_return (0, "unknown input '%U'",
1332           format_unformat_error, input);
1333      }
1334   unformat_free (line_input);
1335
1336   if (sm->static_mapping_only)
1337     return clib_error_return (0, "static mapping only mode");
1338
1339   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1340   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1341   
1342   if (end_host_order < start_host_order)
1343     return clib_error_return (0, "end address less than start address");
1344
1345   count = (end_host_order - start_host_order) + 1;
1346
1347   if (count > 1024)
1348     clib_warning ("%U - %U, %d addresses...",
1349                   format_ip4_address, &start_addr,
1350                   format_ip4_address, &end_addr,
1351                   count);
1352   
1353   this_addr = start_addr;
1354
1355   for (i = 0; i < count; i++)
1356     {
1357       if (is_add)
1358         snat_add_address (sm, &this_addr);
1359       else
1360         rv = snat_del_address (sm, this_addr);
1361
1362       switch (rv)
1363         {
1364         case VNET_API_ERROR_NO_SUCH_ENTRY:
1365           return clib_error_return (0, "S-NAT address not exist.");
1366           break;
1367         case VNET_API_ERROR_UNSPECIFIED:
1368           return clib_error_return (0, "S-NAT address used in static mapping.");
1369           break;
1370         default:
1371           break;
1372         }
1373
1374       increment_v4_address (&this_addr);
1375     }
1376
1377   return 0;
1378 }
1379
1380 VLIB_CLI_COMMAND (add_address_command, static) = {
1381   .path = "snat add address",
1382   .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
1383   .function = add_address_command_fn,
1384 };
1385
1386 static clib_error_t *
1387 snat_feature_command_fn (vlib_main_t * vm,
1388                           unformat_input_t * input,
1389                           vlib_cli_command_t * cmd)
1390 {
1391   unformat_input_t _line_input, *line_input = &_line_input;
1392   vnet_main_t * vnm = vnet_get_main();
1393   clib_error_t * error = 0;
1394   u32 sw_if_index;
1395   u32 * inside_sw_if_indices = 0;
1396   u32 * outside_sw_if_indices = 0;
1397   int is_del = 0;
1398   int i;
1399
1400   sw_if_index = ~0;
1401
1402   /* Get a line of input. */
1403   if (!unformat_user (input, unformat_line_input, line_input))
1404     return 0;
1405
1406   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1407     {
1408       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1409                     vnm, &sw_if_index))
1410         vec_add1 (inside_sw_if_indices, sw_if_index);
1411       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1412                          vnm, &sw_if_index))
1413         vec_add1 (outside_sw_if_indices, sw_if_index);
1414       else if (unformat (line_input, "del"))
1415         is_del = 1;
1416       else
1417         return clib_error_return (0, "unknown input '%U'",
1418           format_unformat_error, input);
1419     }
1420   unformat_free (line_input);
1421
1422   if (vec_len (inside_sw_if_indices))
1423     {
1424       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1425         {
1426           sw_if_index = inside_sw_if_indices[i];
1427           snat_interface_add_del (sw_if_index, 1, is_del);
1428         }
1429     }
1430
1431   if (vec_len (outside_sw_if_indices))
1432     {
1433       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1434         {
1435           sw_if_index = outside_sw_if_indices[i];
1436           snat_interface_add_del (sw_if_index, 0, is_del);
1437         }
1438     }
1439
1440   vec_free (inside_sw_if_indices);
1441   vec_free (outside_sw_if_indices);
1442
1443   return error;
1444 }
1445
1446 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1447   .path = "set interface snat",
1448   .function = snat_feature_command_fn,
1449   .short_help = "set interface snat in <intfc> out <intfc> [del]",
1450 };
1451
1452 static clib_error_t *
1453 add_static_mapping_command_fn (vlib_main_t * vm,
1454                                unformat_input_t * input,
1455                                vlib_cli_command_t * cmd)
1456 {
1457   unformat_input_t _line_input, *line_input = &_line_input;
1458   clib_error_t * error = 0;
1459   ip4_address_t l_addr, e_addr;
1460   u32 l_port = 0, e_port = 0, vrf_id = ~0;
1461   int is_add = 1;
1462   int addr_only = 1;
1463   int rv;
1464
1465   /* Get a line of input. */
1466   if (!unformat_user (input, unformat_line_input, line_input))
1467     return 0;
1468
1469   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1470     {
1471       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1472                     &l_port))
1473         addr_only = 0;
1474       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1475         ;
1476       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1477                          &e_addr, &e_port))
1478         addr_only = 0;
1479       else if (unformat (line_input, "external %U", unformat_ip4_address,
1480                          &e_addr))
1481         ;
1482       else if (unformat (line_input, "vrf %u", &vrf_id))
1483         ;
1484       else if (unformat (line_input, "del"))
1485         is_add = 0;
1486       else
1487         return clib_error_return (0, "unknown input: '%U'",
1488           format_unformat_error, line_input);
1489     }
1490   unformat_free (line_input);
1491
1492   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1493                                vrf_id, addr_only, is_add);
1494
1495   switch (rv)
1496     {
1497     case VNET_API_ERROR_INVALID_VALUE:
1498       return clib_error_return (0, "External port already in use.");
1499       break;
1500     case VNET_API_ERROR_NO_SUCH_ENTRY:
1501       if (is_add)
1502         return clib_error_return (0, "External addres must be allocated.");
1503       else
1504         return clib_error_return (0, "Mapping not exist.");
1505       break;
1506     case VNET_API_ERROR_NO_SUCH_FIB:
1507       return clib_error_return (0, "No such VRF id.");
1508     case VNET_API_ERROR_VALUE_EXIST:
1509       return clib_error_return (0, "Mapping already exist.");
1510     default:
1511       break;
1512     }
1513
1514   return error;
1515 }
1516
1517 /*?
1518  * @cliexpar
1519  * @cliexstart{snat add static mapping}
1520  * Static mapping allows hosts on the external network to initiate connection
1521  * to to the local network host.
1522  * To create static mapping between local host address 10.0.0.3 port 6303 and
1523  * external address 4.4.4.4 port 3606 use:
1524  *  vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606
1525  * If not runnig "static mapping only" S-NAT plugin mode use before:
1526  *  vpp# snat add address 4.4.4.4
1527  * To create static mapping between local and external address use:
1528  *  vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
1529  * @cliexend
1530 ?*/
1531 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1532   .path = "snat add static mapping",
1533   .function = add_static_mapping_command_fn,
1534   .short_help =
1535     "snat add static mapping local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1536 };
1537
1538 static clib_error_t *
1539 set_workers_command_fn (vlib_main_t * vm,
1540                         unformat_input_t * input,
1541                         vlib_cli_command_t * cmd)
1542 {
1543   unformat_input_t _line_input, *line_input = &_line_input;
1544   uword *bitmap = 0;
1545   int rv = 0;
1546
1547   /* Get a line of input. */
1548   if (!unformat_user (input, unformat_line_input, line_input))
1549     return 0;
1550
1551   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1552     {
1553       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1554         ;
1555       else
1556         return clib_error_return (0, "unknown input '%U'",
1557           format_unformat_error, input);
1558      }
1559   unformat_free (line_input);
1560
1561   if (bitmap == 0)
1562     return clib_error_return (0, "List of workers must be specified.");
1563
1564   rv = snat_set_workers(bitmap);
1565
1566   clib_bitmap_free (bitmap);
1567
1568   switch (rv)
1569     {
1570     case VNET_API_ERROR_INVALID_WORKER:
1571       return clib_error_return (0, "Invalid worker(s).");
1572       break;
1573     case VNET_API_ERROR_FEATURE_DISABLED:
1574       return clib_error_return (0,
1575         "Supported only if 2 or more workes available.");
1576       break;
1577     default:
1578       break;
1579     }
1580
1581   return 0;
1582 }
1583
1584 /*?
1585  * @cliexpar
1586  * @cliexstart{set snat workers}
1587  * Set SNAT workers if 2 or more workers available, use:
1588  *  vpp# set snat workers 0-2,5
1589  * @cliexend
1590 ?*/
1591 VLIB_CLI_COMMAND (set_workers_command, static) = {
1592   .path = "set snat workers",
1593   .function = set_workers_command_fn,
1594   .short_help =
1595     "set snat workers <workers-list>",
1596 };
1597
1598 static clib_error_t *
1599 snat_config (vlib_main_t * vm, unformat_input_t * input)
1600 {
1601   snat_main_t * sm = &snat_main;
1602   u32 translation_buckets = 1024;
1603   u32 translation_memory_size = 128<<20;
1604   u32 user_buckets = 128;
1605   u32 user_memory_size = 64<<20;
1606   u32 max_translations_per_user = 100;
1607   u32 outside_vrf_id = 0;
1608   u32 inside_vrf_id = 0;
1609   u32 static_mapping_buckets = 1024;
1610   u32 static_mapping_memory_size = 64<<20;
1611   u8 static_mapping_only = 0;
1612   u8 static_mapping_connection_tracking = 0;
1613   vlib_thread_main_t *tm = vlib_get_thread_main ();
1614
1615   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1616     {
1617       if (unformat (input, "translation hash buckets %d", &translation_buckets))
1618         ;
1619       else if (unformat (input, "translation hash memory %d",
1620                          &translation_memory_size));
1621       else if (unformat (input, "user hash buckets %d", &user_buckets))
1622         ;
1623       else if (unformat (input, "user hash memory %d",
1624                          &user_memory_size))
1625         ;
1626       else if (unformat (input, "max translations per user %d",
1627                          &max_translations_per_user))
1628         ;
1629       else if (unformat (input, "outside VRF id %d",
1630                          &outside_vrf_id))
1631         ;
1632       else if (unformat (input, "inside VRF id %d",
1633                          &inside_vrf_id))
1634         ;
1635       else if (unformat (input, "static mapping only"))
1636         {
1637           static_mapping_only = 1;
1638           if (unformat (input, "connection tracking"))
1639             static_mapping_connection_tracking = 1;
1640         }
1641       else 
1642         return clib_error_return (0, "unknown input '%U'",
1643                                   format_unformat_error, input);
1644     }
1645
1646   /* for show commands, etc. */
1647   sm->translation_buckets = translation_buckets;
1648   sm->translation_memory_size = translation_memory_size;
1649   sm->user_buckets = user_buckets;
1650   sm->user_memory_size = user_memory_size;
1651   sm->max_translations_per_user = max_translations_per_user;
1652   sm->outside_vrf_id = outside_vrf_id;
1653   sm->outside_fib_index = ~0;
1654   sm->inside_vrf_id = inside_vrf_id;
1655   sm->inside_fib_index = ~0;
1656   sm->static_mapping_only = static_mapping_only;
1657   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
1658
1659   if (!static_mapping_only ||
1660       (static_mapping_only && static_mapping_connection_tracking))
1661     {
1662       clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
1663                             user_memory_size);
1664
1665       clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
1666                             user_memory_size);
1667
1668       vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
1669
1670       clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
1671                             translation_memory_size);
1672
1673       clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
1674                             translation_memory_size);
1675
1676       clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
1677                             user_memory_size);
1678     }
1679   clib_bihash_init_8_8 (&sm->static_mapping_by_local,
1680                         "static_mapping_by_local", static_mapping_buckets,
1681                         static_mapping_memory_size);
1682
1683   clib_bihash_init_8_8 (&sm->static_mapping_by_external,
1684                         "static_mapping_by_external", static_mapping_buckets,
1685                         static_mapping_memory_size);
1686   return 0;
1687 }
1688
1689 VLIB_CONFIG_FUNCTION (snat_config, "snat");
1690
1691 u8 * format_snat_key (u8 * s, va_list * args)
1692 {
1693   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
1694   char * protocol_string = "unknown";
1695   static char *protocol_strings[] = {
1696       "UDP",
1697       "TCP",
1698       "ICMP",
1699   };
1700
1701   if (key->protocol < ARRAY_LEN(protocol_strings))
1702       protocol_string = protocol_strings[key->protocol];
1703
1704   s = format (s, "%U proto %s port %d fib %d",
1705               format_ip4_address, &key->addr, protocol_string,
1706               clib_net_to_host_u16 (key->port), key->fib_index);
1707   return s;
1708 }
1709
1710 u8 * format_snat_session (u8 * s, va_list * args)
1711 {
1712   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
1713   snat_session_t * sess = va_arg (*args, snat_session_t *);
1714
1715   s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
1716   s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
1717   s = format (s, "       last heard %.2f\n", sess->last_heard);
1718   s = format (s, "       total pkts %d, total bytes %lld\n",
1719               sess->total_pkts, sess->total_bytes);
1720   if (snat_is_session_static (sess))
1721     s = format (s, "       static translation\n");
1722   else
1723     s = format (s, "       dynamic translation\n");
1724
1725   return s;
1726 }
1727
1728 u8 * format_snat_user (u8 * s, va_list * args)
1729 {
1730   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
1731   snat_user_t * u = va_arg (*args, snat_user_t *);
1732   int verbose = va_arg (*args, int);
1733   dlist_elt_t * head, * elt;
1734   u32 elt_index, head_index;
1735   u32 session_index;
1736   snat_session_t * sess;
1737
1738   s = format (s, "%U: %d dynamic translations, %d static translations\n",
1739               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
1740
1741   if (verbose == 0)
1742     return s;
1743
1744   if (u->nsessions || u->nstaticsessions)
1745     {
1746       head_index = u->sessions_per_user_list_head_index;
1747       head = pool_elt_at_index (sm->list_pool, head_index);
1748
1749       elt_index = head->next;
1750       elt = pool_elt_at_index (sm->list_pool, elt_index);
1751       session_index = elt->value;
1752
1753       while (session_index != ~0)
1754         {
1755           sess = pool_elt_at_index (sm->sessions, session_index);
1756
1757           s = format (s, "  %U\n", format_snat_session, sm, sess);
1758
1759           elt_index = elt->next;
1760           elt = pool_elt_at_index (sm->list_pool, elt_index);
1761           session_index = elt->value;
1762         }
1763     }
1764
1765   return s;
1766 }
1767
1768 u8 * format_snat_static_mapping (u8 * s, va_list * args)
1769 {
1770   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
1771
1772   if (m->addr_only)
1773       s = format (s, "local %U external %U vrf %d",
1774                   format_ip4_address, &m->local_addr,
1775                   format_ip4_address, &m->external_addr,
1776                   m->vrf_id);
1777   else
1778       s = format (s, "local %U:%d external %U:%d vrf %d",
1779                   format_ip4_address, &m->local_addr, m->local_port,
1780                   format_ip4_address, &m->external_addr, m->external_port,
1781                   m->vrf_id);
1782
1783   return s;
1784 }
1785
1786 static clib_error_t *
1787 show_snat_command_fn (vlib_main_t * vm,
1788                  unformat_input_t * input,
1789                  vlib_cli_command_t * cmd)
1790 {
1791   int verbose = 0;
1792   snat_main_t * sm = &snat_main;
1793   snat_user_t * u;
1794   snat_static_mapping_t *m;
1795   snat_interface_t *i;
1796   vnet_main_t *vnm = vnet_get_main();
1797   snat_main_per_thread_data_t *tsm;
1798   u32 users_num = 0, sessions_num = 0, *worker;
1799   uword j = 0;
1800
1801   if (unformat (input, "detail"))
1802     verbose = 1;
1803   else if (unformat (input, "verbose"))
1804     verbose = 2;
1805
1806   if (sm->static_mapping_only)
1807     {
1808       if (sm->static_mapping_connection_tracking)
1809         vlib_cli_output (vm, "SNAT mode: static mapping only connection "
1810                          "tracking");
1811       else
1812         vlib_cli_output (vm, "SNAT mode: static mapping only");
1813     }
1814   else
1815     {
1816       vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
1817     }
1818
1819   if (verbose > 0)
1820     {
1821       pool_foreach (i, sm->interfaces,
1822       ({
1823         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
1824                          vnet_get_sw_interface (vnm, i->sw_if_index),
1825                          i->is_inside ? "in" : "out");
1826       }));
1827     }
1828
1829   if (sm->num_workers > 1)
1830     {
1831       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
1832       if (verbose > 0)
1833         {
1834           vec_foreach (worker, sm->workers)
1835             {
1836               vlib_worker_thread_t *w =
1837                 vlib_worker_threads + *worker + sm->first_worker_index;
1838               vlib_cli_output (vm, "  %s", w->name);
1839             }
1840         }
1841     }
1842
1843   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
1844     {
1845       vlib_cli_output (vm, "%d static mappings",
1846                        pool_elts (sm->static_mappings));
1847
1848       if (verbose > 0)
1849         {
1850           pool_foreach (m, sm->static_mappings,
1851           ({
1852             vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1853           }));
1854         }
1855     }
1856   else
1857     {
1858       vec_foreach (tsm, sm->per_thread_data)
1859         {
1860           users_num += pool_elts (tsm->users);
1861           sessions_num += pool_elts (tsm->sessions);
1862         }
1863
1864       vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
1865                        " %d static mappings",
1866                        users_num,
1867                        vec_len (sm->addresses),
1868                        sessions_num,
1869                        pool_elts (sm->static_mappings));
1870
1871       if (verbose > 0)
1872         {
1873           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
1874                            verbose - 1);
1875           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
1876                            verbose - 1);
1877           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
1878                            verbose - 1);
1879           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
1880                            verbose - 1);
1881           vec_foreach_index (j, sm->per_thread_data)
1882             {
1883               tsm = vec_elt_at_index (sm->per_thread_data, j);
1884
1885               if (pool_elts (tsm->users) == 0)
1886                 continue;
1887
1888               vlib_worker_thread_t *w = vlib_worker_threads + j;
1889               vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
1890                                w->lcore_id);
1891               vlib_cli_output (vm, "  %d list pool elements",
1892                                pool_elts (tsm->list_pool));
1893
1894               pool_foreach (u, tsm->users,
1895               ({
1896                 vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
1897                                  verbose - 1);
1898               }));
1899             }
1900
1901           if (pool_elts (sm->static_mappings))
1902             {
1903               vlib_cli_output (vm, "static mappings:");
1904               pool_foreach (m, sm->static_mappings,
1905               ({
1906                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
1907               }));
1908             }
1909         }
1910     }
1911
1912   return 0;
1913 }
1914
1915 VLIB_CLI_COMMAND (show_snat_command, static) = {
1916     .path = "show snat",
1917     .short_help = "show snat",
1918     .function = show_snat_command_fn,
1919 };