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