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