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