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