SNAT: session dump last heard type fix
[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 static void
1416 send_snat_user_details
1417 (snat_user_t * u, unix_shared_memory_queue_t * q, u32 context)
1418 {
1419   vl_api_snat_user_details_t * rmp;
1420   snat_main_t * sm = &snat_main;
1421   ip4_fib_t * fib_table;
1422
1423   rmp = vl_msg_api_alloc (sizeof (*rmp));
1424   memset (rmp, 0, sizeof (*rmp));
1425   rmp->_vl_msg_id = ntohs (VL_API_SNAT_USER_DETAILS+sm->msg_id_base);
1426
1427   fib_table = ip4_fib_get(u->fib_index);
1428   rmp->vrf_id = ntohl (fib_table->table_id);
1429
1430   rmp->is_ip4 = 1;
1431   clib_memcpy(rmp->ip_address, &(u->addr), 4);
1432   rmp->nsessions = ntohl (u->nsessions);
1433   rmp->nstaticsessions = ntohl (u->nstaticsessions);
1434   rmp->context = context;
1435
1436   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1437 }
1438
1439 static void
1440 vl_api_snat_user_dump_t_handler
1441 (vl_api_snat_user_dump_t * mp)
1442 {
1443   unix_shared_memory_queue_t *q;
1444   snat_main_t * sm = &snat_main;
1445   snat_main_per_thread_data_t * tsm;
1446   snat_user_t * u;
1447
1448   q = vl_api_client_index_to_input_queue (mp->client_index);
1449   if (q == 0)
1450     return;
1451
1452   vec_foreach (tsm, sm->per_thread_data)
1453     vec_foreach (u, tsm->users)
1454       send_snat_user_details (u, q, mp->context);
1455 }
1456
1457 static void *vl_api_snat_user_dump_t_print
1458 (vl_api_snat_user_dump_t *mp, void * handle)
1459 {
1460   u8 *s;
1461
1462   s = format (0, "SCRIPT: snat_user_dump ");
1463
1464   FINISH;
1465 }
1466
1467 static void
1468 send_snat_user_session_details
1469 (snat_session_t * s, unix_shared_memory_queue_t * q, u32 context)
1470 {
1471   vl_api_snat_user_session_details_t * rmp;
1472   snat_main_t * sm = &snat_main;
1473
1474   rmp = vl_msg_api_alloc (sizeof(*rmp));
1475   memset (rmp, 0, sizeof (*rmp));
1476   rmp->_vl_msg_id = ntohs (VL_API_SNAT_USER_SESSION_DETAILS+sm->msg_id_base);
1477   rmp->is_ip4 = 1;
1478   clib_memcpy(rmp->outside_ip_address, (&s->out2in.addr), 4);
1479   rmp->outside_port = s->out2in.port;
1480   clib_memcpy(rmp->inside_ip_address, (&s->in2out.addr), 4);
1481   rmp->inside_port = s->in2out.port;
1482   rmp->protocol = ntohs(snat_proto_to_ip_proto(s->in2out.protocol));
1483   rmp->is_static = s->flags & SNAT_SESSION_FLAG_STATIC_MAPPING ? 1 : 0;
1484   rmp->last_heard = clib_host_to_net_u64((u64)s->last_heard);
1485   rmp->total_bytes = clib_host_to_net_u64(s->total_bytes);
1486   rmp->total_pkts = ntohl(s->total_pkts);
1487   rmp->context = context;
1488
1489   vl_msg_api_send_shmem (q, (u8 *) & rmp);
1490 }
1491
1492 static void
1493 vl_api_snat_user_session_dump_t_handler
1494 (vl_api_snat_user_session_dump_t * mp)
1495 {
1496   unix_shared_memory_queue_t *q;
1497   snat_main_t * sm = &snat_main;
1498   snat_main_per_thread_data_t *tsm;
1499   snat_session_t * s;
1500   clib_bihash_kv_8_8_t key, value;
1501   snat_user_key_t ukey;
1502   snat_user_t * u;
1503   u32 session_index, head_index, elt_index;
1504   dlist_elt_t * head, * elt;
1505
1506   q = vl_api_client_index_to_input_queue (mp->client_index);
1507   if (q == 0)
1508     return;
1509
1510   clib_memcpy (&ukey.addr, mp->ip_address, 4);
1511   ukey.fib_index = ip4_fib_index_from_table_id (ntohl(mp->vrf_id));
1512   key.key = ukey.as_u64;
1513   if (!clib_bihash_search_8_8 (&sm->worker_by_in, &key, &value))
1514     tsm = vec_elt_at_index (sm->per_thread_data, value.value);
1515   else
1516     tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
1517   if (clib_bihash_search_8_8 (&sm->user_hash, &key, &value))
1518     return;
1519   u = pool_elt_at_index (tsm->users, value.value);
1520   if (!u->nsessions && !u->nstaticsessions)
1521     return;
1522
1523   head_index = u->sessions_per_user_list_head_index;
1524   head = pool_elt_at_index (tsm->list_pool, head_index);
1525   elt_index = head->next;
1526   elt = pool_elt_at_index (tsm->list_pool, elt_index);
1527   session_index = elt->value;
1528   while (session_index != ~0)
1529     {
1530       s = pool_elt_at_index (tsm->sessions, session_index);
1531
1532       send_snat_user_session_details (s, q, mp->context);
1533
1534       elt_index = elt->next;
1535       elt = pool_elt_at_index (tsm->list_pool, elt_index);
1536       session_index = elt->value;
1537     }
1538 }
1539
1540 static void *vl_api_snat_user_session_dump_t_print
1541 (vl_api_snat_user_session_dump_t *mp, void * handle)
1542 {
1543   u8 *s;
1544
1545   s = format (0, "SCRIPT: snat_user_session_dump ");
1546   s = format (s, "ip_address %U vrf_id %d\n",
1547               format_ip4_address, mp->ip_address,
1548               clib_net_to_host_u32 (mp->vrf_id));
1549
1550   FINISH;
1551 }
1552
1553 /* List of message types that this plugin understands */
1554 #define foreach_snat_plugin_api_msg                                     \
1555 _(SNAT_ADD_ADDRESS_RANGE, snat_add_address_range)                       \
1556 _(SNAT_INTERFACE_ADD_DEL_FEATURE, snat_interface_add_del_feature)       \
1557 _(SNAT_ADD_STATIC_MAPPING, snat_add_static_mapping)                     \
1558 _(SNAT_CONTROL_PING, snat_control_ping)                                 \
1559 _(SNAT_STATIC_MAPPING_DUMP, snat_static_mapping_dump)                   \
1560 _(SNAT_SHOW_CONFIG, snat_show_config)                                   \
1561 _(SNAT_ADDRESS_DUMP, snat_address_dump)                                 \
1562 _(SNAT_INTERFACE_DUMP, snat_interface_dump)                             \
1563 _(SNAT_SET_WORKERS, snat_set_workers)                                   \
1564 _(SNAT_WORKER_DUMP, snat_worker_dump)                                   \
1565 _(SNAT_ADD_DEL_INTERFACE_ADDR, snat_add_del_interface_addr)             \
1566 _(SNAT_INTERFACE_ADDR_DUMP, snat_interface_addr_dump)                   \
1567 _(SNAT_IPFIX_ENABLE_DISABLE, snat_ipfix_enable_disable)                 \
1568 _(SNAT_USER_DUMP, snat_user_dump)                                       \
1569 _(SNAT_USER_SESSION_DUMP, snat_user_session_dump)
1570
1571 /* Set up the API message handling tables */
1572 static clib_error_t *
1573 snat_plugin_api_hookup (vlib_main_t *vm)
1574 {
1575    snat_main_t * sm __attribute__ ((unused)) = &snat_main;
1576 #define _(N,n)                                                  \
1577     vl_msg_api_set_handlers((VL_API_##N + sm->msg_id_base),     \
1578                            #n,                                  \
1579                            vl_api_##n##_t_handler,              \
1580                            vl_noop_handler,                     \
1581                            vl_api_##n##_t_endian,               \
1582                            vl_api_##n##_t_print,                \
1583                            sizeof(vl_api_##n##_t), 1); 
1584     foreach_snat_plugin_api_msg;
1585 #undef _
1586
1587     return 0;
1588 }
1589
1590 #define vl_msg_name_crc_list
1591 #include <snat/snat_all_api_h.h>
1592 #undef vl_msg_name_crc_list
1593
1594 static void
1595 setup_message_id_table (snat_main_t * sm, api_main_t * am)
1596 {
1597 #define _(id,n,crc) \
1598   vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + sm->msg_id_base);
1599   foreach_vl_msg_name_crc_snat;
1600 #undef _
1601 }
1602
1603 static void plugin_custom_dump_configure (snat_main_t * sm) 
1604 {
1605 #define _(n,f) sm->api_main->msg_print_handlers \
1606   [VL_API_##n + sm->msg_id_base]                \
1607     = (void *) vl_api_##f##_t_print;
1608   foreach_snat_plugin_api_msg;
1609 #undef _
1610 }
1611
1612
1613 static void
1614 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
1615                                        uword opaque,
1616                                        u32 sw_if_index,
1617                                        ip4_address_t * address,
1618                                        u32 address_length,
1619                                        u32 if_address_index,
1620                                        u32 is_delete);
1621
1622 static clib_error_t * snat_init (vlib_main_t * vm)
1623 {
1624   snat_main_t * sm = &snat_main;
1625   clib_error_t * error = 0;
1626   ip4_main_t * im = &ip4_main;
1627   ip_lookup_main_t * lm = &im->lookup_main;
1628   u8 * name;
1629   uword *p;
1630   vlib_thread_registration_t *tr;
1631   vlib_thread_main_t *tm = vlib_get_thread_main ();
1632   uword *bitmap = 0;
1633   u32 i;
1634   ip4_add_del_interface_address_callback_t cb4;
1635
1636   name = format (0, "snat_%08x%c", api_version, 0);
1637
1638   /* Ask for a correctly-sized block of API message decode slots */
1639   sm->msg_id_base = vl_msg_api_get_msg_ids 
1640       ((char *) name, VL_MSG_FIRST_AVAILABLE);
1641
1642   sm->vlib_main = vm;
1643   sm->vnet_main = vnet_get_main();
1644   sm->ip4_main = im;
1645   sm->ip4_lookup_main = lm;
1646   sm->api_main = &api_main;
1647   sm->first_worker_index = 0;
1648   sm->next_worker = 0;
1649   sm->num_workers = 0;
1650   sm->workers = 0;
1651   sm->fq_in2out_index = ~0;
1652   sm->fq_out2in_index = ~0;
1653
1654   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1655   if (p)
1656     {
1657       tr = (vlib_thread_registration_t *) p[0];
1658       if (tr)
1659         {
1660           sm->num_workers = tr->count;
1661           sm->first_worker_index = tr->first_index;
1662         }
1663     }
1664
1665   /* Use all available workers by default */
1666   if (sm->num_workers > 1)
1667     {
1668       for (i=0; i < sm->num_workers; i++)
1669         bitmap = clib_bitmap_set (bitmap, i, 1);
1670       snat_set_workers(bitmap);
1671       clib_bitmap_free (bitmap);
1672     }
1673
1674   error = snat_plugin_api_hookup (vm);
1675
1676   /* Add our API messages to the global name_crc hash table */
1677   setup_message_id_table (sm, &api_main);
1678
1679   plugin_custom_dump_configure (sm);
1680   vec_free(name);
1681
1682   /* Set up the interface address add/del callback */
1683   cb4.function = snat_ip4_add_del_interface_address_cb;
1684   cb4.function_opaque = 0;
1685
1686   vec_add1 (im->add_del_interface_address_callbacks, cb4);
1687
1688   /* Init IPFIX logging */
1689   snat_ipfix_logging_init(vm);
1690
1691   return error;
1692 }
1693
1694 VLIB_INIT_FUNCTION (snat_init);
1695
1696 void snat_free_outside_address_and_port (snat_main_t * sm, 
1697                                          snat_session_key_t * k, 
1698                                          u32 address_index)
1699 {
1700   snat_address_t *a;
1701   u16 port_host_byte_order = clib_net_to_host_u16 (k->port);
1702   
1703   ASSERT (address_index < vec_len (sm->addresses));
1704
1705   a = sm->addresses + address_index;
1706
1707   switch (k->protocol)
1708     {
1709 #define _(N, i, n, s) \
1710     case SNAT_PROTOCOL_##N: \
1711       ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
1712         port_host_byte_order) == 1); \
1713       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
1714         port_host_byte_order, 0); \
1715       a->busy_##n##_ports--; \
1716       break;
1717       foreach_snat_protocol
1718 #undef _
1719     default:
1720       clib_warning("unknown_protocol");
1721       return;
1722     }
1723 }  
1724
1725 /**
1726  * @brief Match SNAT static mapping.
1727  *
1728  * @param sm          SNAT main.
1729  * @param match       Address and port to match.
1730  * @param mapping     External or local address and port of the matched mapping.
1731  * @param by_external If 0 match by local address otherwise match by external
1732  *                    address.
1733  *
1734  * @returns 0 if match found otherwise 1.
1735  */
1736 int snat_static_mapping_match (snat_main_t * sm,
1737                                snat_session_key_t match,
1738                                snat_session_key_t * mapping,
1739                                u8 by_external)
1740 {
1741   clib_bihash_kv_8_8_t kv, value;
1742   snat_static_mapping_t *m;
1743   snat_session_key_t m_key;
1744   clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local;
1745
1746   if (by_external)
1747     mapping_hash = &sm->static_mapping_by_external;
1748
1749   m_key.addr = match.addr;
1750   m_key.port = clib_net_to_host_u16 (match.port);
1751   m_key.protocol = match.protocol;
1752   m_key.fib_index = match.fib_index;
1753
1754   kv.key = m_key.as_u64;
1755
1756   if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1757     {
1758       /* Try address only mapping */
1759       m_key.port = 0;
1760       m_key.protocol = 0;
1761       kv.key = m_key.as_u64;
1762       if (clib_bihash_search_8_8 (mapping_hash, &kv, &value))
1763         return 1;
1764     }
1765
1766   m = pool_elt_at_index (sm->static_mappings, value.value);
1767
1768   if (by_external)
1769     {
1770       mapping->addr = m->local_addr;
1771       /* Address only mapping doesn't change port */
1772       mapping->port = m->addr_only ? match.port
1773         : clib_host_to_net_u16 (m->local_port);
1774       mapping->fib_index = m->fib_index;
1775     }
1776   else
1777     {
1778       mapping->addr = m->external_addr;
1779       /* Address only mapping doesn't change port */
1780       mapping->port = m->addr_only ? match.port
1781         : clib_host_to_net_u16 (m->external_port);
1782       mapping->fib_index = sm->outside_fib_index;
1783     }
1784
1785   return 0;
1786 }
1787
1788 int snat_alloc_outside_address_and_port (snat_main_t * sm, 
1789                                          snat_session_key_t * k,
1790                                          u32 * address_indexp)
1791 {
1792   int i;
1793   snat_address_t *a;
1794   u32 portnum;
1795
1796   for (i = 0; i < vec_len (sm->addresses); i++)
1797     {
1798       a = sm->addresses + i;
1799       switch (k->protocol)
1800         {
1801 #define _(N, j, n, s) \
1802         case SNAT_PROTOCOL_##N: \
1803           if (a->busy_##n##_ports < (65535-1024)) \
1804             { \
1805               while (1) \
1806                 { \
1807                   portnum = random_u32 (&sm->random_seed); \
1808                   portnum &= 0xFFFF; \
1809                   if (portnum < 1024) \
1810                     continue; \
1811                   if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \
1812                     continue; \
1813                   clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \
1814                   a->busy_##n##_ports++; \
1815                   k->addr = a->addr; \
1816                   k->port = clib_host_to_net_u16(portnum); \
1817                   *address_indexp = i; \
1818                   return 0; \
1819                 } \
1820             } \
1821           break;
1822           foreach_snat_protocol
1823 #undef _
1824         default:
1825           clib_warning("unknown protocol");
1826           return 1;
1827         }
1828
1829     }
1830   /* Totally out of translations to use... */
1831   snat_ipfix_logging_addresses_exhausted(0);
1832   return 1;
1833 }
1834
1835
1836 static clib_error_t *
1837 add_address_command_fn (vlib_main_t * vm,
1838                         unformat_input_t * input,
1839                         vlib_cli_command_t * cmd)
1840 {
1841   unformat_input_t _line_input, *line_input = &_line_input;
1842   snat_main_t * sm = &snat_main;
1843   ip4_address_t start_addr, end_addr, this_addr;
1844   u32 start_host_order, end_host_order;
1845   int i, count;
1846   int is_add = 1;
1847   int rv = 0;
1848   clib_error_t *error = 0;
1849
1850   /* Get a line of input. */
1851   if (!unformat_user (input, unformat_line_input, line_input))
1852     return 0;
1853
1854   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1855     {
1856       if (unformat (line_input, "%U - %U",
1857                     unformat_ip4_address, &start_addr,
1858                     unformat_ip4_address, &end_addr))
1859         ;
1860       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
1861         end_addr = start_addr;
1862       else if (unformat (line_input, "del"))
1863         is_add = 0;
1864       else
1865         {
1866           error = clib_error_return (0, "unknown input '%U'",
1867             format_unformat_error, line_input);
1868           goto done;
1869         }
1870      }
1871
1872   if (sm->static_mapping_only)
1873     {
1874       error = clib_error_return (0, "static mapping only mode");
1875       goto done;
1876     }
1877
1878   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
1879   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
1880   
1881   if (end_host_order < start_host_order)
1882     {
1883       error = clib_error_return (0, "end address less than start address");
1884       goto done;
1885     }
1886
1887   count = (end_host_order - start_host_order) + 1;
1888
1889   if (count > 1024)
1890     clib_warning ("%U - %U, %d addresses...",
1891                   format_ip4_address, &start_addr,
1892                   format_ip4_address, &end_addr,
1893                   count);
1894   
1895   this_addr = start_addr;
1896
1897   for (i = 0; i < count; i++)
1898     {
1899       if (is_add)
1900         snat_add_address (sm, &this_addr);
1901       else
1902         rv = snat_del_address (sm, this_addr, 0);
1903
1904       switch (rv)
1905         {
1906         case VNET_API_ERROR_NO_SUCH_ENTRY:
1907           error = clib_error_return (0, "S-NAT address not exist.");
1908           goto done;
1909         case VNET_API_ERROR_UNSPECIFIED:
1910           error = clib_error_return (0, "S-NAT address used in static mapping.");
1911           goto done;
1912         default:
1913           break;
1914         }
1915
1916       increment_v4_address (&this_addr);
1917     }
1918
1919 done:
1920   unformat_free (line_input);
1921
1922   return error;
1923 }
1924
1925 VLIB_CLI_COMMAND (add_address_command, static) = {
1926   .path = "snat add address",
1927   .short_help = "snat add addresses <ip4-range-start> [- <ip4-range-end>] [del]",
1928   .function = add_address_command_fn,
1929 };
1930
1931 static clib_error_t *
1932 snat_feature_command_fn (vlib_main_t * vm,
1933                           unformat_input_t * input,
1934                           vlib_cli_command_t * cmd)
1935 {
1936   unformat_input_t _line_input, *line_input = &_line_input;
1937   vnet_main_t * vnm = vnet_get_main();
1938   clib_error_t * error = 0;
1939   u32 sw_if_index;
1940   u32 * inside_sw_if_indices = 0;
1941   u32 * outside_sw_if_indices = 0;
1942   int is_del = 0;
1943   int i;
1944
1945   sw_if_index = ~0;
1946
1947   /* Get a line of input. */
1948   if (!unformat_user (input, unformat_line_input, line_input))
1949     return 0;
1950
1951   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1952     {
1953       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
1954                     vnm, &sw_if_index))
1955         vec_add1 (inside_sw_if_indices, sw_if_index);
1956       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
1957                          vnm, &sw_if_index))
1958         vec_add1 (outside_sw_if_indices, sw_if_index);
1959       else if (unformat (line_input, "del"))
1960         is_del = 1;
1961       else
1962         {
1963           error = clib_error_return (0, "unknown input '%U'",
1964             format_unformat_error, line_input);
1965           goto done;
1966         }
1967     }
1968
1969   if (vec_len (inside_sw_if_indices))
1970     {
1971       for (i = 0; i < vec_len(inside_sw_if_indices); i++)
1972         {
1973           sw_if_index = inside_sw_if_indices[i];
1974           snat_interface_add_del (sw_if_index, 1, is_del);
1975         }
1976     }
1977
1978   if (vec_len (outside_sw_if_indices))
1979     {
1980       for (i = 0; i < vec_len(outside_sw_if_indices); i++)
1981         {
1982           sw_if_index = outside_sw_if_indices[i];
1983           snat_interface_add_del (sw_if_index, 0, is_del);
1984         }
1985     }
1986
1987 done:
1988   unformat_free (line_input);
1989   vec_free (inside_sw_if_indices);
1990   vec_free (outside_sw_if_indices);
1991
1992   return error;
1993 }
1994
1995 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1996   .path = "set interface snat",
1997   .function = snat_feature_command_fn,
1998   .short_help = "set interface snat in <intfc> out <intfc> [del]",
1999 };
2000
2001 uword
2002 unformat_snat_protocol (unformat_input_t * input, va_list * args)
2003 {
2004   u32 *r = va_arg (*args, u32 *);
2005
2006   if (0);
2007 #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N;
2008   foreach_snat_protocol
2009 #undef _
2010   else
2011     return 0;
2012   return 1;
2013 }
2014
2015 u8 *
2016 format_snat_protocol (u8 * s, va_list * args)
2017 {
2018   u32 i = va_arg (*args, u32);
2019   u8 *t = 0;
2020
2021   switch (i)
2022     {
2023 #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break;
2024       foreach_snat_protocol
2025 #undef _
2026     default:
2027       s = format (s, "unknown");
2028     }
2029   s = format (s, "%s", t);
2030   return s;
2031 }
2032
2033 static clib_error_t *
2034 add_static_mapping_command_fn (vlib_main_t * vm,
2035                                unformat_input_t * input,
2036                                vlib_cli_command_t * cmd)
2037 {
2038   unformat_input_t _line_input, *line_input = &_line_input;
2039   clib_error_t * error = 0;
2040   ip4_address_t l_addr, e_addr;
2041   u32 l_port = 0, e_port = 0, vrf_id = ~0;
2042   int is_add = 1;
2043   int addr_only = 1;
2044   u32 sw_if_index = ~0;
2045   vnet_main_t * vnm = vnet_get_main();
2046   int rv;
2047   snat_protocol_t proto;
2048   u8 proto_set = 0;
2049
2050   /* Get a line of input. */
2051   if (!unformat_user (input, unformat_line_input, line_input))
2052     return 0;
2053
2054   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2055     {
2056       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
2057                     &l_port))
2058         addr_only = 0;
2059       else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
2060         ;
2061       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
2062                          &e_addr, &e_port))
2063         addr_only = 0;
2064       else if (unformat (line_input, "external %U", unformat_ip4_address,
2065                          &e_addr))
2066         ;
2067       else if (unformat (line_input, "external %U %u",
2068                          unformat_vnet_sw_interface, vnm, &sw_if_index,
2069                          &e_port))
2070         addr_only = 0;
2071
2072       else if (unformat (line_input, "external %U",
2073                          unformat_vnet_sw_interface, vnm, &sw_if_index))
2074         ;
2075       else if (unformat (line_input, "vrf %u", &vrf_id))
2076         ;
2077       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
2078         proto_set = 1;
2079       else if (unformat (line_input, "del"))
2080         is_add = 0;
2081       else
2082         {
2083           error = clib_error_return (0, "unknown input: '%U'",
2084             format_unformat_error, line_input);
2085           goto done;
2086         }
2087     }
2088
2089   if (!addr_only && !proto_set)
2090     {
2091       error = clib_error_return (0, "missing protocol");
2092       goto done;
2093     }
2094
2095   rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port,
2096                                vrf_id, addr_only, sw_if_index, proto, is_add);
2097
2098   switch (rv)
2099     {
2100     case VNET_API_ERROR_INVALID_VALUE:
2101       error = clib_error_return (0, "External port already in use.");
2102       goto done;
2103     case VNET_API_ERROR_NO_SUCH_ENTRY:
2104       if (is_add)
2105         error = clib_error_return (0, "External addres must be allocated.");
2106       else
2107         error = clib_error_return (0, "Mapping not exist.");
2108       goto done;
2109     case VNET_API_ERROR_NO_SUCH_FIB:
2110       error = clib_error_return (0, "No such VRF id.");
2111       goto done;
2112     case VNET_API_ERROR_VALUE_EXIST:
2113       error = clib_error_return (0, "Mapping already exist.");
2114       goto done;
2115     default:
2116       break;
2117     }
2118
2119 done:
2120   unformat_free (line_input);
2121
2122   return error;
2123 }
2124
2125 /*?
2126  * @cliexpar
2127  * @cliexstart{snat add static mapping}
2128  * Static mapping allows hosts on the external network to initiate connection
2129  * to to the local network host.
2130  * To create static mapping between local host address 10.0.0.3 port 6303 and
2131  * external address 4.4.4.4 port 3606 for TCP protocol use:
2132  *  vpp# snat add static mapping local tcp 10.0.0.3 6303 external 4.4.4.4 3606
2133  * If not runnig "static mapping only" S-NAT plugin mode use before:
2134  *  vpp# snat add address 4.4.4.4
2135  * To create static mapping between local and external address use:
2136  *  vpp# snat add static mapping local 10.0.0.3 external 4.4.4.4
2137  * @cliexend
2138 ?*/
2139 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2140   .path = "snat add static mapping",
2141   .function = add_static_mapping_command_fn,
2142   .short_help =
2143     "snat add static mapping local tcp|udp|icmp <addr> [<port>] external <addr> [<port>] [vrf <table-id>] [del]",
2144 };
2145
2146 static clib_error_t *
2147 set_workers_command_fn (vlib_main_t * vm,
2148                         unformat_input_t * input,
2149                         vlib_cli_command_t * cmd)
2150 {
2151   unformat_input_t _line_input, *line_input = &_line_input;
2152   uword *bitmap = 0;
2153   int rv = 0;
2154   clib_error_t *error = 0;
2155
2156   /* Get a line of input. */
2157   if (!unformat_user (input, unformat_line_input, line_input))
2158     return 0;
2159
2160   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2161     {
2162       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
2163         ;
2164       else
2165         {
2166           error = clib_error_return (0, "unknown input '%U'",
2167             format_unformat_error, line_input);
2168           goto done;
2169         }
2170      }
2171
2172   if (bitmap == 0)
2173     {
2174       error = clib_error_return (0, "List of workers must be specified.");
2175       goto done;
2176     }
2177
2178   rv = snat_set_workers(bitmap);
2179
2180   clib_bitmap_free (bitmap);
2181
2182   switch (rv)
2183     {
2184     case VNET_API_ERROR_INVALID_WORKER:
2185       error = clib_error_return (0, "Invalid worker(s).");
2186       goto done;
2187     case VNET_API_ERROR_FEATURE_DISABLED:
2188       error = clib_error_return (0,
2189         "Supported only if 2 or more workes available.");
2190       goto done;
2191     default:
2192       break;
2193     }
2194
2195 done:
2196   unformat_free (line_input);
2197
2198   return error;
2199 }
2200
2201 /*?
2202  * @cliexpar
2203  * @cliexstart{set snat workers}
2204  * Set SNAT workers if 2 or more workers available, use:
2205  *  vpp# set snat workers 0-2,5
2206  * @cliexend
2207 ?*/
2208 VLIB_CLI_COMMAND (set_workers_command, static) = {
2209   .path = "set snat workers",
2210   .function = set_workers_command_fn,
2211   .short_help =
2212     "set snat workers <workers-list>",
2213 };
2214
2215 static clib_error_t *
2216 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
2217                                               unformat_input_t * input,
2218                                               vlib_cli_command_t * cmd)
2219 {
2220   unformat_input_t _line_input, *line_input = &_line_input;
2221   u32 domain_id = 0;
2222   u32 src_port = 0;
2223   u8 enable = 1;
2224   int rv = 0;
2225   clib_error_t *error = 0;
2226
2227   /* Get a line of input. */
2228   if (!unformat_user (input, unformat_line_input, line_input))
2229     return 0;
2230
2231   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2232     {
2233       if (unformat (line_input, "domain %d", &domain_id))
2234         ;
2235       else if (unformat (line_input, "src-port %d", &src_port))
2236         ;
2237       else if (unformat (line_input, "disable"))
2238         enable = 0;
2239       else
2240         {
2241           error = clib_error_return (0, "unknown input '%U'",
2242             format_unformat_error, line_input);
2243           goto done;
2244         }
2245      }
2246
2247   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
2248
2249   if (rv)
2250     {
2251       error = clib_error_return (0, "ipfix logging enable failed");
2252       goto done;
2253     }
2254
2255 done:
2256   unformat_free (line_input);
2257
2258   return error;
2259 }
2260
2261 /*?
2262  * @cliexpar
2263  * @cliexstart{snat ipfix logging}
2264  * To enable SNAT IPFIX logging use:
2265  *  vpp# snat ipfix logging
2266  * To set IPFIX exporter use:
2267  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2268  * @cliexend
2269 ?*/
2270 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2271   .path = "snat ipfix logging",
2272   .function = snat_ipfix_logging_enable_disable_command_fn,
2273   .short_help = "snat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2274 };
2275
2276 static clib_error_t *
2277 snat_config (vlib_main_t * vm, unformat_input_t * input)
2278 {
2279   snat_main_t * sm = &snat_main;
2280   u32 translation_buckets = 1024;
2281   u32 translation_memory_size = 128<<20;
2282   u32 user_buckets = 128;
2283   u32 user_memory_size = 64<<20;
2284   u32 max_translations_per_user = 100;
2285   u32 outside_vrf_id = 0;
2286   u32 inside_vrf_id = 0;
2287   u32 static_mapping_buckets = 1024;
2288   u32 static_mapping_memory_size = 64<<20;
2289   u8 static_mapping_only = 0;
2290   u8 static_mapping_connection_tracking = 0;
2291   vlib_thread_main_t *tm = vlib_get_thread_main ();
2292
2293   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2294     {
2295       if (unformat (input, "translation hash buckets %d", &translation_buckets))
2296         ;
2297       else if (unformat (input, "translation hash memory %d",
2298                          &translation_memory_size));
2299       else if (unformat (input, "user hash buckets %d", &user_buckets))
2300         ;
2301       else if (unformat (input, "user hash memory %d",
2302                          &user_memory_size))
2303         ;
2304       else if (unformat (input, "max translations per user %d",
2305                          &max_translations_per_user))
2306         ;
2307       else if (unformat (input, "outside VRF id %d",
2308                          &outside_vrf_id))
2309         ;
2310       else if (unformat (input, "inside VRF id %d",
2311                          &inside_vrf_id))
2312         ;
2313       else if (unformat (input, "static mapping only"))
2314         {
2315           static_mapping_only = 1;
2316           if (unformat (input, "connection tracking"))
2317             static_mapping_connection_tracking = 1;
2318         }
2319       else 
2320         return clib_error_return (0, "unknown input '%U'",
2321                                   format_unformat_error, input);
2322     }
2323
2324   /* for show commands, etc. */
2325   sm->translation_buckets = translation_buckets;
2326   sm->translation_memory_size = translation_memory_size;
2327   sm->user_buckets = user_buckets;
2328   sm->user_memory_size = user_memory_size;
2329   sm->max_translations_per_user = max_translations_per_user;
2330   sm->outside_vrf_id = outside_vrf_id;
2331   sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2332                                                              outside_vrf_id);
2333   sm->inside_vrf_id = inside_vrf_id;
2334   sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4,
2335                                                             inside_vrf_id);
2336   sm->static_mapping_only = static_mapping_only;
2337   sm->static_mapping_connection_tracking = static_mapping_connection_tracking;
2338
2339   if (!static_mapping_only ||
2340       (static_mapping_only && static_mapping_connection_tracking))
2341     {
2342       clib_bihash_init_8_8 (&sm->worker_by_in, "worker-by-in", user_buckets,
2343                             user_memory_size);
2344
2345       clib_bihash_init_8_8 (&sm->worker_by_out, "worker-by-out", user_buckets,
2346                             user_memory_size);
2347
2348       vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1);
2349
2350       clib_bihash_init_8_8 (&sm->in2out, "in2out", translation_buckets,
2351                             translation_memory_size);
2352
2353       clib_bihash_init_8_8 (&sm->out2in, "out2in", translation_buckets,
2354                             translation_memory_size);
2355
2356       clib_bihash_init_8_8 (&sm->user_hash, "users", user_buckets,
2357                             user_memory_size);
2358     }
2359   clib_bihash_init_8_8 (&sm->static_mapping_by_local,
2360                         "static_mapping_by_local", static_mapping_buckets,
2361                         static_mapping_memory_size);
2362
2363   clib_bihash_init_8_8 (&sm->static_mapping_by_external,
2364                         "static_mapping_by_external", static_mapping_buckets,
2365                         static_mapping_memory_size);
2366   return 0;
2367 }
2368
2369 VLIB_CONFIG_FUNCTION (snat_config, "snat");
2370
2371 u8 * format_snat_key (u8 * s, va_list * args)
2372 {
2373   snat_session_key_t * key = va_arg (*args, snat_session_key_t *);
2374   char * protocol_string = "unknown";
2375   static char *protocol_strings[] = {
2376       "UDP",
2377       "TCP",
2378       "ICMP",
2379   };
2380
2381   if (key->protocol < ARRAY_LEN(protocol_strings))
2382       protocol_string = protocol_strings[key->protocol];
2383
2384   s = format (s, "%U proto %s port %d fib %d",
2385               format_ip4_address, &key->addr, protocol_string,
2386               clib_net_to_host_u16 (key->port), key->fib_index);
2387   return s;
2388 }
2389
2390 u8 * format_snat_session (u8 * s, va_list * args)
2391 {
2392   snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *);
2393   snat_session_t * sess = va_arg (*args, snat_session_t *);
2394
2395   s = format (s, "  i2o %U\n", format_snat_key, &sess->in2out);
2396   s = format (s, "    o2i %U\n", format_snat_key, &sess->out2in);
2397   s = format (s, "       last heard %.2f\n", sess->last_heard);
2398   s = format (s, "       total pkts %d, total bytes %lld\n",
2399               sess->total_pkts, sess->total_bytes);
2400   if (snat_is_session_static (sess))
2401     s = format (s, "       static translation\n");
2402   else
2403     s = format (s, "       dynamic translation\n");
2404
2405   return s;
2406 }
2407
2408 u8 * format_snat_user (u8 * s, va_list * args)
2409 {
2410   snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *);
2411   snat_user_t * u = va_arg (*args, snat_user_t *);
2412   int verbose = va_arg (*args, int);
2413   dlist_elt_t * head, * elt;
2414   u32 elt_index, head_index;
2415   u32 session_index;
2416   snat_session_t * sess;
2417
2418   s = format (s, "%U: %d dynamic translations, %d static translations\n",
2419               format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions);
2420
2421   if (verbose == 0)
2422     return s;
2423
2424   if (u->nsessions || u->nstaticsessions)
2425     {
2426       head_index = u->sessions_per_user_list_head_index;
2427       head = pool_elt_at_index (sm->list_pool, head_index);
2428
2429       elt_index = head->next;
2430       elt = pool_elt_at_index (sm->list_pool, elt_index);
2431       session_index = elt->value;
2432
2433       while (session_index != ~0)
2434         {
2435           sess = pool_elt_at_index (sm->sessions, session_index);
2436
2437           s = format (s, "  %U\n", format_snat_session, sm, sess);
2438
2439           elt_index = elt->next;
2440           elt = pool_elt_at_index (sm->list_pool, elt_index);
2441           session_index = elt->value;
2442         }
2443     }
2444
2445   return s;
2446 }
2447
2448 u8 * format_snat_static_mapping (u8 * s, va_list * args)
2449 {
2450   snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *);
2451
2452   if (m->addr_only)
2453       s = format (s, "local %U external %U vrf %d",
2454                   format_ip4_address, &m->local_addr,
2455                   format_ip4_address, &m->external_addr,
2456                   m->vrf_id);
2457   else
2458       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2459                   format_snat_protocol, m->proto,
2460                   format_ip4_address, &m->local_addr, m->local_port,
2461                   format_ip4_address, &m->external_addr, m->external_port,
2462                   m->vrf_id);
2463
2464   return s;
2465 }
2466
2467 u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args)
2468 {
2469   snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *);
2470   vnet_main_t *vnm = vnet_get_main();
2471
2472   if (m->addr_only)
2473       s = format (s, "local %U external %U vrf %d",
2474                   format_ip4_address, &m->l_addr,
2475                   format_vnet_sw_interface_name, vnm,
2476                   vnet_get_sw_interface (vnm, m->sw_if_index),
2477                   m->vrf_id);
2478   else
2479       s = format (s, "%U local %U:%d external %U:%d vrf %d",
2480                   format_snat_protocol, m->proto,
2481                   format_ip4_address, &m->l_addr, m->l_port,
2482                   format_vnet_sw_interface_name, vnm,
2483                   vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port,
2484                   m->vrf_id);
2485
2486   return s;
2487 }
2488
2489 static clib_error_t *
2490 show_snat_command_fn (vlib_main_t * vm,
2491                  unformat_input_t * input,
2492                  vlib_cli_command_t * cmd)
2493 {
2494   int verbose = 0;
2495   snat_main_t * sm = &snat_main;
2496   snat_user_t * u;
2497   snat_static_mapping_t *m;
2498   snat_interface_t *i;
2499   snat_address_t * ap;
2500   vnet_main_t *vnm = vnet_get_main();
2501   snat_main_per_thread_data_t *tsm;
2502   u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index;
2503   uword j = 0;
2504   snat_static_map_resolve_t *rp;
2505
2506   if (unformat (input, "detail"))
2507     verbose = 1;
2508   else if (unformat (input, "verbose"))
2509     verbose = 2;
2510
2511   if (sm->static_mapping_only)
2512     {
2513       if (sm->static_mapping_connection_tracking)
2514         vlib_cli_output (vm, "SNAT mode: static mapping only connection "
2515                          "tracking");
2516       else
2517         vlib_cli_output (vm, "SNAT mode: static mapping only");
2518     }
2519   else
2520     {
2521       vlib_cli_output (vm, "SNAT mode: dynamic translations enabled");
2522     }
2523
2524   if (verbose > 0)
2525     {
2526       pool_foreach (i, sm->interfaces,
2527       ({
2528         vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm,
2529                          vnet_get_sw_interface (vnm, i->sw_if_index),
2530                          i->is_inside ? "in" : "out");
2531       }));
2532
2533       if (vec_len (sm->auto_add_sw_if_indices))
2534         {
2535           vlib_cli_output (vm, "SNAT pool addresses interfaces:");
2536           vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
2537             {
2538               vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm,
2539                                vnet_get_sw_interface (vnm, *sw_if_index));
2540             }
2541         }
2542
2543       vec_foreach (ap, sm->addresses)
2544         {
2545           vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
2546 #define _(N, i, n, s) \
2547           vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
2548           foreach_snat_protocol
2549 #undef _
2550         }
2551     }
2552
2553   if (sm->num_workers > 1)
2554     {
2555       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
2556       if (verbose > 0)
2557         {
2558           vec_foreach (worker, sm->workers)
2559             {
2560               vlib_worker_thread_t *w =
2561                 vlib_worker_threads + *worker + sm->first_worker_index;
2562               vlib_cli_output (vm, "  %s", w->name);
2563             }
2564         }
2565     }
2566
2567   if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))
2568     {
2569       vlib_cli_output (vm, "%d static mappings",
2570                        pool_elts (sm->static_mappings));
2571
2572       if (verbose > 0)
2573         {
2574           pool_foreach (m, sm->static_mappings,
2575           ({
2576             vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2577           }));
2578         }
2579     }
2580   else
2581     {
2582       vec_foreach (tsm, sm->per_thread_data)
2583         {
2584           users_num += pool_elts (tsm->users);
2585           sessions_num += pool_elts (tsm->sessions);
2586         }
2587
2588       vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions,"
2589                        " %d static mappings",
2590                        users_num,
2591                        vec_len (sm->addresses),
2592                        sessions_num,
2593                        pool_elts (sm->static_mappings));
2594
2595       if (verbose > 0)
2596         {
2597           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->in2out,
2598                            verbose - 1);
2599           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->out2in,
2600                            verbose - 1);
2601           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_in,
2602                            verbose - 1);
2603           vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->worker_by_out,
2604                            verbose - 1);
2605           vec_foreach_index (j, sm->per_thread_data)
2606             {
2607               tsm = vec_elt_at_index (sm->per_thread_data, j);
2608
2609               if (pool_elts (tsm->users) == 0)
2610                 continue;
2611
2612               vlib_worker_thread_t *w = vlib_worker_threads + j;
2613               vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name,
2614                                w->lcore_id);
2615               vlib_cli_output (vm, "  %d list pool elements",
2616                                pool_elts (tsm->list_pool));
2617
2618               pool_foreach (u, tsm->users,
2619               ({
2620                 vlib_cli_output (vm, "  %U", format_snat_user, tsm, u,
2621                                  verbose - 1);
2622               }));
2623             }
2624
2625           if (pool_elts (sm->static_mappings) || vec_len (sm->to_resolve))
2626             {
2627               vlib_cli_output (vm, "static mappings:");
2628               pool_foreach (m, sm->static_mappings,
2629               ({
2630                 vlib_cli_output (vm, "%U", format_snat_static_mapping, m);
2631               }));
2632               for (j = 0; j < vec_len (sm->to_resolve); j++)
2633                 {
2634                   rp = sm->to_resolve + j;
2635                   vlib_cli_output (vm, "%U", format_snat_static_map_to_resolve,
2636                                    rp);
2637                 }
2638             }
2639         }
2640     }
2641
2642   return 0;
2643 }
2644
2645 VLIB_CLI_COMMAND (show_snat_command, static) = {
2646     .path = "show snat",
2647     .short_help = "show snat",
2648     .function = show_snat_command_fn,
2649 };
2650
2651
2652 static void
2653 snat_ip4_add_del_interface_address_cb (ip4_main_t * im,
2654                                        uword opaque,
2655                                        u32 sw_if_index,
2656                                        ip4_address_t * address,
2657                                        u32 address_length,
2658                                        u32 if_address_index,
2659                                        u32 is_delete)
2660 {
2661   snat_main_t *sm = &snat_main;
2662   snat_static_map_resolve_t *rp;
2663   u32 *indices_to_delete = 0;
2664   int i, j;
2665   int rv;
2666
2667   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2668     {
2669       if (sw_if_index == sm->auto_add_sw_if_indices[i])
2670         {
2671           if (!is_delete)
2672             {
2673               /* Don't trip over lease renewal, static config */
2674               for (j = 0; j < vec_len(sm->addresses); j++)
2675                 if (sm->addresses[j].addr.as_u32 == address->as_u32)
2676                   return;
2677
2678               snat_add_address (sm, address);
2679               /* Scan static map resolution vector */
2680               for (j = 0; j < vec_len (sm->to_resolve); j++)
2681                 {
2682                   rp = sm->to_resolve + j;
2683                   /* On this interface? */
2684                   if (rp->sw_if_index == sw_if_index)
2685                     {
2686                       /* Add the static mapping */
2687                       rv = snat_add_static_mapping (rp->l_addr,
2688                                                     address[0],
2689                                                     rp->l_port,
2690                                                     rp->e_port,
2691                                                     rp->vrf_id,
2692                                                     rp->addr_only,
2693                                                     ~0 /* sw_if_index */,
2694                                                     rp->proto,
2695                                                     rp->is_add);
2696                       if (rv)
2697                         clib_warning ("snat_add_static_mapping returned %d", 
2698                                       rv);
2699                       vec_add1 (indices_to_delete, j);
2700                     }
2701                 }
2702               /* If we resolved any of the outstanding static mappings */
2703               if (vec_len(indices_to_delete))
2704                 {
2705                   /* Delete them */
2706                   for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2707                     vec_delete(sm->to_resolve, 1, j);
2708                   vec_free(indices_to_delete);
2709                 }
2710               return;
2711             }
2712           else
2713             {
2714               (void) snat_del_address(sm, address[0], 1);
2715               return;
2716             }
2717         }
2718     }
2719 }
2720
2721
2722 static int snat_add_interface_address (snat_main_t *sm,
2723                                        u32 sw_if_index,
2724                                        int is_del)
2725 {
2726   ip4_main_t * ip4_main = sm->ip4_main;
2727   ip4_address_t * first_int_addr;
2728   snat_static_map_resolve_t *rp;
2729   u32 *indices_to_delete = 0;
2730   int i, j;
2731
2732   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index,
2733                                                 0 /* just want the address*/);
2734
2735   for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++)
2736     {
2737       if (sm->auto_add_sw_if_indices[i] == sw_if_index)
2738         {
2739           if (is_del)
2740             {
2741               /* if have address remove it */
2742               if (first_int_addr)
2743                   (void) snat_del_address (sm, first_int_addr[0], 1);
2744               else
2745                 {
2746                   for (j = 0; j < vec_len (sm->to_resolve); j++)
2747                     {
2748                       rp = sm->to_resolve + j;
2749                       if (rp->sw_if_index == sw_if_index)
2750                         vec_add1 (indices_to_delete, j);
2751                     }
2752                   if (vec_len(indices_to_delete))
2753                     {
2754                       for (j = vec_len(indices_to_delete)-1; j >= 0; j--)
2755                         vec_del1(sm->to_resolve, j);
2756                       vec_free(indices_to_delete);
2757                     }
2758                 }
2759               vec_del1(sm->auto_add_sw_if_indices, i);
2760             }
2761           else
2762             return VNET_API_ERROR_VALUE_EXIST;
2763
2764           return 0;
2765         }
2766     }
2767   
2768   if (is_del)
2769     return VNET_API_ERROR_NO_SUCH_ENTRY;
2770
2771   /* add to the auto-address list */
2772   vec_add1(sm->auto_add_sw_if_indices, sw_if_index);
2773
2774   /* If the address is already bound - or static - add it now */
2775   if (first_int_addr)
2776       snat_add_address (sm, first_int_addr);
2777
2778   return 0;
2779 }
2780
2781 static clib_error_t *
2782 snat_add_interface_address_command_fn (vlib_main_t * vm,
2783                                        unformat_input_t * input,
2784                                        vlib_cli_command_t * cmd)
2785 {
2786   snat_main_t *sm = &snat_main;
2787   unformat_input_t _line_input, *line_input = &_line_input;
2788   u32 sw_if_index;
2789   int rv;
2790   int is_del = 0;
2791   clib_error_t *error = 0;
2792
2793   /* Get a line of input. */
2794   if (!unformat_user (input, unformat_line_input, line_input))
2795     return 0;
2796
2797   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2798     {
2799       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
2800                     sm->vnet_main, &sw_if_index))
2801         ;
2802       else if (unformat (line_input, "del"))
2803         is_del = 1;
2804       else
2805         {
2806           error = clib_error_return (0, "unknown input '%U'",
2807                                      format_unformat_error, line_input);
2808           goto done;
2809         }
2810     }
2811
2812   rv = snat_add_interface_address (sm, sw_if_index, is_del);
2813
2814   switch (rv)
2815     {
2816     case 0:
2817       break;
2818
2819     default:
2820       error = clib_error_return (0, "snat_add_interface_address returned %d",
2821                                  rv);
2822       goto done;
2823     }
2824
2825 done:
2826   unformat_free (line_input);
2827
2828   return error;
2829 }
2830
2831 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2832     .path = "snat add interface address",
2833     .short_help = "snat add interface address <interface> [del]",
2834     .function = snat_add_interface_address_command_fn,
2835 };