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