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