SNAT: initialize outside and inside FIB index in snat_config
[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->vrf_id = htonl (m->vrf_id);
1088   rmp->protocol = snat_proto_to_ip_proto (m->proto);
1089   rmp->context = context;
1090
1091   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1092 }
1093
1094 static void
1095 vl_api_snat_static_mapping_dump_t_handler
1096 (vl_api_snat_static_mapping_dump_t * mp)
1097 {
1098   unix_shared_memory_queue_t *q;
1099   snat_main_t * sm = &snat_main;
1100   snat_static_mapping_t * m;
1101
1102   q = vl_api_client_index_to_input_queue (mp->client_index);
1103   if (q == 0)
1104     return;
1105
1106   pool_foreach (m, sm->static_mappings,
1107   ({
1108       send_snat_static_mapping_details (m, q, mp->context);
1109   }));
1110 }
1111
1112 static void *vl_api_snat_static_mapping_dump_t_print
1113 (vl_api_snat_static_mapping_dump_t *mp, void * handle)
1114 {
1115   u8 *s;
1116
1117   s = format (0, "SCRIPT: snat_static_mapping_dump ");
1118
1119   FINISH;
1120 }
1121
1122 static void
1123 vl_api_snat_control_ping_t_handler
1124 (vl_api_snat_control_ping_t * mp)
1125 {
1126   vl_api_snat_control_ping_reply_t *rmp;
1127   snat_main_t * sm = &snat_main;
1128   int rv = 0;
1129
1130   REPLY_MACRO2(VL_API_SNAT_CONTROL_PING_REPLY,
1131   ({
1132     rmp->vpe_pid = ntohl (getpid());
1133   }));
1134 }
1135
1136 static void *vl_api_snat_control_ping_t_print
1137 (vl_api_snat_control_ping_t *mp, void * handle)
1138 {
1139   u8 *s;
1140
1141   s = format (0, "SCRIPT: snat_control_ping ");
1142
1143   FINISH;
1144 }
1145
1146 static void
1147 vl_api_snat_show_config_t_handler
1148 (vl_api_snat_show_config_t * mp)
1149 {
1150   vl_api_snat_show_config_reply_t *rmp;
1151   snat_main_t * sm = &snat_main;
1152   int rv = 0;
1153
1154   REPLY_MACRO2(VL_API_SNAT_SHOW_CONFIG_REPLY,
1155   ({
1156     rmp->translation_buckets = htonl (sm->translation_buckets);
1157     rmp->translation_memory_size = htonl (sm->translation_memory_size);
1158     rmp->user_buckets = htonl (sm->user_buckets);
1159     rmp->user_memory_size = htonl (sm->user_memory_size);
1160     rmp->max_translations_per_user = htonl (sm->max_translations_per_user);
1161     rmp->outside_vrf_id = htonl (sm->outside_vrf_id);
1162     rmp->inside_vrf_id = htonl (sm->inside_vrf_id);
1163     rmp->static_mapping_only = sm->static_mapping_only;
1164     rmp->static_mapping_connection_tracking =
1165       sm->static_mapping_connection_tracking;
1166   }));
1167 }
1168
1169 static void *vl_api_snat_show_config_t_print
1170 (vl_api_snat_show_config_t *mp, void * handle)
1171 {
1172   u8 *s;
1173
1174   s = format (0, "SCRIPT: snat_show_config ");
1175
1176   FINISH;
1177 }
1178
1179 static void 
1180 vl_api_snat_set_workers_t_handler
1181 (vl_api_snat_set_workers_t * mp)
1182 {
1183   snat_main_t * sm = &snat_main;
1184   vl_api_snat_set_workers_reply_t * rmp;
1185   int rv = 0;
1186   uword *bitmap = 0;
1187   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1188
1189   if (sm->num_workers < 2)
1190     {
1191       rv = VNET_API_ERROR_FEATURE_DISABLED;
1192       goto send_reply;
1193     }
1194
1195   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
1196   rv = snat_set_workers(bitmap);
1197   clib_bitmap_free (bitmap);
1198
1199  send_reply:
1200   REPLY_MACRO (VL_API_SNAT_SET_WORKERS_REPLY);
1201 }
1202
1203 static void *vl_api_snat_set_workers_t_print
1204 (vl_api_snat_set_workers_t *mp, void * handle)
1205 {
1206   u8 * s;
1207   uword *bitmap = 0;
1208   u8 first = 1;
1209   int i;
1210   u64 mask = clib_net_to_host_u64 (mp->worker_mask);
1211
1212   s = format (0, "SCRIPT: snat_set_workers ");
1213   bitmap = clib_bitmap_set_multiple (bitmap, 0, mask, BITS (mask)); 
1214   clib_bitmap_foreach (i, bitmap,
1215     ({
1216       if (first)
1217         s = format (s, "%d", i);
1218       else
1219         s = format (s, ",%d", i);
1220       first = 0;
1221     }));
1222   clib_bitmap_free (bitmap);
1223   FINISH;
1224 }
1225
1226 static void
1227 send_snat_worker_details
1228 (u32 worker_index, unix_shared_memory_queue_t * q, u32 context)
1229 {
1230   vl_api_snat_worker_details_t *rmp;
1231   snat_main_t * sm = &snat_main;
1232   vlib_worker_thread_t *w =
1233     vlib_worker_threads + worker_index + sm->first_worker_index;
1234
1235   rmp = vl_msg_api_alloc (sizeof (*rmp));
1236   memset (rmp, 0, sizeof (*rmp));
1237   rmp->_vl_msg_id = ntohs (VL_API_SNAT_WORKER_DETAILS+sm->msg_id_base);
1238   rmp->context = context;
1239   rmp->worker_index = htonl (worker_index);
1240   rmp->lcore_id = htonl (w->lcore_id);
1241   strncpy ((char *) rmp->name, (char *) w->name, ARRAY_LEN (rmp->name) - 1);
1242
1243   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1244 }
1245
1246 static void
1247 vl_api_snat_worker_dump_t_handler
1248 (vl_api_snat_worker_dump_t * mp)
1249 {
1250   unix_shared_memory_queue_t *q;
1251   snat_main_t * sm = &snat_main;
1252   u32 * worker_index;
1253
1254   q = vl_api_client_index_to_input_queue (mp->client_index);
1255   if (q == 0)
1256     return;
1257
1258   vec_foreach (worker_index, sm->workers)
1259     {
1260       send_snat_worker_details(*worker_index, q, mp->context);
1261     }
1262 }
1263
1264 static void *vl_api_snat_worker_dump_t_print
1265 (vl_api_snat_worker_dump_t *mp, void * handle)
1266 {
1267   u8 *s;
1268
1269   s = format (0, "SCRIPT: snat_worker_dump ");
1270
1271   FINISH;
1272 }
1273
1274 static int snat_add_interface_address(snat_main_t *sm,
1275                                       u32 sw_if_index,
1276                                       int is_del);
1277
1278 static void
1279 vl_api_snat_add_del_interface_addr_t_handler
1280 (vl_api_snat_add_del_interface_addr_t * mp)
1281 {
1282   snat_main_t * sm = &snat_main;
1283   vl_api_snat_add_del_interface_addr_reply_t * rmp;
1284   u8 is_del = mp->is_add == 0;
1285   u32 sw_if_index = ntohl(mp->sw_if_index);
1286   int rv = 0;
1287
1288   VALIDATE_SW_IF_INDEX(mp);
1289
1290   rv = snat_add_interface_address (sm, sw_if_index, is_del);
1291   
1292   BAD_SW_IF_INDEX_LABEL;
1293
1294   REPLY_MACRO(VL_API_SNAT_ADD_DEL_INTERFACE_ADDR_REPLY);
1295 }
1296
1297 static void *vl_api_snat_add_del_interface_addr_t_print
1298 (vl_api_snat_add_del_interface_addr_t * mp, void *handle)
1299 {
1300   u8 * s;
1301
1302   s = format (0, "SCRIPT: snat_add_del_interface_addr ");
1303   s = format (s, "sw_if_index %d %s",
1304               clib_host_to_net_u32(mp->sw_if_index),
1305               mp->is_add ? "" : "del");
1306
1307   FINISH;
1308 }
1309
1310 static void
1311 send_snat_interface_addr_details
1312 (u32 sw_if_index, unix_shared_memory_queue_t * q, u32 context)
1313 {
1314   vl_api_snat_interface_addr_details_t *rmp;
1315   snat_main_t * sm = &snat_main;
1316
1317   rmp = vl_msg_api_alloc (sizeof (*rmp));
1318   memset (rmp, 0, sizeof (*rmp));
1319   rmp->_vl_msg_id = ntohs (VL_API_SNAT_INTERFACE_ADDR_DETAILS+sm->msg_id_base);
1320   rmp->sw_if_index = ntohl (sw_if_index);
1321   rmp->context = context;
1322
1323   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1324 }
1325
1326 static void
1327 vl_api_snat_interface_addr_dump_t_handler
1328 (vl_api_snat_interface_addr_dump_t * mp)
1329 {
1330   unix_shared_memory_queue_t *q;
1331   snat_main_t * sm = &snat_main;
1332   u32 * i;
1333
1334   q = vl_api_client_index_to_input_queue (mp->client_index);
1335   if (q == 0)
1336     return;
1337
1338   vec_foreach (i, sm->auto_add_sw_if_indices)
1339     send_snat_interface_addr_details(*i, q, mp->context);
1340 }
1341
1342 static void *vl_api_snat_interface_addr_dump_t_print
1343 (vl_api_snat_interface_addr_dump_t *mp, void * handle)
1344 {
1345   u8 *s;
1346
1347   s = format (0, "SCRIPT: snat_interface_addr_dump ");
1348
1349   FINISH;
1350 }
1351
1352 static void
1353 vl_api_snat_ipfix_enable_disable_t_handler
1354 (vl_api_snat_ipfix_enable_disable_t * mp)
1355 {
1356   snat_main_t * sm = &snat_main;
1357   vl_api_snat_ipfix_enable_disable_reply_t * rmp;
1358   int rv = 0;
1359
1360   rv = snat_ipfix_logging_enable_disable(mp->enable,
1361                                          clib_host_to_net_u32 (mp->domain_id),
1362                                          clib_host_to_net_u16 (mp->src_port));
1363
1364   REPLY_MACRO (VL_API_SNAT_IPFIX_ENABLE_DISABLE_REPLY);
1365 }
1366
1367 static void *vl_api_snat_ipfix_enable_disable_t_print
1368 (vl_api_snat_ipfix_enable_disable_t *mp, void * handle)
1369 {
1370   u8 * s;
1371
1372   s = format (0, "SCRIPT: snat_ipfix_enable_disable ");
1373   if (mp->domain_id)
1374     s = format (s, "domain %d ", clib_net_to_host_u32 (mp->domain_id));
1375   if (mp->src_port)
1376     s = format (s, "src_port %d ", clib_net_to_host_u16 (mp->src_port));
1377   if (!mp->enable)
1378     s = format (s, "disable ");
1379
1380   FINISH;
1381 }
1382
1383 /* List of message types that this plugin understands */
1384 #define foreach_snat_plugin_api_msg                                     \
1385 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range)                       \
1386 _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature)       \
1387 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping)                     \
1388 _(SNAT_CONTROL_PING, snat_control_ping)                                 \
1389 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump)                   \
1390 _(SNAT_SHOW_CONFIG, snat_show_config)                                   \
1391 _(SNAT_ADDRESS_DUMP, snat_address_dump)                                 \
1392 _(SNAT_INTERFACE_DUMP, snat_interface_dump)                             \
1393 _(SNAT_SET_WORKERS, snat_set_workers)                                   \
1394 _(SNAT_WORKER_DUMP, snat_worker_dump)                                   \
1395 _(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr)             \
1396 _(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump)                   \
1397 _(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable)
1398
1399 /* Set up the API message handling tables */
1400 static clib_error_t *
1401 snat_plugin_api_hookup (vlib_main_t *vm)
1402 {
1403    snat_main_t * sm __attribute__ ((unused)) = &snat_main;
1404 #define _(N,n)                                                  \
1405     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
1406                            #n,                                  \
1407                            vl_api_##n##_t_handler,              \
1408                            vl_noop_handler,                     \
1409                            vl_api_##n##_t_endian,               \
1410                            vl_api_##n##_t_print,                \
1411                            sizeof(vl_api_##n##_t), 1); 
1412     foreach_snat_plugin_api_msg;
1413 #undef _
1414
1415     return 0;
1416 }
1417
1418 #define vl_msg_name_crc_list
1419 #include <snat/snat_all_api_h.h>
1420 #undef vl_msg_name_crc_list
1421
1422 static void
1423 setup_message_id_table (snat_main_t * sm, api_main_t * am)
1424 {
1425 #define _(id,n,crc) \
1426   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1427   foreach_vl_msg_name_crc_snat;
1428 #undef _
1429 }
1430
1431 static void plugin_custom_dump_configure (snat_main_t * sm) 
1432 {
1433 #define _(n,f) sm->api_main->msg_print_handlers \
1434   [VL_API_##n + sm->msg_id_base]                \
1435     = (void *) vl_api_##f##_t_print;
1436   foreach_snat_plugin_api_msg;
1437 #undef _
1438 }
1439
1440
1441 static void
1442 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1443                                        uword opaque,
1444                                        u32 sw_if_index,
1445                                        ip4_address_t * address,
1446                                        u32 address_length,
1447                                        u32 if_address_index,
1448                                        u32 is_delete);
1449
1450 static clib_error_t * snat_init (vlib_main_t * vm)
1451 {
1452   snat_main_t * sm = &snat_main;
1453   clib_error_t * error = 0;
1454   ip4_main_t * im = &ip4_main;
1455   ip_lookup_main_t * lm = &im->lookup_main;
1456   u8 * name;
1457   uword *p;
1458   vlib_thread_registration_t *tr;
1459   vlib_thread_main_t *tm = vlib_get_thread_main ();
1460   uword *bitmap = 0;
1461   u32 i;
1462   ip4_add_del_interface_address_callback_t cb4;
1463
1464   name = format (0, "snat_%08x%c", api_version, 0);
1465
1466   /* Ask for a correctly-sized block of API message decode slots */
1467   sm->msg_id_base = vl_msg_api_get_msg_ids 
1468       ((char *) name, VL_MSG_FIRST_AVAILABLE);
1469
1470   sm->vlib_main = vm;
1471   sm->vnet_main = vnet_get_main();
1472   sm->ip4_main = im;
1473   sm->ip4_lookup_main = lm;
1474   sm->api_main = &api_main;
1475   sm->first_worker_index = 0;
1476   sm->next_worker = 0;
1477   sm->num_workers = 0;
1478   sm->workers = 0;
1479   sm->fq_in2out_index = ~0;
1480   sm->fq_out2in_index = ~0;
1481
1482   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1483   if (p)
1484     {
1485       tr = (vlib_thread_registration_t *) p[0];
1486       if (tr)
1487         {
1488           sm->num_workers = tr->count;
1489           sm->first_worker_index = tr->first_index;
1490         }
1491     }
1492
1493   /* Use all available workers by default */
1494   if (sm->num_workers > 1)
1495     {
1496       for (i=0; i < sm->num_workers; i++)
1497         bitmap = clib_bitmap_set (bitmap, i, 1);
1498       snat_set_workers(bitmap);
1499       clib_bitmap_free (bitmap);
1500     }
1501
1502   error = snat_plugin_api_hookup (vm);
1503
1504   /* Add our API messages to the global name_crc hash table */
1505   setup_message_id_table (sm, &api_main);
1506
1507   plugin_custom_dump_configure (sm);
1508   vec_free(name);
1509
1510   /* Set up the interface address add/del callback */
1511   cb4.function = snat_ip4_add_del_interface_address_cb;
1512   cb4.function_opaque = 0;
1513
1514   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1515
1516   /* Init IPFIX logging */
1517   snat_ipfix_logging_init(vm);
1518
1519   return error;
1520 }
1521
1522 VLIB_INIT_FUNCTION (snat_init);
1523
1524 void snat_free_outside_address_and_port (snat_main_t * sm, 
1525                                          snat_session_key_t * k, 
1526                                          u32 address_index)
1527 {
1528   snat_address_t *a;
1529   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1530   
1531   ASSERT (address_index < vec_len (sm->addresses));
1532
1533   a = sm->addresses + address_index;
1534
1535   switch (k->protocol)
1536     {
1537 #define _(N, i, n, s) \
1538     case SNAT_PROTOCOL_##N: \
1539       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1540         port_host_byte_order) == 1); \
1541       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1542         port_host_byte_order, 0); \
1543       a->busy_##n##_ports--; \
1544       break;
1545       foreach_snat_protocol
1546 #undef _
1547     default:
1548       clib_warning("unknown_protocol");
1549       return;
1550     }
1551 }  
1552
1553 /**
1554  * @brief Match SNAT static mapping.
1555  *
1556  * @param sm          SNAT main.
1557  * @param match       Address and port to match.
1558  * @param mapping     External or local address and port of the matched mapping.
1559  * @param by_external If 0 match by local address otherwise match by external
1560  *                    address.
1561  *
1562  * @returns 0 if match found otherwise 1.
1563  */
1564 int snat_static_mapping_match (snat_main_t * sm,
1565                                snat_session_key_t match,
1566                                snat_session_key_t * mapping,
1567                                u8 by_external)
1568 {
1569   clib_bihash_kv_8_8_t kv, value;
1570   snat_static_mapping_t *m;
1571   snat_session_key_t m_key;
1572   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1573
1574   if (by_external)
1575     mapping_hash = &sm->static_mapping_by_external;
1576
1577   m_key.addr = match.addr;
1578   m_key.port = clib_net_to_host_u16 (match.port);
1579   m_key.protocol = match.protocol;
1580   m_key.fib_index = match.fib_index;
1581
1582   kv.key = m_key.as_u64;
1583
1584   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1585     {
1586       /* Try address only mapping */
1587       m_key.port = 0;
1588       m_key.protocol = 0;
1589       kv.key = m_key.as_u64;
1590       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1591         return 1;
1592     }
1593
1594   m = pool_elt_at_index (sm->static_mappings, value.value);
1595
1596   if (by_external)
1597     {
1598       mapping->addr = m->local_addr;
1599       /* Address only mapping doesn't change port */
1600       mapping->port = m->addr_only ? match.port
1601         : clib_host_to_net_u16 (m->local_port);
1602       mapping->fib_index = m->fib_index;
1603     }
1604   else
1605     {
1606       mapping->addr = m->external_addr;
1607       /* Address only mapping doesn't change port */
1608       mapping->port = m->addr_only ? match.port
1609         : clib_host_to_net_u16 (m->external_port);
1610       mapping->fib_index = sm->outside_fib_index;
1611     }
1612
1613   return 0;
1614 }
1615
1616 int snat_alloc_outside_address_and_port (snat_main_t * sm, 
1617                                          snat_session_key_t * k,
1618                                          u32 * address_indexp)
1619 {
1620   int i;
1621   snat_address_t *a;
1622   u32 portnum;
1623
1624   for (i = 0; i < vec_len (sm->addresses); i++)
1625     {
1626       a = sm->addresses + i;
1627       switch (k->protocol)
1628         {
1629 #define _(N, j, n, s) \
1630         case SNAT_PROTOCOL_##N: \
1631           if (a->busy_##n##_ports < (65535-1024)) \
1632             { \
1633               while (1) \
1634                 { \
1635                   portnum = random_u32 (&sm->random_seed); \
1636                   portnum &= 0xFFFF; \
1637                   if (portnum < 1024) \
1638                     continue; \
1639                   if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1640                     continue; \
1641                   clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1642                   a->busy_##n##_ports++; \
1643                   k->addr = a->addr; \
1644                   k->port = clib_host_to_net_u16(portnum); \
1645                   *address_indexp = i; \
1646                   return 0; \
1647                 } \
1648             } \
1649           break;
1650           foreach_snat_protocol
1651 #undef _
1652         default:
1653           clib_warning("unknown protocol");
1654           return 1;
1655         }
1656
1657     }
1658   /* Totally out of translations to use... */
1659   snat_ipfix_logging_addresses_exhausted(0);
1660   return 1;
1661 }
1662
1663
1664 static clib_error_t *
1665 add_address_command_fn (vlib_main_t * vm,
1666                         unformat_input_t * input,
1667                         vlib_cli_command_t * cmd)
1668 {
1669   unformat_input_t _line_input, *line_input = &_line_input;
1670   snat_main_t * sm = &snat_main;
1671   ip4_address_t start_addr, end_addr, this_addr;
1672   u32 start_host_order, end_host_order;
1673   int i, count;
1674   int is_add = 1;
1675   int rv = 0;
1676
1677   /* Get a line of input. */
1678   if (!unformat_user (input, unformat_line_input, line_input))
1679     return 0;
1680
1681   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1682     {
1683       if (unformat (line_input, "%U - %U",
1684                     unformat_ip4_address, &start_addr,
1685                     unformat_ip4_address, &end_addr))
1686         ;
1687       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1688         end_addr = start_addr;
1689       else if (unformat (line_input, "del"))
1690         is_add = 0;
1691       else
1692         return clib_error_return (0, "unknown input '%U'",
1693           format_unformat_error, input);
1694      }
1695   unformat_free (line_input);
1696
1697   if (sm->static_mapping_only)
1698     return clib_error_return (0, "static mapping only mode");
1699
1700   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1701   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1702   
1703   if (end_host_order < start_host_order)
1704     return clib_error_return (0, "end address less than start address");
1705
1706   count = (end_host_order - start_host_order) + 1;
1707
1708   if (count > 1024)
1709     clib_warning ("%U - %U, %d addresses...",
1710                   format_ip4_address, &start_addr,
1711                   format_ip4_address, &end_addr,
1712                   count);
1713   
1714   this_addr = start_addr;
1715
1716   for (i = 0; i < count; i++)
1717     {
1718       if (is_add)
1719         snat_add_address (sm, &this_addr);
1720       else
1721         rv = snat_del_address (sm, this_addr, 0);
1722
1723       switch (rv)
1724         {
1725         case VNET_API_ERROR_NO_SUCH_ENTRY:
1726           return clib_error_return (0, "S-NAT address not exist.");
1727           break;
1728         case VNET_API_ERROR_UNSPECIFIED:
1729           return clib_error_return (0, "S-NAT address used in static mapping.");
1730           break;
1731         default:
1732           break;
1733         }
1734
1735       increment_v4_address (&this_addr);
1736     }
1737
1738   return 0;
1739 }
1740
1741 VLIB_CLI_COMMAND (add_address_command, static) = {
1742   .path = "snat add address",
1743   .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
1744   .function = add_address_command_fn,
1745 };
1746
1747 static clib_error_t *
1748 snat_feature_command_fn (vlib_main_t * vm,
1749                           unformat_input_t * input,
1750                           vlib_cli_command_t * cmd)
1751 {
1752   unformat_input_t _line_input, *line_input = &_line_input;
1753   vnet_main_t * vnm = vnet_get_main();
1754   clib_error_t * error = 0;
1755   u32 sw_if_index;
1756   u32 * inside_sw_if_indices = 0;
1757   u32 * outside_sw_if_indices = 0;
1758   int is_del = 0;
1759   int i;
1760
1761   sw_if_index = ~0;
1762
1763   /* Get a line of input. */
1764   if (!unformat_user (input, unformat_line_input, line_input))
1765     return 0;
1766
1767   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1768     {
1769       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1770                     vnm, &sw_if_index))
1771         vec_add1 (inside_sw_if_indices, sw_if_index);
1772       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1773                          vnm, &sw_if_index))
1774         vec_add1 (outside_sw_if_indices, sw_if_index);
1775       else if (unformat (line_input, "del"))
1776         is_del = 1;
1777       else
1778         return clib_error_return (0, "unknown input '%U'",
1779           format_unformat_error, input);
1780     }
1781   unformat_free (line_input);
1782
1783   if (vec_len (inside_sw_if_indices))
1784     {
1785       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1786         {
1787           sw_if_index = inside_sw_if_indices[i];
1788           snat_interface_add_del (sw_if_index, 1, is_del);
1789         }
1790     }
1791
1792   if (vec_len (outside_sw_if_indices))
1793     {
1794       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1795         {
1796           sw_if_index = outside_sw_if_indices[i];
1797           snat_interface_add_del (sw_if_index, 0, is_del);
1798         }
1799     }
1800
1801   vec_free (inside_sw_if_indices);
1802   vec_free (outside_sw_if_indices);
1803
1804   return error;
1805 }
1806
1807 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1808   .path = "set interface snat",
1809   .function = snat_feature_command_fn,
1810   .short_help = "set interface snat in <intfc> out <intfc> [del]",
1811 };
1812
1813 uword
1814 unformat_snat_protocol (unformat_input_t * input, va_list * args)
1815 {
1816   u32 *r = va_arg (*args, u32 *);
1817
1818   if (0);
1819 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
1820   foreach_snat_protocol
1821 #undef _
1822   else
1823     return 0;
1824   return 1;
1825 }
1826
1827 u8 *
1828 format_snat_protocol (u8 * s, va_list * args)
1829 {
1830   u32 i = va_arg (*args, u32);
1831   u8 *t = 0;
1832
1833   switch (i)
1834     {
1835 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
1836       foreach_snat_protocol
1837 #undef _
1838     default:
1839       s = format (s, "unknown");
1840     }
1841   s = format (s, "%s", t);
1842   return s;
1843 }
1844
1845 static clib_error_t *
1846 add_static_mapping_command_fn (vlib_main_t * vm,
1847                                unformat_input_t * input,
1848                                vlib_cli_command_t * cmd)
1849 {
1850   unformat_input_t _line_input, *line_input = &_line_input;
1851   clib_error_t * error = 0;
1852   ip4_address_t l_addr, e_addr;
1853   u32 l_port = 0, e_port = 0, vrf_id = ~0;
1854   int is_add = 1;
1855   int addr_only = 1;
1856   u32 sw_if_index = ~0;
1857   vnet_main_t * vnm = vnet_get_main();
1858   int rv;
1859   snat_protocol_t proto;
1860
1861   /* Get a line of input. */
1862   if (!unformat_user (input, unformat_line_input, line_input))
1863     return 0;
1864
1865   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1866     {
1867       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
1868                     &l_port))
1869         addr_only = 0;
1870       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
1871         ;
1872       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
1873                          &e_addr, &e_port))
1874         addr_only = 0;
1875       else if (unformat (line_input, "external %U", unformat_ip4_address,
1876                          &e_addr))
1877         ;
1878       else if (unformat (line_input, "external %U %u",
1879                          unformat_vnet_sw_interface, vnm, &sw_if_index,
1880                          &e_port))
1881         addr_only = 0;
1882
1883       else if (unformat (line_input, "external %U",
1884                          unformat_vnet_sw_interface, vnm, &sw_if_index))
1885         ;
1886       else if (unformat (line_input, "vrf %u", &vrf_id))
1887         ;
1888       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1889         ;
1890       else if (unformat (line_input, "del"))
1891         is_add = 0;
1892       else
1893         return clib_error_return (0, "unknown input: '%U'",
1894           format_unformat_error, line_input);
1895     }
1896   unformat_free (line_input);
1897
1898   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
1899                                vrf_id, addr_only, sw_if_index, proto, is_add);
1900
1901   switch (rv)
1902     {
1903     case VNET_API_ERROR_INVALID_VALUE:
1904       return clib_error_return (0, "External port already in use.");
1905       break;
1906     case VNET_API_ERROR_NO_SUCH_ENTRY:
1907       if (is_add)
1908         return clib_error_return (0, "External addres must be allocated.");
1909       else
1910         return clib_error_return (0, "Mapping not exist.");
1911       break;
1912     case VNET_API_ERROR_NO_SUCH_FIB:
1913       return clib_error_return (0, "No such VRF id.");
1914     case VNET_API_ERROR_VALUE_EXIST:
1915       return clib_error_return (0, "Mapping already exist.");
1916     default:
1917       break;
1918     }
1919
1920   return error;
1921 }
1922
1923 /*?
1924  * @cliexpar
1925  * @cliexstart{snat add static mapping}
1926  * Static mapping allows hosts on the external network to initiate connection
1927  * to to the local network host.
1928  * To create static mapping between local host address 10.0.0.3 port 6303 and
1929  * external address 4.4.4.4 port 3606 use:
1930  *  vpp# snat add static mapping local 10.0.0.3 6303 external 4.4.4.4 3606
1931  * If not runnig "static mapping only" S-NAT plugin mode use before:
1932  *  vpp# snat add address 4.4.4.4
1933  * To create static mapping between local and external address use:
1934  *  vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
1935  * @cliexend
1936 ?*/
1937 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1938   .path = "snat add static mapping",
1939   .function = add_static_mapping_command_fn,
1940   .short_help =
1941     "snat add static mapping local <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
1942 };
1943
1944 static clib_error_t *
1945 set_workers_command_fn (vlib_main_t * vm,
1946                         unformat_input_t * input,
1947                         vlib_cli_command_t * cmd)
1948 {
1949   unformat_input_t _line_input, *line_input = &_line_input;
1950   uword *bitmap = 0;
1951   int rv = 0;
1952
1953   /* Get a line of input. */
1954   if (!unformat_user (input, unformat_line_input, line_input))
1955     return 0;
1956
1957   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1958     {
1959       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
1960         ;
1961       else
1962         return clib_error_return (0, "unknown input '%U'",
1963           format_unformat_error, input);
1964      }
1965   unformat_free (line_input);
1966
1967   if (bitmap == 0)
1968     return clib_error_return (0, "List of workers must be specified.");
1969
1970   rv = snat_set_workers(bitmap);
1971
1972   clib_bitmap_free (bitmap);
1973
1974   switch (rv)
1975     {
1976     case VNET_API_ERROR_INVALID_WORKER:
1977       return clib_error_return (0, "Invalid worker(s).");
1978       break;
1979     case VNET_API_ERROR_FEATURE_DISABLED:
1980       return clib_error_return (0,
1981         "Supported only if 2 or more workes available.");
1982       break;
1983     default:
1984       break;
1985     }
1986
1987   return 0;
1988 }
1989
1990 /*?
1991  * @cliexpar
1992  * @cliexstart{set snat workers}
1993  * Set SNAT workers if 2 or more workers available, use:
1994  *  vpp# set snat workers 0-2,5
1995  * @cliexend
1996 ?*/
1997 VLIB_CLI_COMMAND (set_workers_command, static) = {
1998   .path = "set snat workers",
1999   .function = set_workers_command_fn,
2000   .short_help =
2001     "set snat workers <workers-list>",
2002 };
2003
2004 static clib_error_t *
2005 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2006                                               unformat_input_t * input,
2007                                               vlib_cli_command_t * cmd)
2008 {
2009   unformat_input_t _line_input, *line_input = &_line_input;
2010   u32 domain_id = 0;
2011   u32 src_port = 0;
2012   u8 enable = 1;
2013   int rv = 0;
2014
2015   /* Get a line of input. */
2016   if (!unformat_user (input, unformat_line_input, line_input))
2017     return 0;
2018
2019   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2020     {
2021       if (unformat (line_input, "domain %d", &domain_id))
2022         ;
2023       else if (unformat (line_input, "src-port %d", &src_port))
2024         ;
2025       else if (unformat (line_input, "disable"))
2026         enable = 0;
2027       else
2028         return clib_error_return (0, "unknown input '%U'",
2029           format_unformat_error, input);
2030      }
2031   unformat_free (line_input);
2032
2033   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2034
2035   if (rv)
2036     return clib_error_return (0, "ipfix logging enable failed");
2037
2038   return 0;
2039 }
2040
2041 /*?
2042  * @cliexpar
2043  * @cliexstart{snat ipfix logging}
2044  * To enable SNAT IPFIX logging use:
2045  *  vpp# snat ipfix logging
2046  * To set IPFIX exporter use:
2047  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2048  * @cliexend
2049 ?*/
2050 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2051   .path = "snat ipfix logging",
2052   .function = snat_ipfix_logging_enable_disable_command_fn,
2053   .short_help = "snat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2054 };
2055
2056 static clib_error_t *
2057 snat_config (vlib_main_t * vm, unformat_input_t * input)
2058 {
2059   snat_main_t * sm = &snat_main;
2060   u32 translation_buckets = 1024;
2061   u32 translation_memory_size = 128<<20;
2062   u32 user_buckets = 128;
2063   u32 user_memory_size = 64<<20;
2064   u32 max_translations_per_user = 100;
2065   u32 outside_vrf_id = 0;
2066   u32 inside_vrf_id = 0;
2067   u32 static_mapping_buckets = 1024;
2068   u32 static_mapping_memory_size = 64<<20;
2069   u8 static_mapping_only = 0;
2070   u8 static_mapping_connection_tracking = 0;
2071   vlib_thread_main_t *tm = vlib_get_thread_main ();
2072
2073   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2074     {
2075       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2076         ;
2077       else if (unformat (input, "translation hash memory %d",
2078                          &translation_memory_size));
2079       else if (unformat (input, "user hash buckets %d", &user_buckets))
2080         ;
2081       else if (unformat (input, "user hash memory %d",
2082                          &user_memory_size))
2083         ;
2084       else if (unformat (input, "max translations per user %d",
2085                          &max_translations_per_user))
2086         ;
2087       else if (unformat (input, "outside VRF id %d",
2088                          &outside_vrf_id))
2089         ;
2090       else if (unformat (input, "inside VRF id %d",
2091                          &inside_vrf_id))
2092         ;
2093       else if (unformat (input, "static mapping only"))
2094         {
2095           static_mapping_only = 1;
2096           if (unformat (input, "connection tracking"))
2097             static_mapping_connection_tracking = 1;
2098         }
2099       else 
2100         return clib_error_return (0, "unknown input '%U'",
2101                                   format_unformat_error, input);
2102     }
2103
2104   /* for show commands, etc. */
2105   sm->translation_buckets = translation_buckets;
2106   sm->translation_memory_size = translation_memory_size;
2107   sm->user_buckets = user_buckets;
2108   sm->user_memory_size = user_memory_size;
2109   sm->max_translations_per_user = max_translations_per_user;
2110   sm->outside_vrf_id = outside_vrf_id;
2111   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2112                                                              outside_vrf_id);
2113   sm->inside_vrf_id = inside_vrf_id;
2114   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2115                                                             inside_vrf_id);
2116   sm->static_mapping_only = static_mapping_only;
2117   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2118
2119   if (!static_mapping_only ||
2120       (static_mapping_only && static_mapping_connection_tracking))
2121     {
2122       clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
2123                             user_memory_size);
2124
2125       clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
2126                             user_memory_size);
2127
2128       vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2129
2130       clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
2131                             translation_memory_size);
2132
2133       clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
2134                             translation_memory_size);
2135
2136       clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
2137                             user_memory_size);
2138     }
2139   clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2140                         "static_mapping_by_local", static_mapping_buckets,
2141                         static_mapping_memory_size);
2142
2143   clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2144                         "static_mapping_by_external", static_mapping_buckets,
2145                         static_mapping_memory_size);
2146   return 0;
2147 }
2148
2149 VLIB_CONFIG_FUNCTION (snat_config, "snat");
2150
2151 u8 * format_snat_key (u8 * s, va_list * args)
2152 {
2153   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2154   char * protocol_string = "unknown";
2155   static char *protocol_strings[] = {
2156       "UDP",
2157       "TCP",
2158       "ICMP",
2159   };
2160
2161   if (key->protocol < ARRAY_LEN(protocol_strings))
2162       protocol_string = protocol_strings[key->protocol];
2163
2164   s = format (s, "%U proto %s port %d fib %d",
2165               format_ip4_address, &key->addr, protocol_string,
2166               clib_net_to_host_u16 (key->port), key->fib_index);
2167   return s;
2168 }
2169
2170 u8 * format_snat_session (u8 * s, va_list * args)
2171 {
2172   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2173   snat_session_t * sess = va_arg (*args, snat_session_t *);
2174
2175   s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2176   s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2177   s = format (s, "       last heard %.2f\n", sess->last_heard);
2178   s = format (s, "       total pkts %d, total bytes %lld\n",
2179               sess->total_pkts, sess->total_bytes);
2180   if (snat_is_session_static (sess))
2181     s = format (s, "       static translation\n");
2182   else
2183     s = format (s, "       dynamic translation\n");
2184
2185   return s;
2186 }
2187
2188 u8 * format_snat_user (u8 * s, va_list * args)
2189 {
2190   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2191   snat_user_t * u = va_arg (*args, snat_user_t *);
2192   int verbose = va_arg (*args, int);
2193   dlist_elt_t * head, * elt;
2194   u32 elt_index, head_index;
2195   u32 session_index;
2196   snat_session_t * sess;
2197
2198   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2199               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2200
2201   if (verbose == 0)
2202     return s;
2203
2204   if (u->nsessions || u->nstaticsessions)
2205     {
2206       head_index = u->sessions_per_user_list_head_index;
2207       head = pool_elt_at_index (sm->list_pool, head_index);
2208
2209       elt_index = head->next;
2210       elt = pool_elt_at_index (sm->list_pool, elt_index);
2211       session_index = elt->value;
2212
2213       while (session_index != ~0)
2214         {
2215           sess = pool_elt_at_index (sm->sessions, session_index);
2216
2217           s = format (s, "  %U\n", format_snat_session, sm, sess);
2218
2219           elt_index = elt->next;
2220           elt = pool_elt_at_index (sm->list_pool, elt_index);
2221           session_index = elt->value;
2222         }
2223     }
2224
2225   return s;
2226 }
2227
2228 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2229 {
2230   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2231
2232   if (m->addr_only)
2233       s = format (s, "local %U external %U vrf %d",
2234                   format_ip4_address, &m->local_addr,
2235                   format_ip4_address, &m->external_addr,
2236                   m->vrf_id);
2237   else
2238       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2239                   format_snat_protocol, m->proto,
2240                   format_ip4_address, &m->local_addr, m->local_port,
2241                   format_ip4_address, &m->external_addr, m->external_port,
2242                   m->vrf_id);
2243
2244   return s;
2245 }
2246
2247 static clib_error_t *
2248 show_snat_command_fn (vlib_main_t * vm,
2249                  unformat_input_t * input,
2250                  vlib_cli_command_t * cmd)
2251 {
2252   int verbose = 0;
2253   snat_main_t * sm = &snat_main;
2254   snat_user_t * u;
2255   snat_static_mapping_t *m;
2256   snat_interface_t *i;
2257   snat_address_t * ap;
2258   vnet_main_t *vnm = vnet_get_main();
2259   snat_main_per_thread_data_t *tsm;
2260   u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2261   uword j = 0;
2262
2263   if (unformat (input, "detail"))
2264     verbose = 1;
2265   else if (unformat (input, "verbose"))
2266     verbose = 2;
2267
2268   if (sm->static_mapping_only)
2269     {
2270       if (sm->static_mapping_connection_tracking)
2271         vlib_cli_output (vm, "SNAT mode: static mapping only connection "
2272                          "tracking");
2273       else
2274         vlib_cli_output (vm, "SNAT mode: static mapping only");
2275     }
2276   else
2277     {
2278       vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
2279     }
2280
2281   if (verbose > 0)
2282     {
2283       pool_foreach (i, sm->interfaces,
2284       ({
2285         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2286                          vnet_get_sw_interface (vnm, i->sw_if_index),
2287                          i->is_inside ? "in" : "out");
2288       }));
2289
2290       if (vec_len (sm->auto_add_sw_if_indices))
2291         {
2292           vlib_cli_output (vm, "SNAT pool addresses interfaces:");
2293           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2294             {
2295               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2296                                vnet_get_sw_interface (vnm, *sw_if_index));
2297             }
2298         }
2299
2300       vec_foreach (ap, sm->addresses)
2301         {
2302           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2303 #define _(N, i, n, s) \
2304           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
2305           foreach_snat_protocol
2306 #undef _
2307         }
2308     }
2309
2310   if (sm->num_workers > 1)
2311     {
2312       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2313       if (verbose > 0)
2314         {
2315           vec_foreach (worker, sm->workers)
2316             {
2317               vlib_worker_thread_t *w =
2318                 vlib_worker_threads + *worker + sm->first_worker_index;
2319               vlib_cli_output (vm, "  %s", w->name);
2320             }
2321         }
2322     }
2323
2324   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2325     {
2326       vlib_cli_output (vm, "%d static mappings",
2327                        pool_elts (sm->static_mappings));
2328
2329       if (verbose > 0)
2330         {
2331           pool_foreach (m, sm->static_mappings,
2332           ({
2333             vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2334           }));
2335         }
2336     }
2337   else
2338     {
2339       vec_foreach (tsm, sm->per_thread_data)
2340         {
2341           users_num += pool_elts (tsm->users);
2342           sessions_num += pool_elts (tsm->sessions);
2343         }
2344
2345       vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2346                        " %d static mappings",
2347                        users_num,
2348                        vec_len (sm->addresses),
2349                        sessions_num,
2350                        pool_elts (sm->static_mappings));
2351
2352       if (verbose > 0)
2353         {
2354           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
2355                            verbose - 1);
2356           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
2357                            verbose - 1);
2358           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
2359                            verbose - 1);
2360           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
2361                            verbose - 1);
2362           vec_foreach_index (j, sm->per_thread_data)
2363             {
2364               tsm = vec_elt_at_index (sm->per_thread_data, j);
2365
2366               if (pool_elts (tsm->users) == 0)
2367                 continue;
2368
2369               vlib_worker_thread_t *w = vlib_worker_threads + j;
2370               vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2371                                w->lcore_id);
2372               vlib_cli_output (vm, "  %d list pool elements",
2373                                pool_elts (tsm->list_pool));
2374
2375               pool_foreach (u, tsm->users,
2376               ({
2377                 vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
2378                                  verbose - 1);
2379               }));
2380             }
2381
2382           if (pool_elts (sm->static_mappings))
2383             {
2384               vlib_cli_output (vm, "static mappings:");
2385               pool_foreach (m, sm->static_mappings,
2386               ({
2387                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2388               }));
2389             }
2390         }
2391     }
2392
2393   return 0;
2394 }
2395
2396 VLIB_CLI_COMMAND (show_snat_command, static) = {
2397     .path = "show snat",
2398     .short_help = "show snat",
2399     .function = show_snat_command_fn,
2400 };
2401
2402
2403 static void
2404 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2405                                        uword opaque,
2406                                        u32 sw_if_index,
2407                                        ip4_address_t * address,
2408                                        u32 address_length,
2409                                        u32 if_address_index,
2410                                        u32 is_delete)
2411 {
2412   snat_main_t *sm = &snat_main;
2413   snat_static_map_resolve_t *rp;
2414   u32 *indices_to_delete = 0;
2415   int i, j;
2416   int rv;
2417
2418   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2419     {
2420       if (sw_if_index == sm->auto_add_sw_if_indices[i])
2421         {
2422           if (!is_delete)
2423             {
2424               /* Don't trip over lease renewal, static config */
2425               for (j = 0; j < vec_len(sm->addresses); j++)
2426                 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2427                   return;
2428
2429               snat_add_address (sm, address);
2430               /* Scan static map resolution vector */
2431               for (j = 0; j < vec_len (sm->to_resolve); j++)
2432                 {
2433                   rp = sm->to_resolve + j;
2434                   /* On this interface? */
2435                   if (rp->sw_if_index == sw_if_index)
2436                     {
2437                       /* Add the static mapping */
2438                       rv = snat_add_static_mapping (rp->l_addr,
2439                                                     address[0],
2440                                                     rp->l_port,
2441                                                     rp->e_port,
2442                                                     rp->vrf_id,
2443                                                     rp->addr_only,
2444                                                     ~0 /* sw_if_index */,
2445                                                     rp->proto,
2446                                                     rp->is_add);
2447                       if (rv)
2448                         clib_warning ("snat_add_static_mapping returned %d", 
2449                                       rv);
2450                       vec_add1 (indices_to_delete, j);
2451                     }
2452                 }
2453               /* If we resolved any of the outstanding static mappings */
2454               if (vec_len(indices_to_delete))
2455                 {
2456                   /* Delete them */
2457                   for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2458                     vec_delete(sm->to_resolve, 1, j);
2459                   vec_free(indices_to_delete);
2460                 }
2461               return;
2462             }
2463           else
2464             {
2465               (void) snat_del_address(sm, address[0], 1);
2466               return;
2467             }
2468         }
2469     }
2470 }
2471
2472
2473 static int snat_add_interface_address (snat_main_t *sm,
2474                                        u32 sw_if_index,
2475                                        int is_del)
2476 {
2477   ip4_main_t * ip4_main = sm->ip4_main;
2478   ip4_address_t * first_int_addr;
2479   snat_static_map_resolve_t *rp;
2480   u32 *indices_to_delete = 0;
2481   int i, j;
2482
2483   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2484                                                 0 /* just want the address*/);
2485
2486   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2487     {
2488       if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2489         {
2490           if (is_del)
2491             {
2492               /* if have address remove it */
2493               if (first_int_addr)
2494                   (void) snat_del_address (sm, first_int_addr[0], 1);
2495               else
2496                 {
2497                   for (j = 0; j < vec_len (sm->to_resolve); j++)
2498                     {
2499                       rp = sm->to_resolve + j;
2500                       if (rp->sw_if_index == sw_if_index)
2501                         vec_add1 (indices_to_delete, j);
2502                     }
2503                   if (vec_len(indices_to_delete))
2504                     {
2505                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2506                         vec_del1(sm->to_resolve, j);
2507                       vec_free(indices_to_delete);
2508                     }
2509                 }
2510               vec_del1(sm->auto_add_sw_if_indices, i);
2511             }
2512           else
2513             return VNET_API_ERROR_VALUE_EXIST;
2514
2515           return 0;
2516         }
2517     }
2518   
2519   if (is_del)
2520     return VNET_API_ERROR_NO_SUCH_ENTRY;
2521
2522   /* add to the auto-address list */
2523   vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2524
2525   /* If the address is already bound - or static - add it now */
2526   if (first_int_addr)
2527       snat_add_address (sm, first_int_addr);
2528
2529   return 0;
2530 }
2531
2532 static clib_error_t *
2533 snat_add_interface_address_command_fn (vlib_main_t * vm,
2534                                        unformat_input_t * input,
2535                                        vlib_cli_command_t * cmd)
2536 {
2537   snat_main_t *sm = &snat_main;
2538   unformat_input_t _line_input, *line_input = &_line_input;
2539   u32 sw_if_index;
2540   int rv;
2541   int is_del = 0;
2542
2543   /* Get a line of input. */
2544   if (!unformat_user (input, unformat_line_input, line_input))
2545     return 0;
2546
2547   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2548     {
2549       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2550                     sm->vnet_main, &sw_if_index))
2551         ;
2552       else if (unformat (line_input, "del"))
2553         is_del = 1;
2554       else
2555         return clib_error_return (0, "unknown input '%U'",
2556                                   format_unformat_error, line_input);
2557     }
2558
2559   rv = snat_add_interface_address (sm, sw_if_index, is_del);
2560
2561   switch (rv)
2562     {
2563     case 0:
2564       break;
2565
2566     default:
2567       return clib_error_return (0, "snat_add_interface_address returned %d",
2568                                 rv);
2569     }
2570   return 0;
2571 }
2572
2573 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2574     .path = "snat add interface address",
2575     .short_help = "snat add interface address <interface> [del]",
2576     .function = snat_add_interface_address_command_fn,
2577 };