nat: ED: reduce number of hash tables used
[vpp.git] / src / plugins / nat / nat44_cli.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT44 CLI
18  */
19
20 #include <nat/nat.h>
21 #include <nat/nat_ipfix_logging.h>
22 #include <nat/nat_det.h>
23 #include <nat/nat64.h>
24 #include <nat/nat_inlines.h>
25 #include <nat/nat44/inlines.h>
26 #include <nat/nat_affinity.h>
27 #include <vnet/fib/fib_table.h>
28 #include <nat/nat_ha.h>
29
30 #define UNSUPPORTED_IN_DET_MODE_STR \
31   "This command is unsupported in deterministic mode"
32 #define SUPPORTED_ONLY_IN_DET_MODE_STR \
33   "This command is supported only in deterministic mode"
34
35 static clib_error_t *
36 set_workers_command_fn (vlib_main_t * vm,
37                         unformat_input_t * input, vlib_cli_command_t * cmd)
38 {
39   unformat_input_t _line_input, *line_input = &_line_input;
40   snat_main_t *sm = &snat_main;
41   uword *bitmap = 0;
42   int rv = 0;
43   clib_error_t *error = 0;
44
45   if (sm->deterministic)
46     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
47
48   /* Get a line of input. */
49   if (!unformat_user (input, unformat_line_input, line_input))
50     return 0;
51
52   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
53     {
54       if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap))
55         ;
56       else
57         {
58           error = clib_error_return (0, "unknown input '%U'",
59                                      format_unformat_error, line_input);
60           goto done;
61         }
62     }
63
64   if (bitmap == 0)
65     {
66       error = clib_error_return (0, "List of workers must be specified.");
67       goto done;
68     }
69
70   rv = snat_set_workers (bitmap);
71
72   clib_bitmap_free (bitmap);
73
74   switch (rv)
75     {
76     case VNET_API_ERROR_INVALID_WORKER:
77       error = clib_error_return (0, "Invalid worker(s).");
78       goto done;
79     case VNET_API_ERROR_FEATURE_DISABLED:
80       error = clib_error_return (0,
81                                  "Supported only if 2 or more workes available.");
82       goto done;
83     default:
84       break;
85     }
86
87 done:
88   unformat_free (line_input);
89
90   return error;
91 }
92
93 static clib_error_t *
94 nat_show_workers_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
95                              vlib_cli_command_t * cmd)
96 {
97   snat_main_t *sm = &snat_main;
98   u32 *worker;
99
100   if (sm->deterministic)
101     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
102
103   if (sm->num_workers > 1)
104     {
105       vlib_cli_output (vm, "%d workers", vec_len (sm->workers));
106       /* *INDENT-OFF* */
107       vec_foreach (worker, sm->workers)
108         {
109           vlib_worker_thread_t *w =
110             vlib_worker_threads + *worker + sm->first_worker_index;
111           vlib_cli_output (vm, "  %s", w->name);
112         }
113       /* *INDENT-ON* */
114     }
115
116   return 0;
117 }
118
119 static clib_error_t *
120 snat_set_log_level_command_fn (vlib_main_t * vm,
121                                unformat_input_t * input,
122                                vlib_cli_command_t * cmd)
123 {
124   unformat_input_t _line_input, *line_input = &_line_input;
125   snat_main_t *sm = &snat_main;
126   u8 log_level = SNAT_LOG_NONE;
127   clib_error_t *error = 0;
128
129   /* Get a line of input. */
130   if (!unformat_user (input, unformat_line_input, line_input))
131     return 0;
132
133   if (!unformat (line_input, "%d", &log_level))
134     {
135       error = clib_error_return (0, "unknown input '%U'",
136                                  format_unformat_error, line_input);
137       goto done;
138     }
139   if (log_level > SNAT_LOG_DEBUG)
140     {
141       error = clib_error_return (0, "unknown logging level '%d'", log_level);
142       goto done;
143     }
144   sm->log_level = log_level;
145
146 done:
147   unformat_free (line_input);
148
149   return error;
150 }
151
152 static clib_error_t *
153 snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm,
154                                               unformat_input_t * input,
155                                               vlib_cli_command_t * cmd)
156 {
157   unformat_input_t _line_input, *line_input = &_line_input;
158   u32 domain_id = 0;
159   u32 src_port = 0;
160   u8 enable = 1;
161   int rv = 0;
162   clib_error_t *error = 0;
163
164   /* Get a line of input. */
165   if (!unformat_user (input, unformat_line_input, line_input))
166     {
167       rv = snat_ipfix_logging_enable_disable (enable, domain_id,
168                                               (u16) src_port);
169       if (rv)
170         return clib_error_return (0, "ipfix logging enable failed");
171       return 0;
172     }
173
174   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
175     {
176       if (unformat (line_input, "domain %d", &domain_id))
177         ;
178       else if (unformat (line_input, "src-port %d", &src_port))
179         ;
180       else if (unformat (line_input, "disable"))
181         enable = 0;
182       else
183         {
184           error = clib_error_return (0, "unknown input '%U'",
185                                      format_unformat_error, line_input);
186           goto done;
187         }
188     }
189
190   rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port);
191
192   if (rv)
193     {
194       error = clib_error_return (0, "ipfix logging enable failed");
195       goto done;
196     }
197
198 done:
199   unformat_free (line_input);
200
201   return error;
202 }
203
204 static clib_error_t *
205 nat44_show_hash_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
206                             vlib_cli_command_t * cmd)
207 {
208   snat_main_t *sm = &snat_main;
209   snat_main_per_thread_data_t *tsm;
210   nat_affinity_main_t *nam = &nat_affinity_main;
211   int i;
212   int verbose = 0;
213
214   if (unformat (input, "detail"))
215     verbose = 1;
216   else if (unformat (input, "verbose"))
217     verbose = 2;
218
219   vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local,
220                    verbose);
221   vlib_cli_output (vm, "%U",
222                    format_bihash_8_8, &sm->static_mapping_by_external,
223                    verbose);
224   vec_foreach_index (i, sm->per_thread_data)
225   {
226     tsm = vec_elt_at_index (sm->per_thread_data, i);
227     vlib_cli_output (vm, "-------- thread %d %s --------\n",
228                      i, vlib_worker_threads[i].name);
229     if (sm->endpoint_dependent)
230       {
231         vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->in2out_ed,
232                          verbose);
233         vlib_cli_output (vm, "%U", format_bihash_16_8, &tsm->out2in_ed,
234                          verbose);
235       }
236     else
237       {
238         vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->in2out, verbose);
239         vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->out2in, verbose);
240       }
241     vlib_cli_output (vm, "%U", format_bihash_8_8, &tsm->user_hash, verbose);
242   }
243
244   if (sm->endpoint_dependent)
245     {
246       vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash,
247                        verbose);
248     }
249   return 0;
250 }
251
252 static clib_error_t *
253 nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
254                                               unformat_input_t * input,
255                                               vlib_cli_command_t * cmd)
256 {
257   unformat_input_t _line_input, *line_input = &_line_input;
258   snat_main_t *sm = &snat_main;
259   clib_error_t *error = 0;
260   u32 psid, psid_offset, psid_length, port_start, port_end;
261
262   if (sm->deterministic)
263     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
264
265   /* Get a line of input. */
266   if (!unformat_user (input, unformat_line_input, line_input))
267     return 0;
268
269   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
270     {
271       if (unformat (line_input, "default"))
272         nat_set_alloc_addr_and_port_default ();
273       else
274         if (unformat
275             (line_input, "map-e psid %d psid-offset %d psid-len %d", &psid,
276              &psid_offset, &psid_length))
277         nat_set_alloc_addr_and_port_mape ((u16) psid, (u16) psid_offset,
278                                           (u16) psid_length);
279       else
280         if (unformat
281             (line_input, "port-range %d - %d", &port_start, &port_end))
282         {
283           if (port_end <= port_start)
284             {
285               error =
286                 clib_error_return (0,
287                                    "The end-port must be greater than start-port");
288               goto done;
289             }
290           nat_set_alloc_addr_and_port_range ((u16) port_start,
291                                              (u16) port_end);
292         }
293       else
294         {
295           error = clib_error_return (0, "unknown input '%U'",
296                                      format_unformat_error, line_input);
297           goto done;
298         }
299     }
300
301 done:
302   unformat_free (line_input);
303
304   return error;
305 };
306
307 static clib_error_t *
308 nat44_show_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm,
309                                                unformat_input_t * input,
310                                                vlib_cli_command_t * cmd)
311 {
312   snat_main_t *sm = &snat_main;
313
314   if (sm->deterministic)
315     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
316
317   vlib_cli_output (vm, "NAT address and port: %U",
318                    format_nat_addr_and_port_alloc_alg,
319                    sm->addr_and_port_alloc_alg);
320   switch (sm->addr_and_port_alloc_alg)
321     {
322     case NAT_ADDR_AND_PORT_ALLOC_ALG_MAPE:
323       vlib_cli_output (vm, "  psid %d psid-offset %d psid-len %d", sm->psid,
324                        sm->psid_offset, sm->psid_length);
325       break;
326     case NAT_ADDR_AND_PORT_ALLOC_ALG_RANGE:
327       vlib_cli_output (vm, "  start-port %d end-port %d", sm->start_port,
328                        sm->end_port);
329       break;
330     default:
331       break;
332     }
333
334   return 0;
335 }
336
337 static clib_error_t *
338 nat_set_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
339                                  vlib_cli_command_t * cmd)
340 {
341   unformat_input_t _line_input, *line_input = &_line_input;
342   snat_main_t *sm = &snat_main;
343   clib_error_t *error = 0;
344   u32 mss;
345
346   /* Get a line of input. */
347   if (!unformat_user (input, unformat_line_input, line_input))
348     return 0;
349
350   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
351     {
352       if (unformat (line_input, "disable"))
353         sm->mss_clamping = 0;
354       else if (unformat (line_input, "%d", &mss))
355         {
356           sm->mss_clamping = (u16) mss;
357           sm->mss_value_net = clib_host_to_net_u16 (sm->mss_clamping);
358         }
359       else
360         {
361           error = clib_error_return (0, "unknown input '%U'",
362                                      format_unformat_error, line_input);
363           goto done;
364         }
365     }
366
367 done:
368   unformat_free (line_input);
369
370   return error;
371 }
372
373 static clib_error_t *
374 nat_show_mss_clamping_command_fn (vlib_main_t * vm, unformat_input_t * input,
375                                   vlib_cli_command_t * cmd)
376 {
377   snat_main_t *sm = &snat_main;
378
379   if (sm->mss_clamping)
380     vlib_cli_output (vm, "mss-clamping %d", sm->mss_clamping);
381   else
382     vlib_cli_output (vm, "mss-clamping disabled");
383
384   return 0;
385 }
386
387 static clib_error_t *
388 nat_ha_failover_command_fn (vlib_main_t * vm, unformat_input_t * input,
389                             vlib_cli_command_t * cmd)
390 {
391   unformat_input_t _line_input, *line_input = &_line_input;
392   ip4_address_t addr;
393   u32 port, session_refresh_interval = 10;
394   int rv;
395   clib_error_t *error = 0;
396
397   /* Get a line of input. */
398   if (!unformat_user (input, unformat_line_input, line_input))
399     return 0;
400
401   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
402     {
403       if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
404         ;
405       else
406         if (unformat
407             (line_input, "refresh-interval %u", &session_refresh_interval))
408         ;
409       else
410         {
411           error = clib_error_return (0, "unknown input '%U'",
412                                      format_unformat_error, line_input);
413           goto done;
414         }
415     }
416
417   rv = nat_ha_set_failover (&addr, (u16) port, session_refresh_interval);
418   if (rv)
419     error = clib_error_return (0, "set HA failover failed");
420
421 done:
422   unformat_free (line_input);
423
424   return error;
425 }
426
427 static clib_error_t *
428 nat_ha_listener_command_fn (vlib_main_t * vm, unformat_input_t * input,
429                             vlib_cli_command_t * cmd)
430 {
431   unformat_input_t _line_input, *line_input = &_line_input;
432   ip4_address_t addr;
433   u32 port, path_mtu = 512;
434   int rv;
435   clib_error_t *error = 0;
436
437   /* Get a line of input. */
438   if (!unformat_user (input, unformat_line_input, line_input))
439     return 0;
440
441   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
442     {
443       if (unformat (line_input, "%U:%u", unformat_ip4_address, &addr, &port))
444         ;
445       else if (unformat (line_input, "path-mtu %u", &path_mtu))
446         ;
447       else
448         {
449           error = clib_error_return (0, "unknown input '%U'",
450                                      format_unformat_error, line_input);
451           goto done;
452         }
453     }
454
455   rv = nat_ha_set_listener (&addr, (u16) port, path_mtu);
456   if (rv)
457     error = clib_error_return (0, "set HA listener failed");
458
459 done:
460   unformat_free (line_input);
461
462   return error;
463 }
464
465 static clib_error_t *
466 nat_show_ha_command_fn (vlib_main_t * vm, unformat_input_t * input,
467                         vlib_cli_command_t * cmd)
468 {
469   ip4_address_t addr;
470   u16 port;
471   u32 path_mtu, session_refresh_interval, resync_ack_missed;
472   u8 in_resync;
473
474   nat_ha_get_listener (&addr, &port, &path_mtu);
475   if (!port)
476     {
477       vlib_cli_output (vm, "NAT HA disabled\n");
478       return 0;
479     }
480
481   vlib_cli_output (vm, "LISTENER:\n");
482   vlib_cli_output (vm, "  %U:%u path-mtu %u\n",
483                    format_ip4_address, &addr, port, path_mtu);
484
485   nat_ha_get_failover (&addr, &port, &session_refresh_interval);
486   vlib_cli_output (vm, "FAILOVER:\n");
487   if (port)
488     vlib_cli_output (vm, "  %U:%u refresh-interval %usec\n",
489                      format_ip4_address, &addr, port,
490                      session_refresh_interval);
491   else
492     vlib_cli_output (vm, "  NA\n");
493
494   nat_ha_get_resync_status (&in_resync, &resync_ack_missed);
495   vlib_cli_output (vm, "RESYNC:\n");
496   if (in_resync)
497     vlib_cli_output (vm, "  in progress\n");
498   else
499     vlib_cli_output (vm, "  completed (%d ACK missed)\n", resync_ack_missed);
500
501   return 0;
502 }
503
504 static clib_error_t *
505 nat_ha_flush_command_fn (vlib_main_t * vm, unformat_input_t * input,
506                          vlib_cli_command_t * cmd)
507 {
508   nat_ha_flush (0);
509   return 0;
510 }
511
512 static clib_error_t *
513 nat_ha_resync_command_fn (vlib_main_t * vm, unformat_input_t * input,
514                           vlib_cli_command_t * cmd)
515 {
516   clib_error_t *error = 0;
517
518   if (nat_ha_resync (0, 0, 0))
519     error = clib_error_return (0, "NAT HA resync already running");
520
521   return error;
522 }
523
524 static clib_error_t *
525 add_address_command_fn (vlib_main_t * vm,
526                         unformat_input_t * input, vlib_cli_command_t * cmd)
527 {
528   unformat_input_t _line_input, *line_input = &_line_input;
529   snat_main_t *sm = &snat_main;
530   ip4_address_t start_addr, end_addr, this_addr;
531   u32 start_host_order, end_host_order;
532   u32 vrf_id = ~0;
533   int i, count;
534   int is_add = 1;
535   int rv = 0;
536   clib_error_t *error = 0;
537   u8 twice_nat = 0;
538
539   if (sm->deterministic)
540     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
541
542   /* Get a line of input. */
543   if (!unformat_user (input, unformat_line_input, line_input))
544     return 0;
545
546   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
547     {
548       if (unformat (line_input, "%U - %U",
549                     unformat_ip4_address, &start_addr,
550                     unformat_ip4_address, &end_addr))
551         ;
552       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
553         ;
554       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
555         end_addr = start_addr;
556       else if (unformat (line_input, "twice-nat"))
557         twice_nat = 1;
558       else if (unformat (line_input, "del"))
559         is_add = 0;
560       else
561         {
562           error = clib_error_return (0, "unknown input '%U'",
563                                      format_unformat_error, line_input);
564           goto done;
565         }
566     }
567
568   if (sm->static_mapping_only)
569     {
570       error = clib_error_return (0, "static mapping only mode");
571       goto done;
572     }
573
574   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
575   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
576
577   if (end_host_order < start_host_order)
578     {
579       error = clib_error_return (0, "end address less than start address");
580       goto done;
581     }
582
583   count = (end_host_order - start_host_order) + 1;
584
585   if (count > 1024)
586     nat_log_info ("%U - %U, %d addresses...",
587                   format_ip4_address, &start_addr,
588                   format_ip4_address, &end_addr, count);
589
590   this_addr = start_addr;
591
592   for (i = 0; i < count; i++)
593     {
594       if (is_add)
595         rv = snat_add_address (sm, &this_addr, vrf_id, twice_nat);
596       else
597         rv = snat_del_address (sm, this_addr, 0, twice_nat);
598
599       switch (rv)
600         {
601         case VNET_API_ERROR_VALUE_EXIST:
602           error = clib_error_return (0, "NAT address already in use.");
603           goto done;
604         case VNET_API_ERROR_NO_SUCH_ENTRY:
605           error = clib_error_return (0, "NAT address not exist.");
606           goto done;
607         case VNET_API_ERROR_UNSPECIFIED:
608           error =
609             clib_error_return (0, "NAT address used in static mapping.");
610           goto done;
611         case VNET_API_ERROR_FEATURE_DISABLED:
612           error =
613             clib_error_return (0,
614                                "twice NAT available only for endpoint-dependent mode.");
615           goto done;
616         default:
617           break;
618         }
619
620       if (sm->out2in_dpo)
621         nat44_add_del_address_dpo (this_addr, is_add);
622
623       increment_v4_address (&this_addr);
624     }
625
626 done:
627   unformat_free (line_input);
628
629   return error;
630 }
631
632 static clib_error_t *
633 nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
634                                vlib_cli_command_t * cmd)
635 {
636   snat_main_per_thread_data_t *tsm;
637   snat_main_t *sm = &snat_main;
638   snat_session_t *s;
639
640   if (sm->deterministic || !sm->endpoint_dependent)
641     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
642
643   // print session configuration values
644   vlib_cli_output (vm, "max translations: %u", sm->max_translations);
645   vlib_cli_output (vm, "max translations per user: %u",
646                    sm->max_translations_per_user);
647
648   u32 count = 0;
649
650   u64 now = vlib_time_now (sm->vlib_main);
651   u64 sess_timeout_time;
652
653   u32 udp_sessions = 0;
654   u32 tcp_sessions = 0;
655   u32 icmp_sessions = 0;
656
657   u32 timed_out = 0;
658   u32 transitory = 0;
659   u32 transitory_wait_closed = 0;
660   u32 transitory_closed = 0;
661   u32 established = 0;
662
663   if (sm->num_workers > 1)
664     {
665       /* *INDENT-OFF* */
666       vec_foreach (tsm, sm->per_thread_data)
667         {
668           pool_foreach (s, tsm->sessions,
669           ({
670             sess_timeout_time = s->last_heard +
671               (f64) nat44_session_get_timeout (sm, s);
672             if (now >= sess_timeout_time)
673               timed_out++;
674
675             switch (s->in2out.protocol)
676               {
677               case SNAT_PROTOCOL_ICMP:
678                 icmp_sessions++;
679                 break;
680               case SNAT_PROTOCOL_TCP:
681                 tcp_sessions++;
682                 if (s->state)
683                   {
684                     if (s->tcp_close_timestamp)
685                       {
686                         if (now >= s->tcp_close_timestamp)
687                           {
688                             ++transitory_closed;
689                           }
690                         else
691                           {
692                             ++transitory_wait_closed;
693                           }
694                       }
695                     transitory++;
696                   }
697                 else
698                   established++;
699                 break;
700               case SNAT_PROTOCOL_UDP:
701               default:
702                 udp_sessions++;
703                 break;
704               }
705           }));
706           count += pool_elts (tsm->sessions);
707         }
708       /* *INDENT-ON* */
709     }
710   else
711     {
712       tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers);
713       /* *INDENT-OFF* */
714       pool_foreach (s, tsm->sessions,
715       ({
716         sess_timeout_time = s->last_heard +
717             (f64) nat44_session_get_timeout (sm, s);
718         if (now >= sess_timeout_time)
719           timed_out++;
720
721         switch (s->in2out.protocol)
722           {
723           case SNAT_PROTOCOL_ICMP:
724             icmp_sessions++;
725             break;
726           case SNAT_PROTOCOL_TCP:
727             tcp_sessions++;
728             if (s->state)
729               {
730                 if (s->tcp_close_timestamp)
731                   {
732                     if (now >= s->tcp_close_timestamp)
733                       {
734                         ++transitory_closed;
735                       }
736                     else
737                       {
738                         ++transitory_wait_closed;
739                       }
740                   }
741                 transitory++;
742               }
743             else
744               established++;
745             break;
746           case SNAT_PROTOCOL_UDP:
747           default:
748             udp_sessions++;
749             break;
750           }
751       }));
752       /* *INDENT-ON* */
753       count = pool_elts (tsm->sessions);
754     }
755
756   vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
757   vlib_cli_output (vm, "total sessions: %u", count);
758   vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
759   vlib_cli_output (vm, "total tcp established sessions: %u", established);
760   vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
761   vlib_cli_output (vm, "total tcp transitory (WAIT-CLOSED) sessions: %u",
762                    transitory_wait_closed);
763   vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u",
764                    transitory_closed);
765   vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
766   vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
767   return 0;
768 }
769
770 static clib_error_t *
771 nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
772                                  vlib_cli_command_t * cmd)
773 {
774   snat_main_t *sm = &snat_main;
775   snat_address_t *ap;
776
777   if (sm->deterministic)
778     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
779
780   vlib_cli_output (vm, "NAT44 pool addresses:");
781   /* *INDENT-OFF* */
782   vec_foreach (ap, sm->addresses)
783     {
784       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
785       if (ap->fib_index != ~0)
786           vlib_cli_output (vm, "  tenant VRF: %u",
787             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
788       else
789         vlib_cli_output (vm, "  tenant VRF independent");
790     #define _(N, i, n, s) \
791       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
792       foreach_snat_protocol
793     #undef _
794     }
795   vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
796   vec_foreach (ap, sm->twice_nat_addresses)
797     {
798       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
799       if (ap->fib_index != ~0)
800           vlib_cli_output (vm, "  tenant VRF: %u",
801             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
802       else
803         vlib_cli_output (vm, "  tenant VRF independent");
804     #define _(N, i, n, s) \
805       vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
806       foreach_snat_protocol
807     #undef _
808     }
809   /* *INDENT-ON* */
810   return 0;
811 }
812
813 static clib_error_t *
814 snat_feature_command_fn (vlib_main_t * vm,
815                          unformat_input_t * input, vlib_cli_command_t * cmd)
816 {
817   unformat_input_t _line_input, *line_input = &_line_input;
818   vnet_main_t *vnm = vnet_get_main ();
819   clib_error_t *error = 0;
820   u32 sw_if_index;
821   u32 *inside_sw_if_indices = 0;
822   u32 *outside_sw_if_indices = 0;
823   u8 is_output_feature = 0;
824   int is_del = 0;
825   int i;
826
827   sw_if_index = ~0;
828
829   /* Get a line of input. */
830   if (!unformat_user (input, unformat_line_input, line_input))
831     return 0;
832
833   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
834     {
835       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
836                     vnm, &sw_if_index))
837         vec_add1 (inside_sw_if_indices, sw_if_index);
838       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
839                          vnm, &sw_if_index))
840         vec_add1 (outside_sw_if_indices, sw_if_index);
841       else if (unformat (line_input, "output-feature"))
842         is_output_feature = 1;
843       else if (unformat (line_input, "del"))
844         is_del = 1;
845       else
846         {
847           error = clib_error_return (0, "unknown input '%U'",
848                                      format_unformat_error, line_input);
849           goto done;
850         }
851     }
852
853   if (vec_len (inside_sw_if_indices))
854     {
855       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
856         {
857           sw_if_index = inside_sw_if_indices[i];
858           if (is_output_feature)
859             {
860               if (snat_interface_add_del_output_feature
861                   (sw_if_index, 1, is_del))
862                 {
863                   error = clib_error_return (0, "%s %U failed",
864                                              is_del ? "del" : "add",
865                                              format_vnet_sw_if_index_name,
866                                              vnm, sw_if_index);
867                   goto done;
868                 }
869             }
870           else
871             {
872               if (snat_interface_add_del (sw_if_index, 1, is_del))
873                 {
874                   error = clib_error_return (0, "%s %U failed",
875                                              is_del ? "del" : "add",
876                                              format_vnet_sw_if_index_name,
877                                              vnm, sw_if_index);
878                   goto done;
879                 }
880             }
881         }
882     }
883
884   if (vec_len (outside_sw_if_indices))
885     {
886       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
887         {
888           sw_if_index = outside_sw_if_indices[i];
889           if (is_output_feature)
890             {
891               if (snat_interface_add_del_output_feature
892                   (sw_if_index, 0, is_del))
893                 {
894                   error = clib_error_return (0, "%s %U failed",
895                                              is_del ? "del" : "add",
896                                              format_vnet_sw_if_index_name,
897                                              vnm, sw_if_index);
898                   goto done;
899                 }
900             }
901           else
902             {
903               if (snat_interface_add_del (sw_if_index, 0, is_del))
904                 {
905                   error = clib_error_return (0, "%s %U failed",
906                                              is_del ? "del" : "add",
907                                              format_vnet_sw_if_index_name,
908                                              vnm, sw_if_index);
909                   goto done;
910                 }
911             }
912         }
913     }
914
915 done:
916   unformat_free (line_input);
917   vec_free (inside_sw_if_indices);
918   vec_free (outside_sw_if_indices);
919
920   return error;
921 }
922
923 static clib_error_t *
924 nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
925                                   vlib_cli_command_t * cmd)
926 {
927   snat_main_t *sm = &snat_main;
928   snat_interface_t *i;
929   vnet_main_t *vnm = vnet_get_main ();
930
931   vlib_cli_output (vm, "NAT44 interfaces:");
932   /* *INDENT-OFF* */
933   pool_foreach (i, sm->interfaces,
934   ({
935     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
936                      i->sw_if_index,
937                      (nat_interface_is_inside(i) &&
938                       nat_interface_is_outside(i)) ? "in out" :
939                      (nat_interface_is_inside(i) ? "in" : "out"));
940   }));
941
942   pool_foreach (i, sm->output_feature_interfaces,
943   ({
944     vlib_cli_output (vm, " %U output-feature %s",
945                      format_vnet_sw_if_index_name, vnm,
946                      i->sw_if_index,
947                      (nat_interface_is_inside(i) &&
948                       nat_interface_is_outside(i)) ? "in out" :
949                      (nat_interface_is_inside(i) ? "in" : "out"));
950   }));
951   /* *INDENT-ON* */
952
953   return 0;
954 }
955
956 static clib_error_t *
957 add_static_mapping_command_fn (vlib_main_t * vm,
958                                unformat_input_t * input,
959                                vlib_cli_command_t * cmd)
960 {
961   unformat_input_t _line_input, *line_input = &_line_input;
962   snat_main_t *sm = &snat_main;
963   clib_error_t *error = 0;
964   ip4_address_t l_addr, e_addr;
965   u32 l_port = 0, e_port = 0, vrf_id = ~0;
966   int is_add = 1;
967   int addr_only = 1;
968   u32 sw_if_index = ~0;
969   vnet_main_t *vnm = vnet_get_main ();
970   int rv;
971   snat_protocol_t proto = ~0;
972   u8 proto_set = 0;
973   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
974   u8 out2in_only = 0;
975
976   if (sm->deterministic)
977     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
978
979   /* Get a line of input. */
980   if (!unformat_user (input, unformat_line_input, line_input))
981     return 0;
982
983   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
984     {
985       if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr,
986                     &l_port))
987         addr_only = 0;
988       else
989         if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr))
990         ;
991       else if (unformat (line_input, "external %U %u", unformat_ip4_address,
992                          &e_addr, &e_port))
993         addr_only = 0;
994       else if (unformat (line_input, "external %U", unformat_ip4_address,
995                          &e_addr))
996         ;
997       else if (unformat (line_input, "external %U %u",
998                          unformat_vnet_sw_interface, vnm, &sw_if_index,
999                          &e_port))
1000         addr_only = 0;
1001
1002       else if (unformat (line_input, "external %U",
1003                          unformat_vnet_sw_interface, vnm, &sw_if_index))
1004         ;
1005       else if (unformat (line_input, "vrf %u", &vrf_id))
1006         ;
1007       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
1008         proto_set = 1;
1009       else if (unformat (line_input, "twice-nat"))
1010         twice_nat = TWICE_NAT;
1011       else if (unformat (line_input, "self-twice-nat"))
1012         twice_nat = TWICE_NAT_SELF;
1013       else if (unformat (line_input, "out2in-only"))
1014         out2in_only = 1;
1015       else if (unformat (line_input, "del"))
1016         is_add = 0;
1017       else
1018         {
1019           error = clib_error_return (0, "unknown input: '%U'",
1020                                      format_unformat_error, line_input);
1021           goto done;
1022         }
1023     }
1024
1025   if (twice_nat && addr_only)
1026     {
1027       error = clib_error_return (0, "twice NAT only for 1:1 NAPT");
1028       goto done;
1029     }
1030
1031   if (!addr_only && !proto_set)
1032     {
1033       error = clib_error_return (0, "missing protocol");
1034       goto done;
1035     }
1036
1037   rv = snat_add_static_mapping (l_addr, e_addr, (u16) l_port, (u16) e_port,
1038                                 vrf_id, addr_only, sw_if_index, proto, is_add,
1039                                 twice_nat, out2in_only, 0, 0);
1040
1041   switch (rv)
1042     {
1043     case VNET_API_ERROR_INVALID_VALUE:
1044       error = clib_error_return (0, "External port already in use.");
1045       goto done;
1046     case VNET_API_ERROR_NO_SUCH_ENTRY:
1047       if (is_add)
1048         error = clib_error_return (0, "External address must be allocated.");
1049       else
1050         error = clib_error_return (0, "Mapping not exist.");
1051       goto done;
1052     case VNET_API_ERROR_NO_SUCH_FIB:
1053       error = clib_error_return (0, "No such VRF id.");
1054       goto done;
1055     case VNET_API_ERROR_VALUE_EXIST:
1056       error = clib_error_return (0, "Mapping already exist.");
1057       goto done;
1058     case VNET_API_ERROR_FEATURE_DISABLED:
1059       error =
1060         clib_error_return (0,
1061                            "twice-nat/out2in-only available only for endpoint-dependent mode.");
1062       goto done;
1063     default:
1064       break;
1065     }
1066
1067 done:
1068   unformat_free (line_input);
1069
1070   return error;
1071 }
1072
1073 static clib_error_t *
1074 add_identity_mapping_command_fn (vlib_main_t * vm,
1075                                  unformat_input_t * input,
1076                                  vlib_cli_command_t * cmd)
1077 {
1078   unformat_input_t _line_input, *line_input = &_line_input;
1079   snat_main_t *sm = &snat_main;
1080   clib_error_t *error = 0;
1081   ip4_address_t addr;
1082   u32 port = 0, vrf_id = ~0;
1083   int is_add = 1;
1084   int addr_only = 1;
1085   u32 sw_if_index = ~0;
1086   vnet_main_t *vnm = vnet_get_main ();
1087   int rv;
1088   snat_protocol_t proto;
1089
1090   if (sm->deterministic)
1091     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1092
1093   addr.as_u32 = 0;
1094
1095   /* Get a line of input. */
1096   if (!unformat_user (input, unformat_line_input, line_input))
1097     return 0;
1098
1099   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1100     {
1101       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
1102         ;
1103       else if (unformat (line_input, "external %U",
1104                          unformat_vnet_sw_interface, vnm, &sw_if_index))
1105         ;
1106       else if (unformat (line_input, "vrf %u", &vrf_id))
1107         ;
1108       else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto,
1109                          &port))
1110         addr_only = 0;
1111       else if (unformat (line_input, "del"))
1112         is_add = 0;
1113       else
1114         {
1115           error = clib_error_return (0, "unknown input: '%U'",
1116                                      format_unformat_error, line_input);
1117           goto done;
1118         }
1119     }
1120
1121   rv = snat_add_static_mapping (addr, addr, (u16) port, (u16) port,
1122                                 vrf_id, addr_only, sw_if_index, proto, is_add,
1123                                 0, 0, 0, 1);
1124
1125   switch (rv)
1126     {
1127     case VNET_API_ERROR_INVALID_VALUE:
1128       error = clib_error_return (0, "External port already in use.");
1129       goto done;
1130     case VNET_API_ERROR_NO_SUCH_ENTRY:
1131       if (is_add)
1132         error = clib_error_return (0, "External address must be allocated.");
1133       else
1134         error = clib_error_return (0, "Mapping not exist.");
1135       goto done;
1136     case VNET_API_ERROR_NO_SUCH_FIB:
1137       error = clib_error_return (0, "No such VRF id.");
1138       goto done;
1139     case VNET_API_ERROR_VALUE_EXIST:
1140       error = clib_error_return (0, "Mapping already exist.");
1141       goto done;
1142     default:
1143       break;
1144     }
1145
1146 done:
1147   unformat_free (line_input);
1148
1149   return error;
1150 }
1151
1152 static clib_error_t *
1153 add_lb_static_mapping_command_fn (vlib_main_t * vm,
1154                                   unformat_input_t * input,
1155                                   vlib_cli_command_t * cmd)
1156 {
1157   unformat_input_t _line_input, *line_input = &_line_input;
1158   snat_main_t *sm = &snat_main;
1159   clib_error_t *error = 0;
1160   ip4_address_t l_addr, e_addr;
1161   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0, affinity = 0;
1162   int is_add = 1;
1163   int rv;
1164   snat_protocol_t proto;
1165   u8 proto_set = 0;
1166   nat44_lb_addr_port_t *locals = 0, local;
1167   twice_nat_type_t twice_nat = TWICE_NAT_DISABLED;
1168   u8 out2in_only = 0;
1169
1170   if (sm->deterministic)
1171     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1172
1173   /* Get a line of input. */
1174   if (!unformat_user (input, unformat_line_input, line_input))
1175     return 0;
1176
1177   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1178     {
1179       if (unformat (line_input, "local %U:%u probability %u",
1180                     unformat_ip4_address, &l_addr, &l_port, &probability))
1181         {
1182           clib_memset (&local, 0, sizeof (local));
1183           local.addr = l_addr;
1184           local.port = (u16) l_port;
1185           local.probability = (u8) probability;
1186           vec_add1 (locals, local);
1187         }
1188       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1189                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1190                          &probability))
1191         {
1192           clib_memset (&local, 0, sizeof (local));
1193           local.addr = l_addr;
1194           local.port = (u16) l_port;
1195           local.probability = (u8) probability;
1196           local.vrf_id = vrf_id;
1197           vec_add1 (locals, local);
1198         }
1199       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1200                          &e_addr, &e_port))
1201         ;
1202       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
1203                          &proto))
1204         proto_set = 1;
1205       else if (unformat (line_input, "twice-nat"))
1206         twice_nat = TWICE_NAT;
1207       else if (unformat (line_input, "self-twice-nat"))
1208         twice_nat = TWICE_NAT_SELF;
1209       else if (unformat (line_input, "out2in-only"))
1210         out2in_only = 1;
1211       else if (unformat (line_input, "del"))
1212         is_add = 0;
1213       else if (unformat (line_input, "affinity %u", &affinity))
1214         ;
1215       else
1216         {
1217           error = clib_error_return (0, "unknown input: '%U'",
1218                                      format_unformat_error, line_input);
1219           goto done;
1220         }
1221     }
1222
1223   if (vec_len (locals) < 2)
1224     {
1225       error = clib_error_return (0, "at least two local must be set");
1226       goto done;
1227     }
1228
1229   if (!proto_set)
1230     {
1231       error = clib_error_return (0, "missing protocol");
1232       goto done;
1233     }
1234
1235   rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, locals,
1236                                         is_add, twice_nat, out2in_only, 0,
1237                                         affinity);
1238
1239   switch (rv)
1240     {
1241     case VNET_API_ERROR_INVALID_VALUE:
1242       error = clib_error_return (0, "External port already in use.");
1243       goto done;
1244     case VNET_API_ERROR_NO_SUCH_ENTRY:
1245       if (is_add)
1246         error = clib_error_return (0, "External address must be allocated.");
1247       else
1248         error = clib_error_return (0, "Mapping not exist.");
1249       goto done;
1250     case VNET_API_ERROR_VALUE_EXIST:
1251       error = clib_error_return (0, "Mapping already exist.");
1252       goto done;
1253     case VNET_API_ERROR_FEATURE_DISABLED:
1254       error =
1255         clib_error_return (0, "Available only for endpoint-dependent mode.");
1256       goto done;
1257     default:
1258       break;
1259     }
1260
1261 done:
1262   unformat_free (line_input);
1263   vec_free (locals);
1264
1265   return error;
1266 }
1267
1268 static clib_error_t *
1269 add_lb_backend_command_fn (vlib_main_t * vm,
1270                            unformat_input_t * input, vlib_cli_command_t * cmd)
1271 {
1272   unformat_input_t _line_input, *line_input = &_line_input;
1273   snat_main_t *sm = &snat_main;
1274   clib_error_t *error = 0;
1275   ip4_address_t l_addr, e_addr;
1276   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
1277   int is_add = 1;
1278   int rv;
1279   snat_protocol_t proto;
1280   u8 proto_set = 0;
1281
1282   if (sm->deterministic)
1283     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1284
1285   /* Get a line of input. */
1286   if (!unformat_user (input, unformat_line_input, line_input))
1287     return 0;
1288
1289   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1290     {
1291       if (unformat (line_input, "local %U:%u probability %u",
1292                     unformat_ip4_address, &l_addr, &l_port, &probability))
1293         ;
1294       else if (unformat (line_input, "local %U:%u vrf %u probability %u",
1295                          unformat_ip4_address, &l_addr, &l_port, &vrf_id,
1296                          &probability))
1297         ;
1298       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
1299                          &e_addr, &e_port))
1300         ;
1301       else if (unformat (line_input, "protocol %U", unformat_snat_protocol,
1302                          &proto))
1303         proto_set = 1;
1304       else if (unformat (line_input, "del"))
1305         is_add = 0;
1306       else
1307         {
1308           error = clib_error_return (0, "unknown input: '%U'",
1309                                      format_unformat_error, line_input);
1310           goto done;
1311         }
1312     }
1313
1314   if (!l_port || !e_port)
1315     {
1316       error = clib_error_return (0, "local or external must be set");
1317       goto done;
1318     }
1319
1320   if (!proto_set)
1321     {
1322       error = clib_error_return (0, "missing protocol");
1323       goto done;
1324     }
1325
1326   rv =
1327     nat44_lb_static_mapping_add_del_local (e_addr, (u16) e_port, l_addr,
1328                                            l_port, proto, vrf_id, probability,
1329                                            is_add);
1330
1331   switch (rv)
1332     {
1333     case VNET_API_ERROR_INVALID_VALUE:
1334       error = clib_error_return (0, "External is not load-balancing static "
1335                                  "mapping.");
1336       goto done;
1337     case VNET_API_ERROR_NO_SUCH_ENTRY:
1338       error = clib_error_return (0, "Mapping or back-end not exist.");
1339       goto done;
1340     case VNET_API_ERROR_VALUE_EXIST:
1341       error = clib_error_return (0, "Back-end already exist.");
1342       goto done;
1343     case VNET_API_ERROR_FEATURE_DISABLED:
1344       error =
1345         clib_error_return (0, "Available only for endpoint-dependent mode.");
1346       goto done;
1347     case VNET_API_ERROR_UNSPECIFIED:
1348       error = clib_error_return (0, "At least two back-ends must remain");
1349       goto done;
1350     default:
1351       break;
1352     }
1353
1354 done:
1355   unformat_free (line_input);
1356
1357   return error;
1358 }
1359
1360 static clib_error_t *
1361 nat44_show_static_mappings_command_fn (vlib_main_t * vm,
1362                                        unformat_input_t * input,
1363                                        vlib_cli_command_t * cmd)
1364 {
1365   snat_main_t *sm = &snat_main;
1366   snat_static_mapping_t *m;
1367   snat_static_map_resolve_t *rp;
1368
1369   if (sm->deterministic)
1370     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1371
1372   vlib_cli_output (vm, "NAT44 static mappings:");
1373   /* *INDENT-OFF* */
1374   pool_foreach (m, sm->static_mappings,
1375   ({
1376     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
1377   }));
1378   vec_foreach (rp, sm->to_resolve)
1379     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
1380   /* *INDENT-ON* */
1381
1382   return 0;
1383 }
1384
1385 static clib_error_t *
1386 snat_add_interface_address_command_fn (vlib_main_t * vm,
1387                                        unformat_input_t * input,
1388                                        vlib_cli_command_t * cmd)
1389 {
1390   snat_main_t *sm = &snat_main;
1391   unformat_input_t _line_input, *line_input = &_line_input;
1392   u32 sw_if_index;
1393   int rv;
1394   int is_del = 0;
1395   clib_error_t *error = 0;
1396   u8 twice_nat = 0;
1397
1398   if (sm->deterministic)
1399     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1400
1401   /* Get a line of input. */
1402   if (!unformat_user (input, unformat_line_input, line_input))
1403     return 0;
1404
1405   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1406     {
1407       if (unformat (line_input, "%U", unformat_vnet_sw_interface,
1408                     sm->vnet_main, &sw_if_index))
1409         ;
1410       else if (unformat (line_input, "twice-nat"))
1411         twice_nat = 1;
1412       else if (unformat (line_input, "del"))
1413         is_del = 1;
1414       else
1415         {
1416           error = clib_error_return (0, "unknown input '%U'",
1417                                      format_unformat_error, line_input);
1418           goto done;
1419         }
1420     }
1421
1422   rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
1423
1424   switch (rv)
1425     {
1426     case 0:
1427       break;
1428
1429     default:
1430       error = clib_error_return (0, "snat_add_interface_address returned %d",
1431                                  rv);
1432       goto done;
1433     }
1434
1435 done:
1436   unformat_free (line_input);
1437
1438   return error;
1439 }
1440
1441 static clib_error_t *
1442 nat44_show_interface_address_command_fn (vlib_main_t * vm,
1443                                          unformat_input_t * input,
1444                                          vlib_cli_command_t * cmd)
1445 {
1446   snat_main_t *sm = &snat_main;
1447   vnet_main_t *vnm = vnet_get_main ();
1448   u32 *sw_if_index;
1449
1450   if (sm->deterministic)
1451     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1452
1453   /* *INDENT-OFF* */
1454   vlib_cli_output (vm, "NAT44 pool address interfaces:");
1455   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
1456     {
1457       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1458                        *sw_if_index);
1459     }
1460   vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:");
1461   vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
1462     {
1463       vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
1464                        *sw_if_index);
1465     }
1466   /* *INDENT-ON* */
1467
1468   return 0;
1469 }
1470
1471 static clib_error_t *
1472 nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
1473                                 vlib_cli_command_t * cmd)
1474 {
1475   unformat_input_t _line_input, *line_input = &_line_input;
1476   clib_error_t *error = 0;
1477   snat_main_t *sm = &snat_main;
1478   snat_main_per_thread_data_t *tsm;
1479
1480   int detail = 0, metrics = 0;
1481   snat_user_t *u;
1482   int i = 0;
1483
1484   if (sm->deterministic)
1485     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1486
1487   if (!unformat_user (input, unformat_line_input, line_input))
1488     goto print;
1489
1490   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1491     {
1492       if (unformat (line_input, "detail"))
1493         detail = 1;
1494       else if (unformat (line_input, "metrics"))
1495         metrics = 1;
1496       else
1497         {
1498           error = clib_error_return (0, "unknown input '%U'",
1499                                      format_unformat_error, line_input);
1500           break;
1501         }
1502     }
1503   unformat_free (line_input);
1504
1505 print:
1506   vlib_cli_output (vm, "NAT44 sessions:");
1507   /* *INDENT-OFF* */
1508   vec_foreach_index (i, sm->per_thread_data)
1509     {
1510       tsm = vec_elt_at_index (sm->per_thread_data, i);
1511
1512       vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n",
1513                        i, vlib_worker_threads[i].name,
1514                        pool_elts (tsm->sessions));
1515       if (metrics)
1516         {
1517           u64 now = vlib_time_now (sm->vlib_main);
1518           pool_foreach (u, tsm->users,
1519           ({
1520             vlib_cli_output (vm, "  %U", format_snat_user_v2, tsm, u, now);
1521           }));
1522         }
1523       else
1524         {
1525           pool_foreach (u, tsm->users,
1526           ({
1527             vlib_cli_output (vm, "  %U", format_snat_user, tsm, u, detail);
1528           }));
1529         }
1530     }
1531   /* *INDENT-ON* */
1532   return error;
1533 }
1534
1535 static clib_error_t *
1536 nat44_del_user_command_fn (vlib_main_t * vm,
1537                            unformat_input_t * input, vlib_cli_command_t * cmd)
1538 {
1539   snat_main_t *sm = &snat_main;
1540   unformat_input_t _line_input, *line_input = &_line_input;
1541   clib_error_t *error = 0;
1542   ip4_address_t addr;
1543   u32 fib_index = 0;
1544   int rv;
1545
1546   if (sm->deterministic)
1547     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1548
1549   /* Get a line of input. */
1550   if (!unformat_user (input, unformat_line_input, line_input))
1551     return 0;
1552
1553   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1554     {
1555       if (unformat (line_input, "%U", unformat_ip4_address, &addr))
1556         ;
1557       else if (unformat (line_input, "fib %u", &fib_index))
1558         ;
1559       else
1560         {
1561           error = clib_error_return (0, "unknown input '%U'",
1562                                      format_unformat_error, line_input);
1563           goto done;
1564         }
1565     }
1566
1567   rv = nat44_user_del (&addr, fib_index);
1568
1569   if (!rv)
1570     {
1571       error = clib_error_return (0, "nat44_user_del returned %d", rv);
1572     }
1573
1574 done:
1575   unformat_free (line_input);
1576
1577   return error;
1578 }
1579
1580 static clib_error_t *
1581 nat44_del_session_command_fn (vlib_main_t * vm,
1582                               unformat_input_t * input,
1583                               vlib_cli_command_t * cmd)
1584 {
1585   snat_main_t *sm = &snat_main;
1586   unformat_input_t _line_input, *line_input = &_line_input;
1587   int is_in = 0, is_ed = 0;
1588   clib_error_t *error = 0;
1589   ip4_address_t addr, eh_addr;
1590   u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
1591   snat_protocol_t proto;
1592   int rv;
1593
1594   if (sm->deterministic)
1595     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1596
1597   /* Get a line of input. */
1598   if (!unformat_user (input, unformat_line_input, line_input))
1599     return 0;
1600
1601   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1602     {
1603       if (unformat
1604           (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
1605            unformat_snat_protocol, &proto))
1606         ;
1607       else if (unformat (line_input, "in"))
1608         {
1609           is_in = 1;
1610           vrf_id = sm->inside_vrf_id;
1611         }
1612       else if (unformat (line_input, "out"))
1613         {
1614           is_in = 0;
1615           vrf_id = sm->outside_vrf_id;
1616         }
1617       else if (unformat (line_input, "vrf %u", &vrf_id))
1618         ;
1619       else
1620         if (unformat
1621             (line_input, "external-host %U:%u", unformat_ip4_address,
1622              &eh_addr, &eh_port))
1623         is_ed = 1;
1624       else
1625         {
1626           error = clib_error_return (0, "unknown input '%U'",
1627                                      format_unformat_error, line_input);
1628           goto done;
1629         }
1630     }
1631
1632   if (is_ed)
1633     rv =
1634       nat44_del_ed_session (sm, &addr, port, &eh_addr, eh_port,
1635                             snat_proto_to_ip_proto (proto), vrf_id, is_in);
1636   else
1637     rv = nat44_del_session (sm, &addr, port, proto, vrf_id, is_in);
1638
1639   switch (rv)
1640     {
1641     case 0:
1642       break;
1643
1644     default:
1645       error = clib_error_return (0, "nat44_del_session returned %d", rv);
1646       goto done;
1647     }
1648
1649 done:
1650   unformat_free (line_input);
1651
1652   return error;
1653 }
1654
1655 static clib_error_t *
1656 snat_forwarding_set_command_fn (vlib_main_t * vm,
1657                                 unformat_input_t * input,
1658                                 vlib_cli_command_t * cmd)
1659 {
1660   snat_main_t *sm = &snat_main;
1661   unformat_input_t _line_input, *line_input = &_line_input;
1662   u8 forwarding_enable;
1663   u8 forwarding_enable_set = 0;
1664   clib_error_t *error = 0;
1665
1666   if (sm->deterministic)
1667     return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR);
1668
1669   /* Get a line of input. */
1670   if (!unformat_user (input, unformat_line_input, line_input))
1671     return clib_error_return (0, "'enable' or 'disable' expected");
1672
1673   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1674     {
1675       if (!forwarding_enable_set && unformat (line_input, "enable"))
1676         {
1677           forwarding_enable = 1;
1678           forwarding_enable_set = 1;
1679         }
1680       else if (!forwarding_enable_set && unformat (line_input, "disable"))
1681         {
1682           forwarding_enable = 0;
1683           forwarding_enable_set = 1;
1684         }
1685       else
1686         {
1687           error = clib_error_return (0, "unknown input '%U'",
1688                                      format_unformat_error, line_input);
1689           goto done;
1690         }
1691     }
1692
1693   if (!forwarding_enable_set)
1694     {
1695       error = clib_error_return (0, "'enable' or 'disable' expected");
1696       goto done;
1697     }
1698
1699   sm->forwarding_enabled = forwarding_enable;
1700
1701 done:
1702   unformat_free (line_input);
1703
1704   return error;
1705 }
1706
1707 static clib_error_t *
1708 snat_det_map_command_fn (vlib_main_t * vm,
1709                          unformat_input_t * input, vlib_cli_command_t * cmd)
1710 {
1711   snat_main_t *sm = &snat_main;
1712   unformat_input_t _line_input, *line_input = &_line_input;
1713   ip4_address_t in_addr, out_addr;
1714   u32 in_plen, out_plen;
1715   int is_add = 1, rv;
1716   clib_error_t *error = 0;
1717
1718   if (!sm->deterministic)
1719     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1720
1721   /* Get a line of input. */
1722   if (!unformat_user (input, unformat_line_input, line_input))
1723     return 0;
1724
1725   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1726     {
1727       if (unformat
1728           (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
1729         ;
1730       else
1731         if (unformat
1732             (line_input, "out %U/%u", unformat_ip4_address, &out_addr,
1733              &out_plen))
1734         ;
1735       else if (unformat (line_input, "del"))
1736         is_add = 0;
1737       else
1738         {
1739           error = clib_error_return (0, "unknown input '%U'",
1740                                      format_unformat_error, line_input);
1741           goto done;
1742         }
1743     }
1744
1745   rv = snat_det_add_map (sm, &in_addr, (u8) in_plen, &out_addr, (u8) out_plen,
1746                          is_add);
1747
1748   if (rv)
1749     {
1750       error = clib_error_return (0, "snat_det_add_map return %d", rv);
1751       goto done;
1752     }
1753
1754 done:
1755   unformat_free (line_input);
1756
1757   return error;
1758 }
1759
1760 static clib_error_t *
1761 nat44_det_show_mappings_command_fn (vlib_main_t * vm,
1762                                     unformat_input_t * input,
1763                                     vlib_cli_command_t * cmd)
1764 {
1765   snat_main_t *sm = &snat_main;
1766   snat_det_map_t *dm;
1767
1768   if (!sm->deterministic)
1769     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1770
1771   vlib_cli_output (vm, "NAT44 deterministic mappings:");
1772   /* *INDENT-OFF* */
1773   pool_foreach (dm, sm->det_maps,
1774   ({
1775     vlib_cli_output (vm, " in %U/%d out %U/%d\n",
1776                      format_ip4_address, &dm->in_addr, dm->in_plen,
1777                      format_ip4_address, &dm->out_addr, dm->out_plen);
1778     vlib_cli_output (vm, "  outside address sharing ratio: %d\n",
1779                      dm->sharing_ratio);
1780     vlib_cli_output (vm, "  number of ports per inside host: %d\n",
1781                      dm->ports_per_host);
1782     vlib_cli_output (vm, "  sessions number: %d\n", dm->ses_num);
1783   }));
1784   /* *INDENT-ON* */
1785
1786   return 0;
1787 }
1788
1789 static clib_error_t *
1790 snat_det_forward_command_fn (vlib_main_t * vm,
1791                              unformat_input_t * input,
1792                              vlib_cli_command_t * cmd)
1793 {
1794   snat_main_t *sm = &snat_main;
1795   unformat_input_t _line_input, *line_input = &_line_input;
1796   ip4_address_t in_addr, out_addr;
1797   u16 lo_port;
1798   snat_det_map_t *dm;
1799   clib_error_t *error = 0;
1800
1801   if (!sm->deterministic)
1802     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1803
1804   /* Get a line of input. */
1805   if (!unformat_user (input, unformat_line_input, line_input))
1806     return 0;
1807
1808   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1809     {
1810       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
1811         ;
1812       else
1813         {
1814           error = clib_error_return (0, "unknown input '%U'",
1815                                      format_unformat_error, line_input);
1816           goto done;
1817         }
1818     }
1819
1820   dm = snat_det_map_by_user (sm, &in_addr);
1821   if (!dm)
1822     vlib_cli_output (vm, "no match");
1823   else
1824     {
1825       snat_det_forward (dm, &in_addr, &out_addr, &lo_port);
1826       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
1827                        lo_port, lo_port + dm->ports_per_host - 1);
1828     }
1829
1830 done:
1831   unformat_free (line_input);
1832
1833   return error;
1834 }
1835
1836 static clib_error_t *
1837 snat_det_reverse_command_fn (vlib_main_t * vm,
1838                              unformat_input_t * input,
1839                              vlib_cli_command_t * cmd)
1840 {
1841   snat_main_t *sm = &snat_main;
1842   unformat_input_t _line_input, *line_input = &_line_input;
1843   ip4_address_t in_addr, out_addr;
1844   u32 out_port;
1845   snat_det_map_t *dm;
1846   clib_error_t *error = 0;
1847
1848   if (!sm->deterministic)
1849     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1850
1851   /* Get a line of input. */
1852   if (!unformat_user (input, unformat_line_input, line_input))
1853     return 0;
1854
1855   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1856     {
1857       if (unformat
1858           (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
1859         ;
1860       else
1861         {
1862           error = clib_error_return (0, "unknown input '%U'",
1863                                      format_unformat_error, line_input);
1864           goto done;
1865         }
1866     }
1867
1868   if (out_port < 1024 || out_port > 65535)
1869     {
1870       error = clib_error_return (0, "wrong port, must be <1024-65535>");
1871       goto done;
1872     }
1873
1874   dm = snat_det_map_by_out (sm, &out_addr);
1875   if (!dm)
1876     vlib_cli_output (vm, "no match");
1877   else
1878     {
1879       snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr);
1880       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
1881     }
1882
1883 done:
1884   unformat_free (line_input);
1885
1886   return error;
1887 }
1888
1889 static clib_error_t *
1890 set_timeout_command_fn (vlib_main_t * vm,
1891                         unformat_input_t * input, vlib_cli_command_t * cmd)
1892 {
1893   snat_main_t *sm = &snat_main;
1894   unformat_input_t _line_input, *line_input = &_line_input;
1895   clib_error_t *error = 0;
1896
1897   /* Get a line of input. */
1898   if (!unformat_user (input, unformat_line_input, line_input))
1899     return 0;
1900
1901   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1902     {
1903       if (unformat (line_input, "udp %u", &sm->udp_timeout))
1904         {
1905           if (nat64_set_udp_timeout (sm->udp_timeout))
1906             {
1907               error = clib_error_return (0, "Invalid UDP timeout value");
1908               goto done;
1909             }
1910         }
1911       else if (unformat (line_input, "tcp-established %u",
1912                          &sm->tcp_established_timeout))
1913         {
1914           if (nat64_set_tcp_timeouts
1915               (sm->tcp_transitory_timeout, sm->tcp_established_timeout))
1916             {
1917               error =
1918                 clib_error_return (0,
1919                                    "Invalid TCP established timeouts value");
1920               goto done;
1921             }
1922         }
1923       else if (unformat (line_input, "tcp-transitory %u",
1924                          &sm->tcp_transitory_timeout))
1925         {
1926           if (nat64_set_tcp_timeouts
1927               (sm->tcp_transitory_timeout, sm->tcp_established_timeout))
1928             {
1929               error =
1930                 clib_error_return (0,
1931                                    "Invalid TCP transitory timeouts value");
1932               goto done;
1933             }
1934         }
1935       else if (unformat (line_input, "icmp %u", &sm->icmp_timeout))
1936         {
1937           if (nat64_set_icmp_timeout (sm->icmp_timeout))
1938             {
1939               error = clib_error_return (0, "Invalid ICMP timeout value");
1940               goto done;
1941             }
1942         }
1943       else if (unformat (line_input, "reset"))
1944         {
1945           sm->udp_timeout = SNAT_UDP_TIMEOUT;
1946           sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
1947           sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
1948           sm->icmp_timeout = SNAT_ICMP_TIMEOUT;
1949           nat64_set_udp_timeout (0);
1950           nat64_set_icmp_timeout (0);
1951           nat64_set_tcp_timeouts (0, 0);
1952         }
1953       else
1954         {
1955           error = clib_error_return (0, "unknown input '%U'",
1956                                      format_unformat_error, line_input);
1957           goto done;
1958         }
1959     }
1960 done:
1961   unformat_free (line_input);
1962   return error;
1963 }
1964
1965 static clib_error_t *
1966 nat_show_timeouts_command_fn (vlib_main_t * vm,
1967                               unformat_input_t * input,
1968                               vlib_cli_command_t * cmd)
1969 {
1970   snat_main_t *sm = &snat_main;
1971
1972   vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout);
1973   vlib_cli_output (vm, "tcp-established timeout: %dsec",
1974                    sm->tcp_established_timeout);
1975   vlib_cli_output (vm, "tcp-transitory timeout: %dsec",
1976                    sm->tcp_transitory_timeout);
1977   vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout);
1978
1979   return 0;
1980 }
1981
1982 static clib_error_t *
1983 nat44_det_show_sessions_command_fn (vlib_main_t * vm,
1984                                     unformat_input_t * input,
1985                                     vlib_cli_command_t * cmd)
1986 {
1987   snat_main_t *sm = &snat_main;
1988   snat_det_map_t *dm;
1989   snat_det_session_t *ses;
1990   int i;
1991
1992   if (!sm->deterministic)
1993     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
1994
1995   vlib_cli_output (vm, "NAT44 deterministic sessions:");
1996   /* *INDENT-OFF* */
1997   pool_foreach (dm, sm->det_maps,
1998   ({
1999     vec_foreach_index (i, dm->sessions)
2000       {
2001         ses = vec_elt_at_index (dm->sessions, i);
2002         if (ses->in_port)
2003           vlib_cli_output (vm, "  %U", format_det_map_ses, dm, ses, &i);
2004       }
2005   }));
2006   /* *INDENT-ON* */
2007   return 0;
2008 }
2009
2010 static clib_error_t *
2011 snat_det_close_session_out_fn (vlib_main_t * vm,
2012                                unformat_input_t * input,
2013                                vlib_cli_command_t * cmd)
2014 {
2015   snat_main_t *sm = &snat_main;
2016   unformat_input_t _line_input, *line_input = &_line_input;
2017   ip4_address_t out_addr, ext_addr, in_addr;
2018   u32 out_port, ext_port;
2019   snat_det_map_t *dm;
2020   snat_det_session_t *ses;
2021   snat_det_out_key_t key;
2022   clib_error_t *error = 0;
2023
2024   if (!sm->deterministic)
2025     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
2026
2027   /* Get a line of input. */
2028   if (!unformat_user (input, unformat_line_input, line_input))
2029     return 0;
2030
2031   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2032     {
2033       if (unformat (line_input, "%U:%d %U:%d",
2034                     unformat_ip4_address, &out_addr, &out_port,
2035                     unformat_ip4_address, &ext_addr, &ext_port))
2036         ;
2037       else
2038         {
2039           error = clib_error_return (0, "unknown input '%U'",
2040                                      format_unformat_error, line_input);
2041           goto done;
2042         }
2043     }
2044
2045   unformat_free (line_input);
2046
2047   dm = snat_det_map_by_out (sm, &out_addr);
2048   if (!dm)
2049     vlib_cli_output (vm, "no match");
2050   else
2051     {
2052       snat_det_reverse (dm, &ext_addr, (u16) out_port, &in_addr);
2053       key.ext_host_addr = out_addr;
2054       key.ext_host_port = ntohs ((u16) ext_port);
2055       key.out_port = ntohs ((u16) out_port);
2056       ses = snat_det_get_ses_by_out (dm, &out_addr, key.as_u64);
2057       if (!ses)
2058         vlib_cli_output (vm, "no match");
2059       else
2060         snat_det_ses_close (dm, ses);
2061     }
2062
2063 done:
2064   unformat_free (line_input);
2065
2066   return error;
2067 }
2068
2069 static clib_error_t *
2070 snat_det_close_session_in_fn (vlib_main_t * vm,
2071                               unformat_input_t * input,
2072                               vlib_cli_command_t * cmd)
2073 {
2074   snat_main_t *sm = &snat_main;
2075   unformat_input_t _line_input, *line_input = &_line_input;
2076   ip4_address_t in_addr, ext_addr;
2077   u32 in_port, ext_port;
2078   snat_det_map_t *dm;
2079   snat_det_session_t *ses;
2080   snat_det_out_key_t key;
2081   clib_error_t *error = 0;
2082
2083   if (!sm->deterministic)
2084     return clib_error_return (0, SUPPORTED_ONLY_IN_DET_MODE_STR);
2085
2086   /* Get a line of input. */
2087   if (!unformat_user (input, unformat_line_input, line_input))
2088     return 0;
2089
2090   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2091     {
2092       if (unformat (line_input, "%U:%d %U:%d",
2093                     unformat_ip4_address, &in_addr, &in_port,
2094                     unformat_ip4_address, &ext_addr, &ext_port))
2095         ;
2096       else
2097         {
2098           error = clib_error_return (0, "unknown input '%U'",
2099                                      format_unformat_error, line_input);
2100           goto done;
2101         }
2102     }
2103
2104   unformat_free (line_input);
2105
2106   dm = snat_det_map_by_user (sm, &in_addr);
2107   if (!dm)
2108     vlib_cli_output (vm, "no match");
2109   else
2110     {
2111       key.ext_host_addr = ext_addr;
2112       key.ext_host_port = ntohs ((u16) ext_port);
2113       ses =
2114         snat_det_find_ses_by_in (dm, &in_addr, ntohs ((u16) in_port), key);
2115       if (!ses)
2116         vlib_cli_output (vm, "no match");
2117       else
2118         snat_det_ses_close (dm, ses);
2119     }
2120
2121 done:
2122   unformat_free (line_input);
2123
2124   return error;
2125 }
2126 /* *INDENT-OFF* */
2127
2128 /*?
2129  * @cliexpar
2130  * @cliexstart{set snat workers}
2131  * Set NAT workers if 2 or more workers available, use:
2132  *  vpp# set snat workers 0-2,5
2133  * @cliexend
2134 ?*/
2135 VLIB_CLI_COMMAND (set_workers_command, static) = {
2136   .path = "set nat workers",
2137   .function = set_workers_command_fn,
2138   .short_help = "set nat workers <workers-list>",
2139 };
2140
2141 /*?
2142  * @cliexpar
2143  * @cliexstart{show nat workers}
2144  * Show NAT workers.
2145  *  vpp# show nat workers:
2146  *  2 workers
2147  *    vpp_wk_0
2148  *    vpp_wk_1
2149  * @cliexend
2150 ?*/
2151 VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
2152   .path = "show nat workers",
2153   .short_help = "show nat workers",
2154   .function = nat_show_workers_commnad_fn,
2155 };
2156
2157 /*?
2158  * @cliexpar
2159  * @cliexstart{set nat timeout}
2160  * Set values of timeouts for NAT sessions (in seconds), use:
2161  *  vpp# set nat timeout udp 120 tcp-established 7500 tcp-transitory 250 icmp 90
2162  * To reset default values use:
2163  *  vpp# set nat44 deterministic timeout reset
2164  * @cliexend
2165 ?*/
2166 VLIB_CLI_COMMAND (set_timeout_command, static) = {
2167   .path = "set nat timeout",
2168   .function = set_timeout_command_fn,
2169   .short_help =
2170     "set nat timeout [udp <sec> | tcp-established <sec> "
2171     "tcp-transitory <sec> | icmp <sec> | reset]",
2172 };
2173
2174 /*?
2175  * @cliexpar
2176  * @cliexstart{show nat timeouts}
2177  * Show values of timeouts for NAT sessions.
2178  * vpp# show nat timeouts
2179  * udp timeout: 300sec
2180  * tcp-established timeout: 7440sec
2181  * tcp-transitory timeout: 240sec
2182  * icmp timeout: 60sec
2183  * @cliexend
2184 ?*/
2185 VLIB_CLI_COMMAND (nat_show_timeouts_command, static) = {
2186   .path = "show nat timeouts",
2187   .short_help = "show nat timeouts",
2188   .function = nat_show_timeouts_command_fn,
2189 };
2190
2191 /*?
2192  * @cliexpar
2193  * @cliexstart{nat set logging level}
2194  * To set NAT logging level use:
2195  * Set nat logging level
2196  * @cliexend
2197 ?*/
2198 VLIB_CLI_COMMAND (snat_set_log_level_command, static) = {
2199   .path = "nat set logging level",
2200   .function = snat_set_log_level_command_fn,
2201   .short_help = "nat set logging level <level>",
2202 };
2203
2204 /*?
2205  * @cliexpar
2206  * @cliexstart{snat ipfix logging}
2207  * To enable NAT IPFIX logging use:
2208  *  vpp# nat ipfix logging
2209  * To set IPFIX exporter use:
2210  *  vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1
2211  * @cliexend
2212 ?*/
2213 VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = {
2214   .path = "nat ipfix logging",
2215   .function = snat_ipfix_logging_enable_disable_command_fn,
2216   .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]",
2217 };
2218
2219 /*?
2220  * @cliexpar
2221  * @cliexstart{nat addr-port-assignment-alg}
2222  * Set address and port assignment algorithm
2223  * For the MAP-E CE limit port choice based on PSID use:
2224  *  vpp# nat addr-port-assignment-alg map-e psid 10 psid-offset 6 psid-len 6
2225  * For port range use:
2226  *  vpp# nat addr-port-assignment-alg port-range <start-port> - <end-port>
2227  * To set standard (default) address and port assignment algorithm use:
2228  *  vpp# nat addr-port-assignment-alg default
2229  * @cliexend
2230 ?*/
2231 VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = {
2232     .path = "nat addr-port-assignment-alg",
2233     .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]",
2234     .function = nat44_set_alloc_addr_and_port_alg_command_fn,
2235 };
2236
2237 /*?
2238  * @cliexpar
2239  * @cliexstart{show nat addr-port-assignment-alg}
2240  * Show address and port assignment algorithm
2241  * @cliexend
2242 ?*/
2243 VLIB_CLI_COMMAND (nat44_show_alloc_addr_and_port_alg_command, static) = {
2244     .path = "show nat addr-port-assignment-alg",
2245     .short_help = "show nat addr-port-assignment-alg",
2246     .function = nat44_show_alloc_addr_and_port_alg_command_fn,
2247 };
2248
2249 /*?
2250  * @cliexpar
2251  * @cliexstart{nat mss-clamping}
2252  * Set TCP MSS rewriting configuration
2253  * To enable TCP MSS rewriting use:
2254  *  vpp# nat mss-clamping 1452
2255  * To disbale TCP MSS rewriting use:
2256  *  vpp# nat mss-clamping disable
2257  * @cliexend
2258 ?*/
2259 VLIB_CLI_COMMAND (nat_set_mss_clamping_command, static) = {
2260     .path = "nat mss-clamping",
2261     .short_help = "nat mss-clamping <mss-value>|disable",
2262     .function = nat_set_mss_clamping_command_fn,
2263 };
2264
2265 /*?
2266  * @cliexpar
2267  * @cliexstart{show nat mss-clamping}
2268  * Show TCP MSS rewriting configuration
2269  * @cliexend
2270 ?*/
2271 VLIB_CLI_COMMAND (nat_show_mss_clamping_command, static) = {
2272     .path = "show nat mss-clamping",
2273     .short_help = "show nat mss-clamping",
2274     .function = nat_show_mss_clamping_command_fn,
2275 };
2276
2277 /*?
2278  * @cliexpar
2279  * @cliexstart{nat ha failover}
2280  * Set HA failover (remote settings)
2281  * @cliexend
2282 ?*/
2283 VLIB_CLI_COMMAND (nat_ha_failover_command, static) = {
2284     .path = "nat ha failover",
2285     .short_help = "nat ha failover <ip4-address>:<port> [refresh-interval <sec>]",
2286     .function = nat_ha_failover_command_fn,
2287 };
2288
2289 /*?
2290  * @cliexpar
2291  * @cliexstart{nat ha listener}
2292  * Set HA listener (local settings)
2293  * @cliexend
2294 ?*/
2295 VLIB_CLI_COMMAND (nat_ha_listener_command, static) = {
2296     .path = "nat ha listener",
2297     .short_help = "nat ha listener <ip4-address>:<port> [path-mtu <path-mtu>]",
2298     .function = nat_ha_listener_command_fn,
2299 };
2300
2301 /*?
2302  * @cliexpar
2303  * @cliexstart{show nat ha}
2304  * Show HA configuration/status
2305  * @cliexend
2306 ?*/
2307 VLIB_CLI_COMMAND (nat_show_ha_command, static) = {
2308     .path = "show nat ha",
2309     .short_help = "show nat ha",
2310     .function = nat_show_ha_command_fn,
2311 };
2312
2313 /*?
2314  * @cliexpar
2315  * @cliexstart{nat ha flush}
2316  * Flush the current HA data (for testing)
2317  * @cliexend
2318 ?*/
2319 VLIB_CLI_COMMAND (nat_ha_flush_command, static) = {
2320     .path = "nat ha flush",
2321     .short_help = "nat ha flush",
2322     .function = nat_ha_flush_command_fn,
2323 };
2324
2325 /*?
2326  * @cliexpar
2327  * @cliexstart{nat ha resync}
2328  * Resync HA (resend existing sessions to new failover)
2329  * @cliexend
2330 ?*/
2331 VLIB_CLI_COMMAND (nat_ha_resync_command, static) = {
2332     .path = "nat ha resync",
2333     .short_help = "nat ha resync",
2334     .function = nat_ha_resync_command_fn,
2335 };
2336
2337 /*?
2338  * @cliexpar
2339  * @cliexstart{show nat44 hash tables}
2340  * Show NAT44 hash tables
2341  * @cliexend
2342 ?*/
2343 VLIB_CLI_COMMAND (nat44_show_hash, static) = {
2344   .path = "show nat44 hash tables",
2345   .short_help = "show nat44 hash tables [detail|verbose]",
2346   .function = nat44_show_hash_commnad_fn,
2347 };
2348
2349 /*?
2350  * @cliexpar
2351  * @cliexstart{nat44 add address}
2352  * Add/delete NAT44 pool address.
2353  * To add NAT44 pool address use:
2354  *  vpp# nat44 add address 172.16.1.3
2355  *  vpp# nat44 add address 172.16.2.2 - 172.16.2.24
2356  * To add NAT44 pool address for specific tenant (identified by VRF id) use:
2357  *  vpp# nat44 add address 172.16.1.3 tenant-vrf 10
2358  * @cliexend
2359 ?*/
2360 VLIB_CLI_COMMAND (add_address_command, static) = {
2361   .path = "nat44 add address",
2362   .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] "
2363                 "[tenant-vrf <vrf-id>] [twice-nat] [del]",
2364   .function = add_address_command_fn,
2365 };
2366
2367 /*?
2368  * @cliexpar
2369  * @cliexstart{show nat44 summary}
2370  * Show NAT44 summary
2371  * vpp# show nat44 summary
2372  * @cliexend
2373 ?*/
2374 VLIB_CLI_COMMAND (nat44_show_summary_command, static) = {
2375   .path = "show nat44 summary",
2376   .short_help = "show nat44 summary",
2377   .function = nat44_show_summary_command_fn,
2378 };
2379
2380 /*?
2381  * @cliexpar
2382  * @cliexstart{show nat44 addresses}
2383  * Show NAT44 pool addresses.
2384  * vpp# show nat44 addresses
2385  * NAT44 pool addresses:
2386  * 172.16.2.2
2387  *   tenant VRF independent
2388  *   10 busy udp ports
2389  *   0 busy tcp ports
2390  *   0 busy icmp ports
2391  * 172.16.1.3
2392  *   tenant VRF: 10
2393  *   0 busy udp ports
2394  *   2 busy tcp ports
2395  *   0 busy icmp ports
2396  * NAT44 twice-nat pool addresses:
2397  * 10.20.30.72
2398  *   tenant VRF independent
2399  *   0 busy udp ports
2400  *   0 busy tcp ports
2401  *   0 busy icmp ports
2402  * @cliexend
2403 ?*/
2404 VLIB_CLI_COMMAND (nat44_show_addresses_command, static) = {
2405   .path = "show nat44 addresses",
2406   .short_help = "show nat44 addresses",
2407   .function = nat44_show_addresses_command_fn,
2408 };
2409
2410 /*?
2411  * @cliexpar
2412  * @cliexstart{set interface nat44}
2413  * Enable/disable NAT44 feature on the interface.
2414  * To enable NAT44 feature with local network interface use:
2415  *  vpp# set interface nat44 in GigabitEthernet0/8/0
2416  * To enable NAT44 feature with external network interface use:
2417  *  vpp# set interface nat44 out GigabitEthernet0/a/0
2418  * @cliexend
2419 ?*/
2420 VLIB_CLI_COMMAND (set_interface_snat_command, static) = {
2421   .path = "set interface nat44",
2422   .function = snat_feature_command_fn,
2423   .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] "
2424                 "[del]",
2425 };
2426
2427 /*?
2428  * @cliexpar
2429  * @cliexstart{show nat44 interfaces}
2430  * Show interfaces with NAT44 feature.
2431  * vpp# show nat44 interfaces
2432  * NAT44 interfaces:
2433  *  GigabitEthernet0/8/0 in
2434  *  GigabitEthernet0/a/0 out
2435  * @cliexend
2436 ?*/
2437 VLIB_CLI_COMMAND (nat44_show_interfaces_command, static) = {
2438   .path = "show nat44 interfaces",
2439   .short_help = "show nat44 interfaces",
2440   .function = nat44_show_interfaces_command_fn,
2441 };
2442
2443 /*?
2444  * @cliexpar
2445  * @cliexstart{nat44 add static mapping}
2446  * Static mapping allows hosts on the external network to initiate connection
2447  * to to the local network host.
2448  * To create static mapping between local host address 10.0.0.3 port 6303 and
2449  * external address 4.4.4.4 port 3606 for TCP protocol use:
2450  *  vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606
2451  * If not runnig "static mapping only" NAT plugin mode use before:
2452  *  vpp# nat44 add address 4.4.4.4
2453  * To create static mapping between local and external address use:
2454  *  vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4
2455  * @cliexend
2456 ?*/
2457 VLIB_CLI_COMMAND (add_static_mapping_command, static) = {
2458   .path = "nat44 add static mapping",
2459   .function = add_static_mapping_command_fn,
2460   .short_help =
2461     "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] "
2462     "external <addr> [<port>] [vrf <table-id>] [twice-nat|self-twice-nat] "
2463     "[out2in-only] [del]",
2464 };
2465
2466 /*?
2467  * @cliexpar
2468  * @cliexstart{nat44 add identity mapping}
2469  * Identity mapping translate an IP address to itself.
2470  * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol
2471  * use:
2472  *  vpp# nat44 add identity mapping 10.0.0.3 tcp 6303
2473  * To create identity mapping for address 10.0.0.3 use:
2474  *  vpp# nat44 add identity mapping 10.0.0.3
2475  * To create identity mapping for DHCP addressed interface use:
2476  *  vpp# nat44 add identity mapping external GigabitEthernet0/a/0 tcp 3606
2477  * @cliexend
2478 ?*/
2479 VLIB_CLI_COMMAND (add_identity_mapping_command, static) = {
2480   .path = "nat44 add identity mapping",
2481   .function = add_identity_mapping_command_fn,
2482   .short_help = "nat44 add identity mapping <ip4-addr>|external <interface> "
2483     "[<protocol> <port>] [vrf <table-id>] [del]",
2484 };
2485
2486 /*?
2487  * @cliexpar
2488  * @cliexstart{nat44 add load-balancing static mapping}
2489  * Service load balancing using NAT44
2490  * To add static mapping with load balancing for service with external IP
2491  * address 1.2.3.4 and TCP port 80 and mapped to 2 local servers
2492  * 10.100.10.10:8080 and 10.100.10.20:8080 with probability 80% resp. 20% use:
2493  *  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
2494  * @cliexend
2495 ?*/
2496 VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = {
2497   .path = "nat44 add load-balancing static mapping",
2498   .function = add_lb_static_mapping_command_fn,
2499   .short_help =
2500     "nat44 add load-balancing static mapping protocol tcp|udp "
2501     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
2502     "probability <n> [twice-nat|self-twice-nat] [out2in-only] "
2503     "[affinity <timeout-seconds>] [del]",
2504 };
2505
2506 /*?
2507  * @cliexpar
2508  * @cliexstart{nat44 add load-balancing static mapping}
2509  * Modify service load balancing using NAT44
2510  * To add new back-end server 10.100.10.30:8080 for service load balancing
2511  * static mapping with external IP address 1.2.3.4 and TCP port 80 use:
2512  *  vpp# nat44 add load-balancing back-end protocol tcp external 1.2.3.4:80 local 10.100.10.30:8080 probability 25
2513  * @cliexend
2514 ?*/
2515 VLIB_CLI_COMMAND (add_lb_backend_command, static) = {
2516   .path = "nat44 add load-balancing back-end",
2517   .function = add_lb_backend_command_fn,
2518   .short_help =
2519     "nat44 add load-balancing back-end protocol tcp|udp "
2520     "external <addr>:<port> local <addr>:<port> [vrf <table-id>] "
2521     "probability <n> [del]",
2522 };
2523
2524 /*?
2525  * @cliexpar
2526  * @cliexstart{show nat44 static mappings}
2527  * Show NAT44 static mappings.
2528  * vpp# show nat44 static mappings
2529  * NAT44 static mappings:
2530  *  local 10.0.0.3 external 4.4.4.4 vrf 0
2531  *  tcp local 192.168.0.4:6303 external 4.4.4.3:3606 vrf 0
2532  *  tcp vrf 0 external 1.2.3.4:80  out2in-only
2533  *   local 10.100.10.10:8080 probability 80
2534  *   local 10.100.10.20:8080 probability 20
2535  *  tcp local 10.100.3.8:8080 external 169.10.10.1:80 vrf 0 twice-nat
2536  *  tcp local 10.0.0.10:3603 external GigabitEthernet0/a/0:6306 vrf 10
2537  * @cliexend
2538 ?*/
2539 VLIB_CLI_COMMAND (nat44_show_static_mappings_command, static) = {
2540   .path = "show nat44 static mappings",
2541   .short_help = "show nat44 static mappings",
2542   .function = nat44_show_static_mappings_command_fn,
2543 };
2544
2545 /*?
2546  * @cliexpar
2547  * @cliexstart{nat44 add interface address}
2548  * Use NAT44 pool address from specific interfce
2549  * To add NAT44 pool address from specific interface use:
2550  *  vpp# nat44 add interface address GigabitEthernet0/8/0
2551  * @cliexend
2552 ?*/
2553 VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
2554     .path = "nat44 add interface address",
2555     .short_help = "nat44 add interface address <interface> [twice-nat] [del]",
2556     .function = snat_add_interface_address_command_fn,
2557 };
2558
2559 /*?
2560  * @cliexpar
2561  * @cliexstart{show nat44 interface address}
2562  * Show NAT44 pool address interfaces
2563  * vpp# show nat44 interface address
2564  * NAT44 pool address interfaces:
2565  *  GigabitEthernet0/a/0
2566  * NAT44 twice-nat pool address interfaces:
2567  *  GigabitEthernet0/8/0
2568  * @cliexend
2569 ?*/
2570 VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
2571   .path = "show nat44 interface address",
2572   .short_help = "show nat44 interface address",
2573   .function = nat44_show_interface_address_command_fn,
2574 };
2575
2576 /*?
2577  * @cliexpar
2578  * @cliexstart{show nat44 sessions}
2579  * Show NAT44 sessions.
2580  * @cliexend
2581 ?*/
2582 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
2583   .path = "show nat44 sessions",
2584   .short_help = "show nat44 sessions [detail|metrics]",
2585   .function = nat44_show_sessions_command_fn,
2586 };
2587
2588 /*?
2589  * @cliexpar
2590  * @cliexstart{nat44 del user}
2591  * To delete all NAT44 user sessions:
2592  *  vpp# nat44 del user 10.0.0.3
2593  * @cliexend
2594 ?*/
2595 VLIB_CLI_COMMAND (nat44_del_user_command, static) = {
2596     .path = "nat44 del user",
2597     .short_help = "nat44 del user <addr> [fib <index>]",
2598     .function = nat44_del_user_command_fn,
2599 };
2600
2601 /*?
2602  * @cliexpar
2603  * @cliexstart{nat44 del session}
2604  * To administratively delete NAT44 session by inside address and port use:
2605  *  vpp# nat44 del session in 10.0.0.3:6303 tcp
2606  * To administratively delete NAT44 session by outside address and port use:
2607  *  vpp# nat44 del session out 1.0.0.3:6033 udp
2608  * @cliexend
2609 ?*/
2610 VLIB_CLI_COMMAND (nat44_del_session_command, static) = {
2611     .path = "nat44 del session",
2612     .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>] [external-host <addr>:<port>]",
2613     .function = nat44_del_session_command_fn,
2614 };
2615
2616 /*?
2617  * @cliexpar
2618  * @cliexstart{nat44 forwarding}
2619  * Enable or disable forwarding
2620  * Forward packets which don't match existing translation
2621  * or static mapping instead of dropping them.
2622  * To enable forwarding, use:
2623  *  vpp# nat44 forwarding enable
2624  * To disable forwarding, use:
2625  *  vpp# nat44 forwarding disable
2626  * @cliexend
2627 ?*/
2628 VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = {
2629   .path = "nat44 forwarding",
2630   .short_help = "nat44 forwarding enable|disable",
2631   .function = snat_forwarding_set_command_fn,
2632 };
2633
2634 /*?
2635  * @cliexpar
2636  * @cliexstart{nat44 deterministic add}
2637  * Create bijective mapping of inside address to outside address and port range
2638  * pairs, with the purpose of enabling deterministic NAT to reduce logging in
2639  * CGN deployments.
2640  * To create deterministic mapping between inside network 10.0.0.0/18 and
2641  * outside network 1.1.1.0/30 use:
2642  * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30
2643  * @cliexend
2644 ?*/
2645 VLIB_CLI_COMMAND (snat_det_map_command, static) = {
2646     .path = "nat44 deterministic add",
2647     .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]",
2648     .function = snat_det_map_command_fn,
2649 };
2650
2651 /*?
2652  * @cliexpar
2653  * @cliexpstart{show nat44 deterministic mappings}
2654  * Show NAT44 deterministic mappings
2655  * vpp# show nat44 deterministic mappings
2656  * NAT44 deterministic mappings:
2657  *  in 10.0.0.0/24 out 1.1.1.1/32
2658  *   outside address sharing ratio: 256
2659  *   number of ports per inside host: 252
2660  *   sessions number: 0
2661  * @cliexend
2662 ?*/
2663 VLIB_CLI_COMMAND (nat44_det_show_mappings_command, static) = {
2664     .path = "show nat44 deterministic mappings",
2665     .short_help = "show nat44 deterministic mappings",
2666     .function = nat44_det_show_mappings_command_fn,
2667 };
2668
2669 /*?
2670  * @cliexpar
2671  * @cliexstart{nat44 deterministic forward}
2672  * Return outside address and port range from inside address for deterministic
2673  * NAT.
2674  * To obtain outside address and port of inside host use:
2675  *  vpp# nat44 deterministic forward 10.0.0.2
2676  *  1.1.1.0:<1054-1068>
2677  * @cliexend
2678 ?*/
2679 VLIB_CLI_COMMAND (snat_det_forward_command, static) = {
2680     .path = "nat44 deterministic forward",
2681     .short_help = "nat44 deterministic forward <addr>",
2682     .function = snat_det_forward_command_fn,
2683 };
2684
2685 /*?
2686  * @cliexpar
2687  * @cliexstart{nat44 deterministic reverse}
2688  * Return inside address from outside address and port for deterministic NAT.
2689  * To obtain inside host address from outside address and port use:
2690  *  #vpp nat44 deterministic reverse 1.1.1.1:1276
2691  *  10.0.16.16
2692  * @cliexend
2693 ?*/
2694 VLIB_CLI_COMMAND (snat_det_reverse_command, static) = {
2695     .path = "nat44 deterministic reverse",
2696     .short_help = "nat44 deterministic reverse <addr>:<port>",
2697     .function = snat_det_reverse_command_fn,
2698 };
2699
2700 /*?
2701  * @cliexpar
2702  * @cliexstart{show nat44 deterministic sessions}
2703  * Show NAT44 deterministic sessions.
2704  * vpp# show nat44 deterministic sessions
2705  * NAT44 deterministic sessions:
2706  *   in 10.0.0.3:3005 out 1.1.1.2:1146 external host 172.16.1.2:3006 state: udp-active expire: 306
2707  *   in 10.0.0.3:3000 out 1.1.1.2:1141 external host 172.16.1.2:3001 state: udp-active expire: 306
2708  *   in 10.0.0.4:3005 out 1.1.1.2:1177 external host 172.16.1.2:3006 state: udp-active expire: 306
2709  * @cliexend
2710 ?*/
2711 VLIB_CLI_COMMAND (nat44_det_show_sessions_command, static) = {
2712   .path = "show nat44 deterministic sessions",
2713   .short_help = "show nat44 deterministic sessions",
2714   .function = nat44_det_show_sessions_command_fn,
2715 };
2716
2717 /*?
2718  * @cliexpar
2719  * @cliexstart{nat44 deterministic close session out}
2720  * Close session using outside ip address and port
2721  * and external ip address and port, use:
2722  *  vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387
2723  * @cliexend
2724 ?*/
2725 VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = {
2726   .path = "nat44 deterministic close session out",
2727   .short_help = "nat44 deterministic close session out "
2728                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
2729   .function = snat_det_close_session_out_fn,
2730 };
2731
2732 /*?
2733  * @cliexpar
2734  * @cliexstart{nat44 deterministic close session in}
2735  * Close session using inside ip address and port
2736  * and external ip address and port, use:
2737  *  vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387
2738  * @cliexend
2739 ?*/
2740 VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = {
2741   .path = "nat44 deterministic close session in",
2742   .short_help = "nat44 deterministic close session in "
2743                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
2744   .function = snat_det_close_session_in_fn,
2745 };
2746
2747 /* *INDENT-ON* */
2748
2749 /*
2750  * fd.io coding-style-patch-verification: ON
2751  *
2752  * Local Variables:
2753  * eval: (c-set-style "gnu")
2754  * End:
2755  */