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