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