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