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