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