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