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