NAT44: LB NAT - local backends in multiple VRFs (VPP-1345)
[vpp.git] / src / plugins / nat / nat44_cli.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT44 CLI
18  */
19
20 #include <nat/nat.h>
21 #include <nat/nat_ipfix_logging.h>
22 #include <nat/nat_det.h>
23 #include <nat/nat_inlines.h>
24 #include <vnet/fib/fib_table.h>
25
26 #define UNSUPPORTED_IN_DET_MODE_STR \
27   "This command is unsupported in deterministic mode"
28 #define SUPPORTED_ONLY_IN_DET_MODE_STR \
29   "This command is supported only in deterministic mode"
30
31 static clib_error_t *
32 set_workers_command_fn (vlib_main_t * vm,
33                         unformat_input_t * input, vlib_cli_command_t * cmd)
34 {
35   unformat_input_t _line_input, *line_input = &_line_input;
36   snat_main_t *sm = &snat_main;
37   uword *bitmap = 0;
38   int rv = 0;
39   clib_error_t *error = 0;
40
41   if (sm->deterministic)
42     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
43
44   /* Get a line of input. */
45   if (!unformat_user (input, unformat_line_input, line_input))
46     return 0;
47
48   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
49     {
50       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
51         ;
52       else
53         {
54           error = clib_error_return (0, "unknown input '%U'",
55                                      format_unformat_error, line_input);
56           goto done;
57         }
58     }
59
60   if (bitmap == 0)
61     {
62       error = clib_error_return (0, "List of workers must be specified.");
63       goto done;
64     }
65
66   rv = snat_set_workers (bitmap);
67
68   clib_bitmap_free (bitmap);
69
70   switch (rv)
71     {
72     case VNET_API_ERROR_INVALID_WORKER:
73       error = clib_error_return (0, "Invalid worker(s).");
74       goto done;
75     case VNET_API_ERROR_FEATURE_DISABLED:
76       error = clib_error_return (0,
77                                  "Supported only if 2 or more workes available.");
78       goto done;
79     default:
80       break;
81     }
82
83 done:
84   unformat_free (line_input);
85
86   return error;
87 }
88
89 static clib_error_t *
90 nat_show_workers_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
91                              vlib_cli_command_t * cmd)
92 {
93   snat_main_t *sm = &snat_main;
94   u32 *worker;
95
96   if (sm->deterministic)
97     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
98
99   if (sm->num_workers > 1)
100     {
101       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
102       /* *INDENT-OFF* */
103       vec_foreach (worker, sm->workers)
104         {
105           vlib_worker_thread_t *w =
106             vlib_worker_threads + *worker + sm->first_worker_index;
107           vlib_cli_output (vm, "  %s", w->name);
108         }
109       /* *INDENT-ON* */
110     }
111
112   return 0;
113 }
114
115 static clib_error_t *
116 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
117                                               unformat_input_t * input,
118                                               vlib_cli_command_t * cmd)
119 {
120   unformat_input_t _line_input, *line_input = &_line_input;
121   u32 domain_id = 0;
122   u32 src_port = 0;
123   u8 enable = 1;
124   int rv = 0;
125   clib_error_t *error = 0;
126
127   /* Get a line of input. */
128   if (!unformat_user (input, unformat_line_input, line_input))
129     return 0;
130
131   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
132     {
133       if (unformat (line_input, "domain %d", &domain_id))
134         ;
135       else if (unformat (line_input, "src-port %d", &src_port))
136         ;
137       else if (unformat (line_input, "disable"))
138         enable = 0;
139       else
140         {
141           error = clib_error_return (0, "unknown input '%U'",
142                                      format_unformat_error, line_input);
143           goto done;
144         }
145     }
146
147   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
148
149   if (rv)
150     {
151       error = clib_error_return (0, "ipfix logging enable failed");
152       goto done;
153     }
154
155 done:
156   unformat_free (line_input);
157
158   return error;
159 }
160
161 static clib_error_t *
162 nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
163                             vlib_cli_command_t * cmd)
164 {
165   snat_main_t *sm = &snat_main;
166   snat_main_per_thread_data_t *tsm;
167   int i;
168   int verbose = 0;
169
170   if (unformat (input, "detail"))
171     verbose = 1;
172   else if (unformat (input, "verbose"))
173     verbose = 2;
174
175   vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local,
176                    verbose);
177   vlib_cli_output (vm, "%U",
178                    format_bihash_8_8, &sm->static_mapping_by_external,
179                    verbose);
180   vec_foreach_index (i, sm->per_thread_data)
181   {
182     tsm = vec_elt_at_index (sm->per_thread_data, i);
183     vlib_cli_output (vm, "-------- thread %d %s --------\n",
184                      i, vlib_worker_threads[i].name);
185     if (sm->endpoint_dependent)
186       {
187         vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->in2out_ed,
188                          verbose);
189         vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->out2in_ed,
190                          verbose);
191       }
192     else
193       {
194         vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->in2out, verbose);
195         vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->out2in, verbose);
196       }
197     vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose);
198   }
199
200   return 0;
201 }
202
203 static clib_error_t *
204 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
205                                               unformat_input_t * input,
206                                               vlib_cli_command_t * cmd)
207 {
208   unformat_input_t _line_input, *line_input = &_line_input;
209   snat_main_t *sm = &snat_main;
210   clib_error_t *error = 0;
211   u32 psid, psid_offset, psid_length;
212
213   if (sm->deterministic)
214     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
215
216   /* Get a line of input. */
217   if (!unformat_user (input, unformat_line_input, line_input))
218     return 0;
219
220   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
221     {
222       if (unformat (line_input, "default"))
223         nat_set_alloc_addr_and_port_default ();
224       else
225         if (unformat
226             (line_input, "map-e psid %d psid-offset %d psid-len %d", &psid,
227              &psid_offset, &psid_length))
228         nat_set_alloc_addr_and_port_mape ((u16) psid, (u16) psid_offset,
229                                           (u16) psid_length);
230       else
231         {
232           error = clib_error_return (0, "unknown input '%U'",
233                                      format_unformat_error, line_input);
234           goto done;
235         }
236     }
237
238 done:
239   unformat_free (line_input);
240
241   return error;
242 };
243
244 static clib_error_t *
245 add_address_command_fn (vlib_main_t * vm,
246                         unformat_input_t * input, vlib_cli_command_t * cmd)
247 {
248   unformat_input_t _line_input, *line_input = &_line_input;
249   snat_main_t *sm = &snat_main;
250   ip4_address_t start_addr, end_addr, this_addr;
251   u32 start_host_order, end_host_order;
252   u32 vrf_id = ~0;
253   int i, count;
254   int is_add = 1;
255   int rv = 0;
256   clib_error_t *error = 0;
257   u8 twice_nat = 0;
258
259   if (sm->deterministic)
260     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
261
262   /* Get a line of input. */
263   if (!unformat_user (input, unformat_line_input, line_input))
264     return 0;
265
266   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
267     {
268       if (unformat (line_input, "%U - %U",
269                     unformat_ip4_address, &start_addr,
270                     unformat_ip4_address, &end_addr))
271         ;
272       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
273         ;
274       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
275         end_addr = start_addr;
276       else if (unformat (line_input, "twice-nat"))
277         twice_nat = 1;
278       else if (unformat (line_input, "del"))
279         is_add = 0;
280       else
281         {
282           error = clib_error_return (0, "unknown input '%U'",
283                                      format_unformat_error, line_input);
284           goto done;
285         }
286     }
287
288   if (sm->static_mapping_only)
289     {
290       error = clib_error_return (0, "static mapping only mode");
291       goto done;
292     }
293
294   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
295   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
296
297   if (end_host_order < start_host_order)
298     {
299       error = clib_error_return (0, "end address less than start address");
300       goto done;
301     }
302
303   count = (end_host_order - start_host_order) + 1;
304
305   if (count > 1024)
306     nat_log_info ("%U - %U, %d addresses...",
307                   format_ip4_address, &start_addr,
308                   format_ip4_address, &end_addr, count);
309
310   this_addr = start_addr;
311
312   for (i = 0; i < count; i++)
313     {
314       if (is_add)
315         rv = snat_add_address (sm, &this_addr, vrf_id, twice_nat);
316       else
317         rv = snat_del_address (sm, this_addr, 0, twice_nat);
318
319       switch (rv)
320         {
321         case VNET_API_ERROR_VALUE_EXIST:
322           error = clib_error_return (0, "NAT address already in use.");
323           goto done;
324         case VNET_API_ERROR_NO_SUCH_ENTRY:
325           error = clib_error_return (0, "NAT address not exist.");
326           goto done;
327         case VNET_API_ERROR_UNSPECIFIED:
328           error =
329             clib_error_return (0, "NAT address used in static mapping.");
330           goto done;
331         case VNET_API_ERROR_FEATURE_DISABLED:
332           error =
333             clib_error_return (0,
334                                "twice NAT available only for endpoint-dependent mode.");
335           goto done;
336         default:
337           break;
338         }
339
340       if (sm->out2in_dpo)
341         nat44_add_del_address_dpo (this_addr, is_add);
342
343       increment_v4_address (&this_addr);
344     }
345
346 done:
347   unformat_free (line_input);
348
349   return error;
350 }
351
352 static clib_error_t *
353 nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
354                                  vlib_cli_command_t * cmd)
355 {
356   snat_main_t *sm = &snat_main;
357   snat_address_t *ap;
358
359   if (sm->deterministic)
360     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
361
362   vlib_cli_output (vm, "NAT44 pool addresses:");
363   /* *INDENT-OFF* */
364   vec_foreach (ap, sm->addresses)
365     {
366       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
367       if (ap->fib_index != ~0)
368           vlib_cli_output (vm, "  tenant VRF: %u",
369             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
370       else
371         vlib_cli_output (vm, "  tenant VRF independent");
372     #define _(N, i, n, s) \
373       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
374       foreach_snat_protocol
375     #undef _
376     }
377   vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
378   vec_foreach (ap, sm->twice_nat_addresses)
379     {
380       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
381       if (ap->fib_index != ~0)
382           vlib_cli_output (vm, "  tenant VRF: %u",
383             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
384       else
385         vlib_cli_output (vm, "  tenant VRF independent");
386     #define _(N, i, n, s) \
387       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
388       foreach_snat_protocol
389     #undef _
390     }
391   /* *INDENT-ON* */
392   return 0;
393 }
394
395 static clib_error_t *
396 snat_feature_command_fn (vlib_main_t * vm,
397                          unformat_input_t * input, vlib_cli_command_t * cmd)
398 {
399   unformat_input_t _line_input, *line_input = &_line_input;
400   vnet_main_t *vnm = vnet_get_main ();
401   clib_error_t *error = 0;
402   u32 sw_if_index;
403   u32 *inside_sw_if_indices = 0;
404   u32 *outside_sw_if_indices = 0;
405   u8 is_output_feature = 0;
406   int is_del = 0;
407   int i;
408
409   sw_if_index = ~0;
410
411   /* Get a line of input. */
412   if (!unformat_user (input, unformat_line_input, line_input))
413     return 0;
414
415   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
416     {
417       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
418                     vnm, &sw_if_index))
419         vec_add1 (inside_sw_if_indices, sw_if_index);
420       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
421                          vnm, &sw_if_index))
422         vec_add1 (outside_sw_if_indices, sw_if_index);
423       else if (unformat (line_input, "output-feature"))
424         is_output_feature = 1;
425       else if (unformat (line_input, "del"))
426         is_del = 1;
427       else
428         {
429           error = clib_error_return (0, "unknown input '%U'",
430                                      format_unformat_error, line_input);
431           goto done;
432         }
433     }
434
435   if (vec_len (inside_sw_if_indices))
436     {
437       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
438         {
439           sw_if_index = inside_sw_if_indices[i];
440           if (is_output_feature)
441             {
442               if (snat_interface_add_del_output_feature
443                   (sw_if_index, 1, is_del))
444                 {
445                   error = clib_error_return (0, "%s %U failed",
446                                              is_del ? "del" : "add",
447                                              format_vnet_sw_if_index_name,
448                                              vnm, sw_if_index);
449                   goto done;
450                 }
451             }
452           else
453             {
454               if (snat_interface_add_del (sw_if_index, 1, is_del))
455                 {
456                   error = clib_error_return (0, "%s %U failed",
457                                              is_del ? "del" : "add",
458                                              format_vnet_sw_if_index_name,
459                                              vnm, sw_if_index);
460                   goto done;
461                 }
462             }
463         }
464     }
465
466   if (vec_len (outside_sw_if_indices))
467     {
468       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
469         {
470           sw_if_index = outside_sw_if_indices[i];
471           if (is_output_feature)
472             {
473               if (snat_interface_add_del_output_feature
474                   (sw_if_index, 0, is_del))
475                 {
476                   error = clib_error_return (0, "%s %U failed",
477                                              is_del ? "del" : "add",
478                                              format_vnet_sw_if_index_name,
479                                              vnm, sw_if_index);
480                   goto done;
481                 }
482             }
483           else
484             {
485               if (snat_interface_add_del (sw_if_index, 0, is_del))
486                 {
487                   error = clib_error_return (0, "%s %U failed",
488                                              is_del ? "del" : "add",
489                                              format_vnet_sw_if_index_name,
490                                              vnm, sw_if_index);
491                   goto done;
492                 }
493             }
494         }
495     }
496
497 done:
498   unformat_free (line_input);
499   vec_free (inside_sw_if_indices);
500   vec_free (outside_sw_if_indices);
501
502   return error;
503 }
504
505 static clib_error_t *
506 nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
507                                   vlib_cli_command_t * cmd)
508 {
509   snat_main_t *sm = &snat_main;
510   snat_interface_t *i;
511   vnet_main_t *vnm = vnet_get_main ();
512
513   vlib_cli_output (vm, "NAT44 interfaces:");
514   /* *INDENT-OFF* */
515   pool_foreach (i, sm->interfaces,
516   ({
517     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
518                      i->sw_if_index,
519                      (nat_interface_is_inside(i) &&
520                       nat_interface_is_outside(i)) ? "in out" :
521                      (nat_interface_is_inside(i) ? "in" : "out"));
522   }));
523
524   pool_foreach (i, sm->output_feature_interfaces,
525   ({
526     vlib_cli_output (vm, " %U output-feature %s",
527                      format_vnet_sw_if_index_name, vnm,
528                      i->sw_if_index,
529                      (nat_interface_is_inside(i) &&
530                       nat_interface_is_outside(i)) ? "in out" :
531                      (nat_interface_is_inside(i) ? "in" : "out"));
532   }));
533   /* *INDENT-ON* */
534
535   return 0;
536 }
537
538 static clib_error_t *
539 add_static_mapping_command_fn (vlib_main_t * vm,
540                                unformat_input_t * input,
541                                vlib_cli_command_t * cmd)
542 {
543   unformat_input_t _line_input, *line_input = &_line_input;
544   snat_main_t *sm = &snat_main;
545   clib_error_t *error = 0;
546   ip4_address_t l_addr, e_addr;
547   u32 l_port = 0, e_port = 0, vrf_id = ~0;
548   int is_add = 1;
549   int addr_only = 1;
550   u32 sw_if_index = ~0;
551   vnet_main_t *vnm = vnet_get_main ();
552   int rv;
553   snat_protocol_t proto = ~0;
554   u8 proto_set = 0;
555   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
556   u8 out2in_only = 0;
557
558   if (sm->deterministic)
559     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
560
561   /* Get a line of input. */
562   if (!unformat_user (input, unformat_line_input, line_input))
563     return 0;
564
565   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
566     {
567       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
568                     &l_port))
569         addr_only = 0;
570       else
571         if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
572         ;
573       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
574                          &e_addr, &e_port))
575         addr_only = 0;
576       else if (unformat (line_input, "external %U", unformat_ip4_address,
577                          &e_addr))
578         ;
579       else if (unformat (line_input, "external %U %u",
580                          unformat_vnet_sw_interface, vnm, &sw_if_index,
581                          &e_port))
582         addr_only = 0;
583
584       else if (unformat (line_input, "external %U",
585                          unformat_vnet_sw_interface, vnm, &sw_if_index))
586         ;
587       else if (unformat (line_input, "vrf %u", &vrf_id))
588         ;
589       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
590         proto_set = 1;
591       else if (unformat (line_input, "twice-nat"))
592         twice_nat = TWICE_NAT;
593       else if (unformat (line_input, "self-twice-nat"))
594         twice_nat = TWICE_NAT_SELF;
595       else if (unformat (line_input, "out2in-only"))
596         out2in_only = 1;
597       else if (unformat (line_input, "del"))
598         is_add = 0;
599       else
600         {
601           error = clib_error_return (0, "unknown input: '%U'",
602                                      format_unformat_error, line_input);
603           goto done;
604         }
605     }
606
607   if (twice_nat && addr_only)
608     {
609       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
610       goto done;
611     }
612
613   if (!addr_only && !proto_set)
614     {
615       error = clib_error_return (0, "missing protocol");
616       goto done;
617     }
618
619   rv = snat_add_static_mapping (l_addr, e_addr, (u16) l_port, (u16) e_port,
620                                 vrf_id, addr_only, sw_if_index, proto, is_add,
621                                 twice_nat, out2in_only, 0);
622
623   switch (rv)
624     {
625     case VNET_API_ERROR_INVALID_VALUE:
626       error = clib_error_return (0, "External port already in use.");
627       goto done;
628     case VNET_API_ERROR_NO_SUCH_ENTRY:
629       if (is_add)
630         error = clib_error_return (0, "External addres must be allocated.");
631       else
632         error = clib_error_return (0, "Mapping not exist.");
633       goto done;
634     case VNET_API_ERROR_NO_SUCH_FIB:
635       error = clib_error_return (0, "No such VRF id.");
636       goto done;
637     case VNET_API_ERROR_VALUE_EXIST:
638       error = clib_error_return (0, "Mapping already exist.");
639       goto done;
640     case VNET_API_ERROR_FEATURE_DISABLED:
641       error =
642         clib_error_return (0,
643                            "twice-nat/out2in-only available only for endpoint-dependent mode.");
644       goto done;
645     default:
646       break;
647     }
648
649 done:
650   unformat_free (line_input);
651
652   return error;
653 }
654
655 static clib_error_t *
656 add_identity_mapping_command_fn (vlib_main_t * vm,
657                                  unformat_input_t * input,
658                                  vlib_cli_command_t * cmd)
659 {
660   unformat_input_t _line_input, *line_input = &_line_input;
661   snat_main_t *sm = &snat_main;
662   clib_error_t *error = 0;
663   ip4_address_t addr;
664   u32 port = 0, vrf_id = ~0;
665   int is_add = 1;
666   int addr_only = 1;
667   u32 sw_if_index = ~0;
668   vnet_main_t *vnm = vnet_get_main ();
669   int rv;
670   snat_protocol_t proto;
671
672   if (sm->deterministic)
673     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
674
675   addr.as_u32 = 0;
676
677   /* Get a line of input. */
678   if (!unformat_user (input, unformat_line_input, line_input))
679     return 0;
680
681   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
682     {
683       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
684         ;
685       else if (unformat (line_input, "external %U",
686                          unformat_vnet_sw_interface, vnm, &sw_if_index))
687         ;
688       else if (unformat (line_input, "vrf %u", &vrf_id))
689         ;
690       else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
691                          &port))
692         addr_only = 0;
693       else if (unformat (line_input, "del"))
694         is_add = 0;
695       else
696         {
697           error = clib_error_return (0, "unknown input: '%U'",
698                                      format_unformat_error, line_input);
699           goto done;
700         }
701     }
702
703   rv = snat_add_static_mapping (addr, addr, (u16) port, (u16) port,
704                                 vrf_id, addr_only, sw_if_index, proto, is_add,
705                                 0, 0, 0);
706
707   switch (rv)
708     {
709     case VNET_API_ERROR_INVALID_VALUE:
710       error = clib_error_return (0, "External port already in use.");
711       goto done;
712     case VNET_API_ERROR_NO_SUCH_ENTRY:
713       if (is_add)
714         error = clib_error_return (0, "External addres must be allocated.");
715       else
716         error = clib_error_return (0, "Mapping not exist.");
717       goto done;
718     case VNET_API_ERROR_NO_SUCH_FIB:
719       error = clib_error_return (0, "No such VRF id.");
720       goto done;
721     case VNET_API_ERROR_VALUE_EXIST:
722       error = clib_error_return (0, "Mapping already exist.");
723       goto done;
724     default:
725       break;
726     }
727
728 done:
729   unformat_free (line_input);
730
731   return error;
732 }
733
734 static clib_error_t *
735 add_lb_static_mapping_command_fn (vlib_main_t * vm,
736                                   unformat_input_t * input,
737                                   vlib_cli_command_t * cmd)
738 {
739   unformat_input_t _line_input, *line_input = &_line_input;
740   snat_main_t *sm = &snat_main;
741   clib_error_t *error = 0;
742   ip4_address_t l_addr, e_addr;
743   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
744   int is_add = 1;
745   int rv;
746   snat_protocol_t proto;
747   u8 proto_set = 0;
748   nat44_lb_addr_port_t *locals = 0, local;
749   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
750   u8 out2in_only = 0;
751
752   if (sm->deterministic)
753     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
754
755   /* Get a line of input. */
756   if (!unformat_user (input, unformat_line_input, line_input))
757     return 0;
758
759   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
760     {
761       if (unformat (line_input, "local %U:%u probability %u",
762                     unformat_ip4_address, &l_addr, &l_port, &probability))
763         {
764           memset (&local, 0, sizeof (local));
765           local.addr = l_addr;
766           local.port = (u16) l_port;
767           local.probability = (u8) probability;
768           vec_add1 (locals, local);
769         }
770       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
771                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
772                          &probability))
773         {
774           memset (&local, 0, sizeof (local));
775           local.addr = l_addr;
776           local.port = (u16) l_port;
777           local.probability = (u8) probability;
778           local.vrf_id = vrf_id;
779           vec_add1 (locals, local);
780         }
781       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
782                          &e_addr, &e_port))
783         ;
784       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
785                          &proto))
786         proto_set = 1;
787       else if (unformat (line_input, "twice-nat"))
788         twice_nat = TWICE_NAT;
789       else if (unformat (line_input, "self-twice-nat"))
790         twice_nat = TWICE_NAT_SELF;
791       else if (unformat (line_input, "out2in-only"))
792         out2in_only = 1;
793       else if (unformat (line_input, "del"))
794         is_add = 0;
795       else
796         {
797           error = clib_error_return (0, "unknown input: '%U'",
798                                      format_unformat_error, line_input);
799           goto done;
800         }
801     }
802
803   if (vec_len (locals) < 2)
804     {
805       error = clib_error_return (0, "at least two local must be set");
806       goto done;
807     }
808
809   if (!proto_set)
810     {
811       error = clib_error_return (0, "missing protocol");
812       goto done;
813     }
814
815   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, locals,
816                                         is_add, twice_nat, out2in_only, 0);
817
818   switch (rv)
819     {
820     case VNET_API_ERROR_INVALID_VALUE:
821       error = clib_error_return (0, "External port already in use.");
822       goto done;
823     case VNET_API_ERROR_NO_SUCH_ENTRY:
824       if (is_add)
825         error = clib_error_return (0, "External addres must be allocated.");
826       else
827         error = clib_error_return (0, "Mapping not exist.");
828       goto done;
829     case VNET_API_ERROR_VALUE_EXIST:
830       error = clib_error_return (0, "Mapping already exist.");
831       goto done;
832     case VNET_API_ERROR_FEATURE_DISABLED:
833       error =
834         clib_error_return (0, "Available only for endpoint-dependent mode.");
835       goto done;
836     default:
837       break;
838     }
839
840 done:
841   unformat_free (line_input);
842   vec_free (locals);
843
844   return error;
845 }
846
847 static clib_error_t *
848 nat44_show_static_mappings_command_fn (vlib_main_t * vm,
849                                        unformat_input_t * input,
850                                        vlib_cli_command_t * cmd)
851 {
852   snat_main_t *sm = &snat_main;
853   snat_static_mapping_t *m;
854   snat_static_map_resolve_t *rp;
855
856   if (sm->deterministic)
857     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
858
859   vlib_cli_output (vm, "NAT44 static mappings:");
860   /* *INDENT-OFF* */
861   pool_foreach (m, sm->static_mappings,
862   ({
863     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
864   }));
865   vec_foreach (rp, sm->to_resolve)
866     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
867   /* *INDENT-ON* */
868
869   return 0;
870 }
871
872 static clib_error_t *
873 snat_add_interface_address_command_fn (vlib_main_t * vm,
874                                        unformat_input_t * input,
875                                        vlib_cli_command_t * cmd)
876 {
877   snat_main_t *sm = &snat_main;
878   unformat_input_t _line_input, *line_input = &_line_input;
879   u32 sw_if_index;
880   int rv;
881   int is_del = 0;
882   clib_error_t *error = 0;
883   u8 twice_nat = 0;
884
885   if (sm->deterministic)
886     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
887
888   /* Get a line of input. */
889   if (!unformat_user (input, unformat_line_input, line_input))
890     return 0;
891
892   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
893     {
894       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
895                     sm->vnet_main, &sw_if_index))
896         ;
897       else if (unformat (line_input, "twice-nat"))
898         twice_nat = 1;
899       else if (unformat (line_input, "del"))
900         is_del = 1;
901       else
902         {
903           error = clib_error_return (0, "unknown input '%U'",
904                                      format_unformat_error, line_input);
905           goto done;
906         }
907     }
908
909   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
910
911   switch (rv)
912     {
913     case 0:
914       break;
915
916     default:
917       error = clib_error_return (0, "snat_add_interface_address returned %d",
918                                  rv);
919       goto done;
920     }
921
922 done:
923   unformat_free (line_input);
924
925   return error;
926 }
927
928 static clib_error_t *
929 nat44_show_interface_address_command_fn (vlib_main_t * vm,
930                                          unformat_input_t * input,
931                                          vlib_cli_command_t * cmd)
932 {
933   snat_main_t *sm = &snat_main;
934   vnet_main_t *vnm = vnet_get_main ();
935   u32 *sw_if_index;
936
937   if (sm->deterministic)
938     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
939
940   /* *INDENT-OFF* */
941   vlib_cli_output (vm, "NAT44 pool address interfaces:");
942   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
943     {
944       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
945                        *sw_if_index);
946     }
947   vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:");
948   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
949     {
950       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
951                        *sw_if_index);
952     }
953   /* *INDENT-ON* */
954
955   return 0;
956 }
957
958 static clib_error_t *
959 nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
960                                 vlib_cli_command_t * cmd)
961 {
962   int verbose = 0;
963   snat_main_t *sm = &snat_main;
964   snat_main_per_thread_data_t *tsm;
965   snat_user_t *u;
966   int i = 0;
967
968   if (sm->deterministic)
969     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
970
971   if (unformat (input, "detail"))
972     verbose = 1;
973
974   vlib_cli_output (vm, "NAT44 sessions:");
975
976   /* *INDENT-OFF* */
977   vec_foreach_index (i, sm->per_thread_data)
978     {
979       tsm = vec_elt_at_index (sm->per_thread_data, i);
980
981       vlib_cli_output (vm, "-------- thread %d %s --------\n",
982                        i, vlib_worker_threads[i].name);
983       pool_foreach (u, tsm->users,
984       ({
985         vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, verbose);
986       }));
987     }
988   /* *INDENT-ON* */
989
990   return 0;
991 }
992
993 static clib_error_t *
994 nat44_del_session_command_fn (vlib_main_t * vm,
995                               unformat_input_t * input,
996                               vlib_cli_command_t * cmd)
997 {
998   snat_main_t *sm = &snat_main;
999   unformat_input_t _line_input, *line_input = &_line_input;
1000   int is_in = 0, is_ed = 0;
1001   clib_error_t *error = 0;
1002   ip4_address_t addr, eh_addr;
1003   u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
1004   snat_protocol_t proto;
1005   int rv;
1006
1007   if (sm->deterministic)
1008     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1009
1010   /* Get a line of input. */
1011   if (!unformat_user (input, unformat_line_input, line_input))
1012     return 0;
1013
1014   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1015     {
1016       if (unformat
1017           (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
1018            unformat_snat_protocol, &proto))
1019         ;
1020       else if (unformat (line_input, "in"))
1021         {
1022           is_in = 1;
1023           vrf_id = sm->inside_vrf_id;
1024         }
1025       else if (unformat (line_input, "out"))
1026         {
1027           is_in = 0;
1028           vrf_id = sm->outside_vrf_id;
1029         }
1030       else if (unformat (line_input, "vrf %u", &vrf_id))
1031         ;
1032       else
1033         if (unformat
1034             (line_input, "external-host %U:%u", unformat_ip4_address,
1035              &eh_addr, &eh_port))
1036         is_ed = 1;
1037       else
1038         {
1039           error = clib_error_return (0, "unknown input '%U'",
1040                                      format_unformat_error, line_input);
1041           goto done;
1042         }
1043     }
1044
1045   if (is_ed)
1046     rv =
1047       nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port,
1048                             snat_proto_to_ip_proto (proto), vrf_id, is_in);
1049   else
1050     rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
1051
1052   switch (rv)
1053     {
1054     case 0:
1055       break;
1056
1057     default:
1058       error = clib_error_return (0, "nat44_del_session returned %d", rv);
1059       goto done;
1060     }
1061
1062 done:
1063   unformat_free (line_input);
1064
1065   return error;
1066 }
1067
1068 static clib_error_t *
1069 snat_forwarding_set_command_fn (vlib_main_t * vm,
1070                                 unformat_input_t * input,
1071                                 vlib_cli_command_t * cmd)
1072 {
1073   snat_main_t *sm = &snat_main;
1074   unformat_input_t _line_input, *line_input = &_line_input;
1075   u8 forwarding_enable;
1076   u8 forwarding_enable_set = 0;
1077   clib_error_t *error = 0;
1078
1079   if (sm->deterministic)
1080     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1081
1082   /* Get a line of input. */
1083   if (!unformat_user (input, unformat_line_input, line_input))
1084     return clib_error_return (0, "'enable' or 'disable' expected");
1085
1086   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1087     {
1088       if (!forwarding_enable_set && unformat (line_input, "enable"))
1089         {
1090           forwarding_enable = 1;
1091           forwarding_enable_set = 1;
1092         }
1093       else if (!forwarding_enable_set && unformat (line_input, "disable"))
1094         {
1095           forwarding_enable = 0;
1096           forwarding_enable_set = 1;
1097         }
1098       else
1099         {
1100           error = clib_error_return (0, "unknown input '%U'",
1101                                      format_unformat_error, line_input);
1102           goto done;
1103         }
1104     }
1105
1106   if (!forwarding_enable_set)
1107     {
1108       error = clib_error_return (0, "'enable' or 'disable' expected");
1109       goto done;
1110     }
1111
1112   sm->forwarding_enabled = forwarding_enable;
1113
1114 done:
1115   unformat_free (line_input);
1116
1117   return error;
1118 }
1119
1120 static clib_error_t *
1121 snat_det_map_command_fn (vlib_main_t * vm,
1122                          unformat_input_t * input, vlib_cli_command_t * cmd)
1123 {
1124   snat_main_t *sm = &snat_main;
1125   unformat_input_t _line_input, *line_input = &_line_input;
1126   ip4_address_t in_addr, out_addr;
1127   u32 in_plen, out_plen;
1128   int is_add = 1, rv;
1129   clib_error_t *error = 0;
1130
1131   if (!sm->deterministic)
1132     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1133
1134   /* Get a line of input. */
1135   if (!unformat_user (input, unformat_line_input, line_input))
1136     return 0;
1137
1138   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1139     {
1140       if (unformat
1141           (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
1142         ;
1143       else
1144         if (unformat
1145             (line_input, "out %U/%u", unformat_ip4_address, &out_addr,
1146              &out_plen))
1147         ;
1148       else if (unformat (line_input, "del"))
1149         is_add = 0;
1150       else
1151         {
1152           error = clib_error_return (0, "unknown input '%U'",
1153                                      format_unformat_error, line_input);
1154           goto done;
1155         }
1156     }
1157
1158   rv = snat_det_add_map (sm, &in_addr, (u8) in_plen, &out_addr, (u8) out_plen,
1159                          is_add);
1160
1161   if (rv)
1162     {
1163       error = clib_error_return (0, "snat_det_add_map return %d", rv);
1164       goto done;
1165     }
1166
1167 done:
1168   unformat_free (line_input);
1169
1170   return error;
1171 }
1172
1173 static clib_error_t *
1174 nat44_det_show_mappings_command_fn (vlib_main_t * vm,
1175                                     unformat_input_t * input,
1176                                     vlib_cli_command_t * cmd)
1177 {
1178   snat_main_t *sm = &snat_main;
1179   snat_det_map_t *dm;
1180
1181   if (!sm->deterministic)
1182     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1183
1184   vlib_cli_output (vm, "NAT44 deterministic mappings:");
1185   /* *INDENT-OFF* */
1186   pool_foreach (dm, sm->det_maps,
1187   ({
1188     vlib_cli_output (vm, " in %U/%d out %U/%d\n",
1189                      format_ip4_address, &dm->in_addr, dm->in_plen,
1190                      format_ip4_address, &dm->out_addr, dm->out_plen);
1191     vlib_cli_output (vm, "  outside address sharing ratio: %d\n",
1192                      dm->sharing_ratio);
1193     vlib_cli_output (vm, "  number of ports per inside host: %d\n",
1194                      dm->ports_per_host);
1195     vlib_cli_output (vm, "  sessions number: %d\n", dm->ses_num);
1196   }));
1197   /* *INDENT-ON* */
1198
1199   return 0;
1200 }
1201
1202 static clib_error_t *
1203 snat_det_forward_command_fn (vlib_main_t * vm,
1204                              unformat_input_t * input,
1205                              vlib_cli_command_t * cmd)
1206 {
1207   snat_main_t *sm = &snat_main;
1208   unformat_input_t _line_input, *line_input = &_line_input;
1209   ip4_address_t in_addr, out_addr;
1210   u16 lo_port;
1211   snat_det_map_t *dm;
1212   clib_error_t *error = 0;
1213
1214   if (!sm->deterministic)
1215     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1216
1217   /* Get a line of input. */
1218   if (!unformat_user (input, unformat_line_input, line_input))
1219     return 0;
1220
1221   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1222     {
1223       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
1224         ;
1225       else
1226         {
1227           error = clib_error_return (0, "unknown input '%U'",
1228                                      format_unformat_error, line_input);
1229           goto done;
1230         }
1231     }
1232
1233   dm = snat_det_map_by_user (sm, &in_addr);
1234   if (!dm)
1235     vlib_cli_output (vm, "no match");
1236   else
1237     {
1238       snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
1239       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
1240                        lo_port, lo_port + dm->ports_per_host - 1);
1241     }
1242
1243 done:
1244   unformat_free (line_input);
1245
1246   return error;
1247 }
1248
1249 static clib_error_t *
1250 snat_det_reverse_command_fn (vlib_main_t * vm,
1251                              unformat_input_t * input,
1252                              vlib_cli_command_t * cmd)
1253 {
1254   snat_main_t *sm = &snat_main;
1255   unformat_input_t _line_input, *line_input = &_line_input;
1256   ip4_address_t in_addr, out_addr;
1257   u32 out_port;
1258   snat_det_map_t *dm;
1259   clib_error_t *error = 0;
1260
1261   if (!sm->deterministic)
1262     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1263
1264   /* Get a line of input. */
1265   if (!unformat_user (input, unformat_line_input, line_input))
1266     return 0;
1267
1268   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1269     {
1270       if (unformat
1271           (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
1272         ;
1273       else
1274         {
1275           error = clib_error_return (0, "unknown input '%U'",
1276                                      format_unformat_error, line_input);
1277           goto done;
1278         }
1279     }
1280
1281   if (out_port < 1024 || out_port > 65535)
1282     {
1283       error = clib_error_return (0, "wrong port, must be <1024-65535>");
1284       goto done;
1285     }
1286
1287   dm = snat_det_map_by_out (sm, &out_addr);
1288   if (!dm)
1289     vlib_cli_output (vm, "no match");
1290   else
1291     {
1292       snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
1293       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
1294     }
1295
1296 done:
1297   unformat_free (line_input);
1298
1299   return error;
1300 }
1301
1302 static clib_error_t *
1303 set_timeout_command_fn (vlib_main_t * vm,
1304                         unformat_input_t * input, vlib_cli_command_t * cmd)
1305 {
1306   snat_main_t *sm = &snat_main;
1307   unformat_input_t _line_input, *line_input = &_line_input;
1308   clib_error_t *error = 0;
1309
1310   if (!sm->deterministic)
1311     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1312
1313   /* Get a line of input. */
1314   if (!unformat_user (input, unformat_line_input, line_input))
1315     return 0;
1316
1317   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1318     {
1319       if (unformat (line_input, "udp %u", &sm->udp_timeout))
1320         ;
1321       else if (unformat (line_input, "tcp-established %u",
1322                          &sm->tcp_established_timeout))
1323         ;
1324       else if (unformat (line_input, "tcp-transitory %u",
1325                          &sm->tcp_transitory_timeout))
1326         ;
1327       else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
1328         ;
1329       else if (unformat (line_input, "reset"))
1330         {
1331           sm->udp_timeout = SNAT_UDP_TIMEOUT;
1332           sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1333           sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1334           sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1335         }
1336       else
1337         {
1338           error = clib_error_return (0, "unknown input '%U'",
1339                                      format_unformat_error, line_input);
1340           goto done;
1341         }
1342     }
1343
1344 done:
1345   unformat_free (line_input);
1346
1347   return error;
1348 }
1349
1350 static clib_error_t *
1351 nat44_det_show_timeouts_command_fn (vlib_main_t * vm,
1352                                     unformat_input_t * input,
1353                                     vlib_cli_command_t * cmd)
1354 {
1355   snat_main_t *sm = &snat_main;
1356
1357   if (!sm->deterministic)
1358     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1359
1360   vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
1361   vlib_cli_output (vm, "tcp-established timeout: %dsec",
1362                    sm->tcp_established_timeout);
1363   vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
1364                    sm->tcp_transitory_timeout);
1365   vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
1366
1367   return 0;
1368 }
1369
1370 static clib_error_t *
1371 nat44_det_show_sessions_command_fn (vlib_main_t * vm,
1372                                     unformat_input_t * input,
1373                                     vlib_cli_command_t * cmd)
1374 {
1375   snat_main_t *sm = &snat_main;
1376   snat_det_map_t *dm;
1377   snat_det_session_t *ses;
1378   int i;
1379
1380   if (!sm->deterministic)
1381     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1382
1383   vlib_cli_output (vm, "NAT44 deterministic sessions:");
1384   /* *INDENT-OFF* */
1385   pool_foreach (dm, sm->det_maps,
1386   ({
1387     vec_foreach_index (i, dm->sessions)
1388       {
1389         ses = vec_elt_at_index (dm->sessions, i);
1390         if (ses->in_port)
1391           vlib_cli_output (vm, "  %U", format_det_map_ses, dm, ses, &i);
1392       }
1393   }));
1394   /* *INDENT-ON* */
1395   return 0;
1396 }
1397
1398 static clib_error_t *
1399 snat_det_close_session_out_fn (vlib_main_t * vm,
1400                                unformat_input_t * input,
1401                                vlib_cli_command_t * cmd)
1402 {
1403   snat_main_t *sm = &snat_main;
1404   unformat_input_t _line_input, *line_input = &_line_input;
1405   ip4_address_t out_addr, ext_addr, in_addr;
1406   u32 out_port, ext_port;
1407   snat_det_map_t *dm;
1408   snat_det_session_t *ses;
1409   snat_det_out_key_t key;
1410   clib_error_t *error = 0;
1411
1412   if (!sm->deterministic)
1413     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1414
1415   /* Get a line of input. */
1416   if (!unformat_user (input, unformat_line_input, line_input))
1417     return 0;
1418
1419   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1420     {
1421       if (unformat (line_input, "%U:%d %U:%d",
1422                     unformat_ip4_address, &out_addr, &out_port,
1423                     unformat_ip4_address, &ext_addr, &ext_port))
1424         ;
1425       else
1426         {
1427           error = clib_error_return (0, "unknown input '%U'",
1428                                      format_unformat_error, line_input);
1429           goto done;
1430         }
1431     }
1432
1433   unformat_free (line_input);
1434
1435   dm = snat_det_map_by_out (sm, &out_addr);
1436   if (!dm)
1437     vlib_cli_output (vm, "no match");
1438   else
1439     {
1440       snat_det_reverse (dm, &ext_addr, (u16) out_port, &in_addr);
1441       key.ext_host_addr = out_addr;
1442       key.ext_host_port = ntohs ((u16) ext_port);
1443       key.out_port = ntohs ((u16) out_port);
1444       ses = snat_det_get_ses_by_out (dm, &out_addr, key.as_u64);
1445       if (!ses)
1446         vlib_cli_output (vm, "no match");
1447       else
1448         snat_det_ses_close (dm, ses);
1449     }
1450
1451 done:
1452   unformat_free (line_input);
1453
1454   return error;
1455 }
1456
1457 static clib_error_t *
1458 snat_det_close_session_in_fn (vlib_main_t * vm,
1459                               unformat_input_t * input,
1460                               vlib_cli_command_t * cmd)
1461 {
1462   snat_main_t *sm = &snat_main;
1463   unformat_input_t _line_input, *line_input = &_line_input;
1464   ip4_address_t in_addr, ext_addr;
1465   u32 in_port, ext_port;
1466   snat_det_map_t *dm;
1467   snat_det_session_t *ses;
1468   snat_det_out_key_t key;
1469   clib_error_t *error = 0;
1470
1471   if (!sm->deterministic)
1472     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1473
1474   /* Get a line of input. */
1475   if (!unformat_user (input, unformat_line_input, line_input))
1476     return 0;
1477
1478   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1479     {
1480       if (unformat (line_input, "%U:%d %U:%d",
1481                     unformat_ip4_address, &in_addr, &in_port,
1482                     unformat_ip4_address, &ext_addr, &ext_port))
1483         ;
1484       else
1485         {
1486           error = clib_error_return (0, "unknown input '%U'",
1487                                      format_unformat_error, line_input);
1488           goto done;
1489         }
1490     }
1491
1492   unformat_free (line_input);
1493
1494   dm = snat_det_map_by_user (sm, &in_addr);
1495   if (!dm)
1496     vlib_cli_output (vm, "no match");
1497   else
1498     {
1499       key.ext_host_addr = ext_addr;
1500       key.ext_host_port = ntohs ((u16) ext_port);
1501       ses =
1502         snat_det_find_ses_by_in (dm, &in_addr, ntohs ((u16) in_port), key);
1503       if (!ses)
1504         vlib_cli_output (vm, "no match");
1505       else
1506         snat_det_ses_close (dm, ses);
1507     }
1508
1509 done:
1510   unformat_free (line_input);
1511
1512   return error;
1513 }
1514 /* *INDENT-OFF* */
1515
1516 /*?
1517  * @cliexpar
1518  * @cliexstart{set snat workers}
1519  * Set NAT workers if 2 or more workers available, use:
1520  *  vpp# set snat workers 0-2,5
1521  * @cliexend
1522 ?*/
1523 VLIB_CLI_COMMAND (set_workers_command, static) = {
1524   .path = "set nat workers",
1525   .function = set_workers_command_fn,
1526   .short_help = "set nat workers <workers-list>",
1527 };
1528
1529 /*?
1530  * @cliexpar
1531  * @cliexstart{show nat workers}
1532  * Show NAT workers.
1533  *  vpp# show nat workers:
1534  *  2 workers
1535  *    vpp_wk_0
1536  *    vpp_wk_1
1537  * @cliexend
1538 ?*/
1539 VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
1540   .path = "show nat workers",
1541   .short_help = "show nat workers",
1542   .function = nat_show_workers_commnad_fn,
1543 };
1544
1545 /*?
1546  * @cliexpar
1547  * @cliexstart{snat ipfix logging}
1548  * To enable NAT IPFIX logging use:
1549  *  vpp# nat ipfix logging
1550  * To set IPFIX exporter use:
1551  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
1552  * @cliexend
1553 ?*/
1554 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
1555   .path = "nat ipfix logging",
1556   .function = snat_ipfix_logging_enable_disable_command_fn,
1557   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
1558 };
1559
1560 /*?
1561  * @cliexpar
1562  * @cliexstart{nat addr-port-assignment-alg}
1563  * Set address and port assignment algorithm
1564  * For the MAP-E CE limit port choice based on PSID use:
1565  *  vpp# nat addr-port-assignment-alg map-e psid 10 psid-offset 6 psid-len 6
1566  * To set standard (default) address and port assignment algorithm use:
1567  *  vpp# nat addr-port-assignment-alg default
1568  * @cliexend
1569 ?*/
1570 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
1571     .path = "nat addr-port-assignment-alg",
1572     .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
1573     .function = nat44_set_alloc_addr_and_port_alg_command_fn,
1574 };
1575
1576 /*?
1577  * @cliexpar
1578  * @cliexstart{show nat44 hash tables}
1579  * Show NAT44 hash tables
1580  * @cliexend
1581 ?*/
1582 VLIB_CLI_COMMAND (nat44_show_hash, static) = {
1583   .path = "show nat44 hash tables",
1584   .short_help = "show nat44 hash tables [detail|verbose]",
1585   .function = nat44_show_hash_commnad_fn,
1586 };
1587
1588 /*?
1589  * @cliexpar
1590  * @cliexstart{nat44 add address}
1591  * Add/delete NAT44 pool address.
1592  * To add NAT44 pool address use:
1593  *  vpp# nat44 add address 172.16.1.3
1594  *  vpp# nat44 add address 172.16.2.2 - 172.16.2.24
1595  * To add NAT44 pool address for specific tenant (identified by VRF id) use:
1596  *  vpp# nat44 add address 172.16.1.3 tenant-vrf 10
1597  * @cliexend
1598 ?*/
1599 VLIB_CLI_COMMAND (add_address_command, static) = {
1600   .path = "nat44 add address",
1601   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
1602                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
1603   .function = add_address_command_fn,
1604 };
1605
1606 /*?
1607  * @cliexpar
1608  * @cliexstart{show nat44 addresses}
1609  * Show NAT44 pool addresses.
1610  * vpp# show nat44 addresses
1611  * NAT44 pool addresses:
1612  * 172.16.2.2
1613  *   tenant VRF independent
1614  *   10 busy udp ports
1615  *   0 busy tcp ports
1616  *   0 busy icmp ports
1617  * 172.16.1.3
1618  *   tenant VRF: 10
1619  *   0 busy udp ports
1620  *   2 busy tcp ports
1621  *   0 busy icmp ports
1622  * NAT44 twice-nat pool addresses:
1623  * 10.20.30.72
1624  *   tenant VRF independent
1625  *   0 busy udp ports
1626  *   0 busy tcp ports
1627  *   0 busy icmp ports
1628  * @cliexend
1629 ?*/
1630 VLIB_CLI_COMMAND (nat44_show_addresses_command, static) = {
1631   .path = "show nat44 addresses",
1632   .short_help = "show nat44 addresses",
1633   .function = nat44_show_addresses_command_fn,
1634 };
1635
1636 /*?
1637  * @cliexpar
1638  * @cliexstart{set interface nat44}
1639  * Enable/disable NAT44 feature on the interface.
1640  * To enable NAT44 feature with local network interface use:
1641  *  vpp# set interface nat44 in GigabitEthernet0/8/0
1642  * To enable NAT44 feature with external network interface use:
1643  *  vpp# set interface nat44 out GigabitEthernet0/a/0
1644  * @cliexend
1645 ?*/
1646 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
1647   .path = "set interface nat44",
1648   .function = snat_feature_command_fn,
1649   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
1650                 "[del]",
1651 };
1652
1653 /*?
1654  * @cliexpar
1655  * @cliexstart{show nat44 interfaces}
1656  * Show interfaces with NAT44 feature.
1657  * vpp# show nat44 interfaces
1658  * NAT44 interfaces:
1659  *  GigabitEthernet0/8/0 in
1660  *  GigabitEthernet0/a/0 out
1661  * @cliexend
1662 ?*/
1663 VLIB_CLI_COMMAND (nat44_show_interfaces_command, static) = {
1664   .path = "show nat44 interfaces",
1665   .short_help = "show nat44 interfaces",
1666   .function = nat44_show_interfaces_command_fn,
1667 };
1668
1669 /*?
1670  * @cliexpar
1671  * @cliexstart{nat44 add static mapping}
1672  * Static mapping allows hosts on the external network to initiate connection
1673  * to to the local network host.
1674  * To create static mapping between local host address 10.0.0.3 port 6303 and
1675  * external address 4.4.4.4 port 3606 for TCP protocol use:
1676  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
1677  * If not runnig "static mapping only" NAT plugin mode use before:
1678  *  vpp# nat44 add address 4.4.4.4
1679  * To create static mapping between local and external address use:
1680  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
1681  * @cliexend
1682 ?*/
1683 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
1684   .path = "nat44 add static mapping",
1685   .function = add_static_mapping_command_fn,
1686   .short_help =
1687     "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
1688     "external <addr> [<port>] [vrf <table-id>] [twice-nat|self-twice-nat] "
1689     "[out2in-only] [del]",
1690 };
1691
1692 /*?
1693  * @cliexpar
1694  * @cliexstart{nat44 add identity mapping}
1695  * Identity mapping translate an IP address to itself.
1696  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
1697  * use:
1698  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
1699  * To create identity mapping for address 10.0.0.3 use:
1700  *  vpp# nat44 add identity mapping 10.0.0.3
1701  * To create identity mapping for DHCP addressed interface use:
1702  *  vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606
1703  * @cliexend
1704 ?*/
1705 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
1706   .path = "nat44 add identity mapping",
1707   .function = add_identity_mapping_command_fn,
1708   .short_help = "nat44 add identity mapping <interface>|<ip4-addr> "
1709     "[<protocol> <port>] [vrf <table-id>] [del]",
1710 };
1711
1712 /*?
1713  * @cliexpar
1714  * @cliexstart{nat44 add load-balancing static mapping}
1715  * Service load balancing using NAT44
1716  * To add static mapping with load balancing for service with external IP
1717  * address 1.2.3.4 and TCP port 80 and mapped to 2 local servers
1718  * 10.100.10.10:8080 and 10.100.10.20:8080 with probability 80% resp. 20% use:
1719  *  vpp# nat44 add load-balancing static mapping protocol tcp external 1.2.3.4:80 local 10.100.10.10:8080 probability 80 local 10.100.10.20:8080 probability 20
1720  * @cliexend
1721 ?*/
1722 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
1723   .path = "nat44 add load-balancing static mapping",
1724   .function = add_lb_static_mapping_command_fn,
1725   .short_help =
1726     "nat44 add load-balancing static mapping protocol tcp|udp "
1727     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
1728     "probability <n> [twice-nat|self-twice-nat] [out2in-only] [del]",
1729 };
1730
1731 /*?
1732  * @cliexpar
1733  * @cliexstart{show nat44 static mappings}
1734  * Show NAT44 static mappings.
1735  * vpp# show nat44 static mappings
1736  * NAT44 static mappings:
1737  *  local 10.0.0.3 external 4.4.4.4 vrf 0
1738  *  tcp local 192.168.0.4:6303 external 4.4.4.3:3606 vrf 0
1739  *  tcp vrf 0 external 1.2.3.4:80  out2in-only
1740  *   local 10.100.10.10:8080 probability 80
1741  *   local 10.100.10.20:8080 probability 20
1742  *  tcp local 10.100.3.8:8080 external 169.10.10.1:80 vrf 0 twice-nat
1743  *  tcp local 10.0.0.10:3603 external GigabitEthernet0/a/0:6306 vrf 10
1744  * @cliexend
1745 ?*/
1746 VLIB_CLI_COMMAND (nat44_show_static_mappings_command, static) = {
1747   .path = "show nat44 static mappings",
1748   .short_help = "show nat44 static mappings",
1749   .function = nat44_show_static_mappings_command_fn,
1750 };
1751
1752 /*?
1753  * @cliexpar
1754  * @cliexstart{nat44 add interface address}
1755  * Use NAT44 pool address from specific interfce
1756  * To add NAT44 pool address from specific interface use:
1757  *  vpp# nat44 add interface address GigabitEthernet0/8/0
1758  * @cliexend
1759 ?*/
1760 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
1761     .path = "nat44 add interface address",
1762     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
1763     .function = snat_add_interface_address_command_fn,
1764 };
1765
1766 /*?
1767  * @cliexpar
1768  * @cliexstart{show nat44 interface address}
1769  * Show NAT44 pool address interfaces
1770  * vpp# show nat44 interface address
1771  * NAT44 pool address interfaces:
1772  *  GigabitEthernet0/a/0
1773  * NAT44 twice-nat pool address interfaces:
1774  *  GigabitEthernet0/8/0
1775  * @cliexend
1776 ?*/
1777 VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
1778   .path = "show nat44 interface address",
1779   .short_help = "show nat44 interface address",
1780   .function = nat44_show_interface_address_command_fn,
1781 };
1782
1783 /*?
1784  * @cliexpar
1785  * @cliexstart{show nat44 sessions}
1786  * Show NAT44 sessions.
1787  * @cliexend
1788 ?*/
1789 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
1790   .path = "show nat44 sessions",
1791   .short_help = "show nat44 sessions [detail]",
1792   .function = nat44_show_sessions_command_fn,
1793 };
1794
1795 /*?
1796  * @cliexpar
1797  * @cliexstart{nat44 del session}
1798  * To administratively delete NAT44 session by inside address and port use:
1799  *  vpp# nat44 del session in 10.0.0.3:6303 tcp
1800  * To administratively delete NAT44 session by outside address and port use:
1801  *  vpp# nat44 del session out 1.0.0.3:6033 udp
1802  * @cliexend
1803 ?*/
1804 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
1805     .path = "nat44 del session",
1806     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
1807     .function = nat44_del_session_command_fn,
1808 };
1809
1810 /*?
1811  * @cliexpar
1812  * @cliexstart{nat44 forwarding}
1813  * Enable or disable forwarding
1814  * Forward packets which don't match existing translation
1815  * or static mapping instead of dropping them.
1816  * To enable forwarding, use:
1817  *  vpp# nat44 forwarding enable
1818  * To disable forwarding, use:
1819  *  vpp# nat44 forwarding disable
1820  * @cliexend
1821 ?*/
1822 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
1823   .path = "nat44 forwarding",
1824   .short_help = "nat44 forwarding enable|disable",
1825   .function = snat_forwarding_set_command_fn,
1826 };
1827
1828 /*?
1829  * @cliexpar
1830  * @cliexstart{nat44 deterministic add}
1831  * Create bijective mapping of inside address to outside address and port range
1832  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
1833  * CGN deployments.
1834  * To create deterministic mapping between inside network 10.0.0.0/18 and
1835  * outside network 1.1.1.0/30 use:
1836  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
1837  * @cliexend
1838 ?*/
1839 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
1840     .path = "nat44 deterministic add",
1841     .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
1842     .function = snat_det_map_command_fn,
1843 };
1844
1845 /*?
1846  * @cliexpar
1847  * @cliexpstart{show nat44 deterministic mappings}
1848  * Show NAT44 deterministic mappings
1849  * vpp# show nat44 deterministic mappings
1850  * NAT44 deterministic mappings:
1851  *  in 10.0.0.0/24 out 1.1.1.1/32
1852  *   outside address sharing ratio: 256
1853  *   number of ports per inside host: 252
1854  *   sessions number: 0
1855  * @cliexend
1856 ?*/
1857 VLIB_CLI_COMMAND (nat44_det_show_mappings_command, static) = {
1858     .path = "show nat44 deterministic mappings",
1859     .short_help = "show nat44 deterministic mappings",
1860     .function = nat44_det_show_mappings_command_fn,
1861 };
1862
1863 /*?
1864  * @cliexpar
1865  * @cliexstart{nat44 deterministic forward}
1866  * Return outside address and port range from inside address for deterministic
1867  * NAT.
1868  * To obtain outside address and port of inside host use:
1869  *  vpp# nat44 deterministic forward 10.0.0.2
1870  *  1.1.1.0:<1054-1068>
1871  * @cliexend
1872 ?*/
1873 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
1874     .path = "nat44 deterministic forward",
1875     .short_help = "nat44 deterministic forward <addr>",
1876     .function = snat_det_forward_command_fn,
1877 };
1878
1879 /*?
1880  * @cliexpar
1881  * @cliexstart{nat44 deterministic reverse}
1882  * Return inside address from outside address and port for deterministic NAT.
1883  * To obtain inside host address from outside address and port use:
1884  *  #vpp nat44 deterministic reverse 1.1.1.1:1276
1885  *  10.0.16.16
1886  * @cliexend
1887 ?*/
1888 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
1889     .path = "nat44 deterministic reverse",
1890     .short_help = "nat44 deterministic reverse <addr>:<port>",
1891     .function = snat_det_reverse_command_fn,
1892 };
1893
1894 /*?
1895  * @cliexpar
1896  * @cliexstart{set nat44 deterministic timeout}
1897  * Set values of timeouts for deterministic NAT (in seconds), use:
1898  *  vpp# set nat44 deterministic timeout udp 120 tcp-established 7500
1899  *  tcp-transitory 250 icmp 90
1900  * To reset default values use:
1901  *  vpp# set nat44 deterministic timeout reset
1902  * @cliexend
1903 ?*/
1904 VLIB_CLI_COMMAND (set_timeout_command, static) = {
1905   .path = "set nat44 deterministic timeout",
1906   .function = set_timeout_command_fn,
1907   .short_help =
1908     "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> "
1909     "tcp-transitory <sec> | icmp <sec> | reset]",
1910 };
1911
1912 /*?
1913  * @cliexpar
1914  * @cliexstart{show nat44 deterministic timeouts}
1915  * Show values of timeouts for deterministic NAT.
1916  * vpp# show nat44 deterministic timeouts
1917  * udp timeout: 300sec
1918  * tcp-established timeout: 7440sec
1919  * tcp-transitory timeout: 240sec
1920  * icmp timeout: 60sec
1921  * @cliexend
1922 ?*/
1923 VLIB_CLI_COMMAND (nat44_det_show_timeouts_command, static) = {
1924   .path = "show nat44 deterministic timeouts",
1925   .short_help = "show nat44 deterministic timeouts",
1926   .function = nat44_det_show_timeouts_command_fn,
1927 };
1928
1929 /*?
1930  * @cliexpar
1931  * @cliexstart{show nat44 deterministic sessions}
1932  * Show NAT44 deterministic sessions.
1933  * vpp# show nat44 deterministic sessions
1934  * NAT44 deterministic sessions:
1935  *   in 10.0.0.3:3005 out 1.1.1.2:1146 external host 172.16.1.2:3006 state: udp-active expire: 306
1936  *   in 10.0.0.3:3000 out 1.1.1.2:1141 external host 172.16.1.2:3001 state: udp-active expire: 306
1937  *   in 10.0.0.4:3005 out 1.1.1.2:1177 external host 172.16.1.2:3006 state: udp-active expire: 306
1938  * @cliexend
1939 ?*/
1940 VLIB_CLI_COMMAND (nat44_det_show_sessions_command, static) = {
1941   .path = "show nat44 deterministic sessions",
1942   .short_help = "show nat44 deterministic sessions",
1943   .function = nat44_det_show_sessions_command_fn,
1944 };
1945
1946 /*?
1947  * @cliexpar
1948  * @cliexstart{nat44 deterministic close session out}
1949  * Close session using outside ip address and port
1950  * and external ip address and port, use:
1951  *  vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
1952  * @cliexend
1953 ?*/
1954 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
1955   .path = "nat44 deterministic close session out",
1956   .short_help = "nat44 deterministic close session out "
1957                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
1958   .function = snat_det_close_session_out_fn,
1959 };
1960
1961 /*?
1962  * @cliexpar
1963  * @cliexstart{nat44 deterministic close session in}
1964  * Close session using inside ip address and port
1965  * and external ip address and port, use:
1966  *  vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
1967  * @cliexend
1968 ?*/
1969 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
1970   .path = "nat44 deterministic close session in",
1971   .short_help = "nat44 deterministic close session in "
1972                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
1973   .function = snat_det_close_session_in_fn,
1974 };
1975
1976 /* *INDENT-ON* */
1977
1978 /*
1979  * fd.io coding-style-patch-verification: ON
1980  *
1981  * Local Variables:
1982  * eval: (c-set-style "gnu")
1983  * End:
1984  */