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