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