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