nat: det44 plugin fix style and api cleanup
[vpp.git] / src / plugins / nat / det44 / det44_cli.c
1 /*
2  * Copyright (c) 2020 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 DET44 CLI
18  */
19 #include <nat/det44/det44.h>
20
21 static clib_error_t *
22 det44_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
23                       vlib_cli_command_t * cmd)
24 {
25   unformat_input_t _line_input, *line_input = &_line_input;
26   ip4_address_t in_addr, out_addr;
27   u32 in_plen, out_plen;
28   int is_add = 1, rv;
29   clib_error_t *error = 0;
30
31   if (!unformat_user (input, unformat_line_input, line_input))
32     return 0;
33
34   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
35     {
36       if (unformat
37           (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen))
38         ;
39       else
40         if (unformat
41             (line_input, "out %U/%u", unformat_ip4_address, &out_addr,
42              &out_plen))
43         ;
44       else if (unformat (line_input, "del"))
45         is_add = 0;
46       else
47         {
48           error = clib_error_return (0, "unknown input '%U'",
49                                      format_unformat_error, line_input);
50           goto done;
51         }
52     }
53
54   rv = snat_det_add_map (&in_addr, (u8) in_plen, &out_addr, (u8) out_plen,
55                          is_add);
56
57   if (rv)
58     {
59       error = clib_error_return (0, "snat_det_add_map return %d", rv);
60       goto done;
61     }
62
63 done:
64   unformat_free (line_input);
65
66   return error;
67 }
68
69 static clib_error_t *
70 det44_show_mappings_command_fn (vlib_main_t * vm,
71                                 unformat_input_t * input,
72                                 vlib_cli_command_t * cmd)
73 {
74   det44_main_t *dm = &det44_main;
75   snat_det_map_t *mp;
76   vlib_cli_output (vm, "NAT44 deterministic mappings:");
77   /* *INDENT-OFF* */
78   pool_foreach (mp, dm->det_maps,
79   ({
80     vlib_cli_output (vm, " in %U/%d out %U/%d\n",
81                      format_ip4_address, &mp->in_addr, mp->in_plen,
82                      format_ip4_address, &mp->out_addr, mp->out_plen);
83     vlib_cli_output (vm, "  outside address sharing ratio: %d\n",
84                      mp->sharing_ratio);
85     vlib_cli_output (vm, "  number of ports per inside host: %d\n",
86                      mp->ports_per_host);
87     vlib_cli_output (vm, "  sessions number: %d\n", mp->ses_num);
88   }));
89   /* *INDENT-ON* */
90   return 0;
91 }
92
93 static clib_error_t *
94 det44_forward_command_fn (vlib_main_t * vm,
95                           unformat_input_t * input, vlib_cli_command_t * cmd)
96 {
97   unformat_input_t _line_input, *line_input = &_line_input;
98   ip4_address_t in_addr, out_addr;
99   u16 lo_port;
100   snat_det_map_t *mp;
101   clib_error_t *error = 0;
102
103   if (!unformat_user (input, unformat_line_input, line_input))
104     return 0;
105
106   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
107     {
108       if (unformat (line_input, "%U", unformat_ip4_address, &in_addr))
109         ;
110       else
111         {
112           error = clib_error_return (0, "unknown input '%U'",
113                                      format_unformat_error, line_input);
114           goto done;
115         }
116     }
117
118   mp = snat_det_map_by_user (&in_addr);
119   if (!mp)
120     vlib_cli_output (vm, "no match");
121   else
122     {
123       snat_det_forward (mp, &in_addr, &out_addr, &lo_port);
124       vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr,
125                        lo_port, lo_port + mp->ports_per_host - 1);
126     }
127
128 done:
129   unformat_free (line_input);
130
131   return error;
132 }
133
134 static clib_error_t *
135 det44_reverse_command_fn (vlib_main_t * vm,
136                           unformat_input_t * input, vlib_cli_command_t * cmd)
137 {
138   unformat_input_t _line_input, *line_input = &_line_input;
139   ip4_address_t in_addr, out_addr;
140   clib_error_t *error = 0;
141   snat_det_map_t *mp;
142   u32 out_port;
143
144   if (!unformat_user (input, unformat_line_input, line_input))
145     return 0;
146
147   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
148     {
149       if (unformat
150           (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port))
151         ;
152       else
153         {
154           error = clib_error_return (0, "unknown input '%U'",
155                                      format_unformat_error, line_input);
156           goto done;
157         }
158     }
159
160   if (out_port < 1024 || out_port > 65535)
161     {
162       error = clib_error_return (0, "wrong port, must be <1024-65535>");
163       goto done;
164     }
165
166   mp = snat_det_map_by_out (&out_addr);
167   if (!mp)
168     vlib_cli_output (vm, "no match");
169   else
170     {
171       snat_det_reverse (mp, &out_addr, (u16) out_port, &in_addr);
172       vlib_cli_output (vm, "%U", format_ip4_address, &in_addr);
173     }
174
175 done:
176   unformat_free (line_input);
177
178   return error;
179 }
180
181 static clib_error_t *
182 det44_show_sessions_command_fn (vlib_main_t * vm,
183                                 unformat_input_t * input,
184                                 vlib_cli_command_t * cmd)
185 {
186   det44_main_t *dm = &det44_main;
187   snat_det_session_t *ses;
188   snat_det_map_t *mp;
189   vlib_cli_output (vm, "NAT44 deterministic sessions:");
190   /* *INDENT-OFF* */
191   pool_foreach (mp, dm->det_maps,
192   ({
193     int i;
194     vec_foreach_index (i, mp->sessions)
195       {
196         ses = vec_elt_at_index (mp->sessions, i);
197         if (ses->in_port)
198           vlib_cli_output (vm, "  %U", format_det_map_ses, mp, ses, &i);
199       }
200   }));
201   /* *INDENT-ON* */
202   return 0;
203 }
204
205 static clib_error_t *
206 det44_close_session_out_fn (vlib_main_t * vm,
207                             unformat_input_t * input,
208                             vlib_cli_command_t * cmd)
209 {
210   unformat_input_t _line_input, *line_input = &_line_input;
211   ip4_address_t out_addr, ext_addr, in_addr;
212   u32 out_port, ext_port;
213   snat_det_map_t *mp;
214   snat_det_session_t *ses;
215   snat_det_out_key_t key;
216   clib_error_t *error = 0;
217
218   if (!unformat_user (input, unformat_line_input, line_input))
219     return 0;
220
221   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
222     {
223       if (unformat (line_input, "%U:%d %U:%d",
224                     unformat_ip4_address, &out_addr, &out_port,
225                     unformat_ip4_address, &ext_addr, &ext_port))
226         ;
227       else
228         {
229           error = clib_error_return (0, "unknown input '%U'",
230                                      format_unformat_error, line_input);
231           goto done;
232         }
233     }
234
235   unformat_free (line_input);
236
237   mp = snat_det_map_by_out (&out_addr);
238   if (!mp)
239     vlib_cli_output (vm, "no match");
240   else
241     {
242       snat_det_reverse (mp, &ext_addr, (u16) out_port, &in_addr);
243       key.ext_host_addr = out_addr;
244       key.ext_host_port = ntohs ((u16) ext_port);
245       key.out_port = ntohs ((u16) out_port);
246       ses = snat_det_get_ses_by_out (mp, &out_addr, key.as_u64);
247       if (!ses)
248         vlib_cli_output (vm, "no match");
249       else
250         snat_det_ses_close (mp, ses);
251     }
252
253 done:
254   unformat_free (line_input);
255
256   return error;
257 }
258
259 static clib_error_t *
260 det44_close_session_in_fn (vlib_main_t * vm,
261                            unformat_input_t * input, vlib_cli_command_t * cmd)
262 {
263   unformat_input_t _line_input, *line_input = &_line_input;
264   ip4_address_t in_addr, ext_addr;
265   u32 in_port, ext_port;
266   snat_det_map_t *mp;
267   snat_det_session_t *ses;
268   snat_det_out_key_t key;
269   clib_error_t *error = 0;
270
271   if (!unformat_user (input, unformat_line_input, line_input))
272     return 0;
273
274   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
275     {
276       if (unformat (line_input, "%U:%d %U:%d",
277                     unformat_ip4_address, &in_addr, &in_port,
278                     unformat_ip4_address, &ext_addr, &ext_port))
279         ;
280       else
281         {
282           error = clib_error_return (0, "unknown input '%U'",
283                                      format_unformat_error, line_input);
284           goto done;
285         }
286     }
287
288   unformat_free (line_input);
289
290   mp = snat_det_map_by_user (&in_addr);
291   if (!mp)
292     vlib_cli_output (vm, "no match");
293   else
294     {
295       key.ext_host_addr = ext_addr;
296       key.ext_host_port = ntohs ((u16) ext_port);
297       ses =
298         snat_det_find_ses_by_in (mp, &in_addr, ntohs ((u16) in_port), key);
299       if (!ses)
300         vlib_cli_output (vm, "no match");
301       else
302         snat_det_ses_close (mp, ses);
303     }
304
305 done:
306   unformat_free (line_input);
307
308   return error;
309 }
310
311 static clib_error_t *
312 det44_set_timeouts_command_fn (vlib_main_t * vm,
313                                unformat_input_t * input,
314                                vlib_cli_command_t * cmd)
315 {
316   unformat_input_t _line_input, *line_input = &_line_input;
317   nat_timeouts_t timeouts = { 0 };
318   clib_error_t *error = 0;
319   u8 reset = 0;
320
321   if (!unformat_user (input, unformat_line_input, line_input))
322     return 0;
323
324   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
325     {
326       if (unformat (line_input, "udp %u", &timeouts.udp));
327       else if (unformat (line_input, "tcp established %u",
328                          &timeouts.tcp.established));
329       else if (unformat (line_input, "tcp transitory %u",
330                          &timeouts.tcp.transitory));
331       else if (unformat (line_input, "icmp %u", &timeouts.icmp));
332       else if (unformat (line_input, "reset"))
333         reset = 1;
334       else
335         {
336           error = clib_error_return (0, "unknown input '%U'",
337                                      format_unformat_error, line_input);
338           goto done;
339         }
340     }
341
342   if (!reset)
343     {
344       if (det44_set_timeouts (&timeouts))
345         {
346           error = clib_error_return (0, "error configuring timeouts");
347         }
348     }
349   else
350     det44_reset_timeouts ();
351 done:
352   unformat_free (line_input);
353   return error;
354 }
355
356 static clib_error_t *
357 det44_show_timeouts_command_fn (vlib_main_t * vm,
358                                 unformat_input_t * input,
359                                 vlib_cli_command_t * cmd)
360 {
361   nat_timeouts_t timeouts;
362   timeouts = det44_get_timeouts ();
363   vlib_cli_output (vm, "udp timeout: %dsec", timeouts.udp);
364   vlib_cli_output (vm, "tcp established timeout: %dsec",
365                    timeouts.tcp.established);
366   vlib_cli_output (vm, "tcp transitory timeout: %dsec",
367                    timeouts.tcp.transitory);
368   vlib_cli_output (vm, "icmp timeout: %dsec", timeouts.icmp);
369   return 0;
370 }
371
372 static clib_error_t *
373 det44_plugin_enable_disable_command_fn (vlib_main_t * vm,
374                                         unformat_input_t * input,
375                                         vlib_cli_command_t * cmd)
376 {
377   unformat_input_t _line_input, *line_input = &_line_input;
378   u8 enable = 0, is_set = 0;
379   clib_error_t *error = 0;
380   det44_config_t c = { 0 };
381
382   if (!unformat_user (input, unformat_line_input, line_input))
383     return 0;
384
385   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
386     {
387       if (!is_set && unformat (line_input, "enable"))
388         {
389           unformat (line_input, "inside vrf %u", &c.inside_vrf_id);
390           unformat (line_input, "outside vrf %u", &c.outside_vrf_id);
391           enable = 1;
392         }
393       else if (!is_set && unformat (line_input, "disable"));
394       else
395         {
396           error = clib_error_return (0, "unknown input '%U'",
397                                      format_unformat_error, line_input);
398           goto done;
399         }
400       is_set = 1;
401     }
402
403   if (enable)
404     {
405       if (det44_plugin_enable (c))
406         error = clib_error_return (0, "plugin enable failed");
407     }
408   else
409     {
410       if (det44_plugin_disable ())
411         error = clib_error_return (0, "plugin disable failed");
412     }
413 done:
414   unformat_free (line_input);
415   return error;
416 }
417
418 typedef struct
419 {
420   u32 sw_if_index;
421   u8 is_inside;
422 } sw_if_indices_t;
423
424 static clib_error_t *
425 det44_feature_command_fn (vlib_main_t * vm,
426                           unformat_input_t * input, vlib_cli_command_t * cmd)
427 {
428   unformat_input_t _line_input, *line_input = &_line_input;
429   sw_if_indices_t *sw_if_indices = 0, *p, e;
430   vnet_main_t *vnm = vnet_get_main ();
431   clib_error_t *error = 0;
432   u8 is_del = 0;
433
434   if (!unformat_user (input, unformat_line_input, line_input))
435     return 0;
436
437   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
438     {
439       if (unformat (line_input, "inside %U", unformat_vnet_sw_interface,
440                     vnm, &e.sw_if_index))
441         {
442           e.is_inside = 1;
443           vec_add1 (sw_if_indices, e);
444         }
445       else if (unformat (line_input, "outside %U", unformat_vnet_sw_interface,
446                          vnm, &e.sw_if_index))
447         {
448           e.is_inside = 0;
449           vec_add1 (sw_if_indices, e);
450         }
451       else if (unformat (line_input, "del"))
452         is_del = 1;
453       else
454         {
455           error = clib_error_return (0, "unknown input '%U'",
456                                      format_unformat_error, line_input);
457           goto done;
458         }
459     }
460
461   /* *INDENT-OFF* */
462   vec_foreach (p, sw_if_indices)
463     {
464       if (det44_interface_add_del (p->sw_if_index, p->is_inside, is_del))
465         {
466           error = clib_error_return (0, "%s %s %U failed",
467                                      is_del ? "del" : "add",
468                                      p->is_inside ? "inside" : "outside",
469                                      format_vnet_sw_if_index_name,
470                                      vnm, p->sw_if_index);
471           break;
472         }
473     }
474   /* *INDENT-ON* */
475 done:
476   unformat_free (line_input);
477   vec_free (sw_if_indices);
478   return error;
479 }
480
481 static clib_error_t *
482 det44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
483                                   vlib_cli_command_t * cmd)
484 {
485   vnet_main_t *vnm = vnet_get_main ();
486   det44_main_t *dm = &det44_main;
487   det44_interface_t *i;
488   vlib_cli_output (vm, "DET44 interfaces:");
489   /* *INDENT-OFF* */
490   pool_foreach (i, dm->interfaces,
491   ({
492     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
493                      i->sw_if_index,
494                      (det44_interface_is_inside(i) &&
495                       det44_interface_is_outside(i)) ? "in out" :
496                      (det44_interface_is_inside(i) ? "in" : "out"));
497   }));
498   /* *INDENT-ON* */
499   return 0;
500 }
501
502 /* *INDENT-OFF* */
503 /*?
504  * @cliexpar
505  * @cliexstart{det44 add}
506  * Create bijective mapping of inside address to outside address and port range
507  * pairs, with the purpose of enabling DET44 to reduce logging in CGN
508  * deployments.
509  * To create mapping between inside network 10.0.0.0/18 and
510  * outside network 1.1.1.0/30 use:
511  * # vpp# det44 add in 10.0.0.0/18 out 1.1.1.0/30
512  * @cliexend
513 ?*/
514 VLIB_CLI_COMMAND (det44_map_command, static) = {
515     .path = "det44 add",
516     .short_help = "det44 add in <addr>/<plen> out <addr>/<plen> [del]",
517     .function = det44_map_command_fn,
518 };
519
520 /*?
521  * @cliexpar
522  * @cliexpstart{show det44 mappings}
523  * Show DET44 mappings
524  * vpp# show det44 mappings
525  * DET44 mappings:
526  *  in 10.0.0.0/24 out 1.1.1.1/32
527  *   outside address sharing ratio: 256
528  *   number of ports per inside host: 252
529  *   sessions number: 0
530  * @cliexend
531 ?*/
532 VLIB_CLI_COMMAND (det44_show_mappings_command, static) = {
533     .path = "show det44 mappings",
534     .short_help = "show det44 mappings",
535     .function = det44_show_mappings_command_fn,
536 };
537
538 /*?
539  * @cliexpar
540  * @cliexstart{det44 forward}
541  * Return outside address and port range from inside address for DET44.
542  * To obtain outside address and port of inside host use:
543  *  vpp# det44 forward 10.0.0.2
544  *  1.1.1.0:<1054-1068>
545  * @cliexend
546 ?*/
547 VLIB_CLI_COMMAND (det44_forward_command, static) = {
548     .path = "det44 forward",
549     .short_help = "det44 forward <addr>",
550     .function = det44_forward_command_fn,
551 };
552
553 /*?
554  * @cliexpar
555  * @cliexstart{det44 reverse}
556  * Return inside address from outside address and port for DET44.
557  * To obtain inside host address from outside address and port use:
558  *  #vpp det44 reverse 1.1.1.1:1276
559  *  10.0.16.16
560  * @cliexend
561 ?*/
562 VLIB_CLI_COMMAND (det44_reverse_command, static) = {
563     .path = "det44 reverse",
564     .short_help = "det44 reverse <addr>:<port>",
565     .function = det44_reverse_command_fn,
566 };
567
568 /*?
569  * @cliexpar
570  * @cliexstart{show det44 sessions}
571  * Show DET44 sessions.
572  * vpp# show det44 sessions
573  * DET44 sessions:
574  *   in 10.0.0.3:3005 out 1.1.1.2:1146 external host 172.16.1.2:3006 state: udp-active expire: 306
575  *   in 10.0.0.3:3000 out 1.1.1.2:1141 external host 172.16.1.2:3001 state: udp-active expire: 306
576  *   in 10.0.0.4:3005 out 1.1.1.2:1177 external host 172.16.1.2:3006 state: udp-active expire: 306
577  * @cliexend
578 ?*/
579 VLIB_CLI_COMMAND (det44_show_sessions_command, static) = {
580   .path = "show det44 sessions",
581   .short_help = "show det44 sessions",
582   .function = det44_show_sessions_command_fn,
583 };
584
585 /*?
586  * @cliexpar
587  * @cliexstart{det44 close session out}
588  * Close session using outside ip address and port
589  * and external ip address and port, use:
590  *  vpp# det44 close session out 1.1.1.1:1276 2.2.2.2:2387
591  * @cliexend
592 ?*/
593 VLIB_CLI_COMMAND (det44_close_sesion_out_command, static) = {
594   .path = "det44 close session out",
595   .short_help = "det44 close session out "
596                 "<out_addr>:<out_port> <ext_addr>:<ext_port>",
597   .function = det44_close_session_out_fn,
598 };
599
600 /*?
601  * @cliexpar
602  * @cliexstart{det44 deterministic close session in}
603  * Close session using inside ip address and port
604  * and external ip address and port, use:
605  *  vpp# det44 close session in 3.3.3.3:3487 2.2.2.2:2387
606  * @cliexend
607 ?*/
608 VLIB_CLI_COMMAND (det44_close_session_in_command, static) = {
609   .path = "det44 close session in",
610   .short_help = "det44 close session in "
611                 "<in_addr>:<in_port> <ext_addr>:<ext_port>",
612   .function = det44_close_session_in_fn,
613 };
614
615 /*?
616  * @cliexpar
617  * @cliexstart{set det44 timeout}
618  * Set values of timeouts for DET44 sessions (in seconds), use:
619  *  vpp# set det44 timeouts udp 120 tcp established 7500 tcp transitory 250 icmp 90
620  * To reset default values use:
621  *  vpp# set det44 timeouts reset
622  * @cliexend
623 ?*/
624 VLIB_CLI_COMMAND (det44_set_timeouts_command, static) =
625 {
626   .path = "set det44 timeouts",
627   .short_help = "set det44 timeouts <[udp <sec>] [tcp established <sec>] "
628                 "[tcp transitory <sec>] [icmp <sec>]|reset>",
629   .function = det44_set_timeouts_command_fn,
630 };
631
632 /*?
633  * @cliexpar
634  * @cliexstart{show det44 timeouts}
635  * Show values of timeouts for DET44 sessions.
636  * vpp# show det44 timeouts
637  * udp timeout: 300sec
638  * tcp-established timeout: 7440sec
639  * tcp-transitory timeout: 240sec
640  * icmp timeout: 60sec
641  * @cliexend
642 ?*/
643 VLIB_CLI_COMMAND (det44_show_timeouts_command, static) =
644 {
645   .path = "show det44 timeouts",
646   .short_help = "show det44 timeouts",
647   .function = det44_show_timeouts_command_fn,
648 };
649
650 /*?
651  * @cliexpar
652  * @cliexstart{det44 plugin}
653  * Enable/disable DET44 plugin.
654  * @cliexend
655 ?*/
656 VLIB_CLI_COMMAND (det44_plugin_enable_disable_command, static) =
657 {
658   .path = "det44 plugin",
659   .short_help = "det44 plugin <enable [inside vrf] [outside vrf]|disable>",
660   .function = det44_plugin_enable_disable_command_fn,
661 };
662
663 /*?
664  * @cliexpar
665  * @cliexstart{set interface det44}
666  * Enable/disable DET44 feature on the interface.
667  * To enable DET44 feature with local network interface use:
668  *  vpp# set interface det44 inside GigabitEthernet0/8/0
669  * To enable DET44 feature with external network interface use:
670  *  vpp# set interface det44 outside GigabitEthernet0/a/0
671  * @cliexend
672 ?*/
673 VLIB_CLI_COMMAND (det44_feature_command, static) =
674 {
675   .path = "set interface det44",
676   .short_help = "set interface det44 inside <intfc> outside <intfc> [del]",
677   .function = det44_feature_command_fn,
678 };
679
680 /*?
681  * @cliexpar
682  * @cliexstart{show det44 interfaces}
683  * Show interfaces with DET44 feature.
684  * vpp# show det44 interfaces
685  * DET44 interfaces:
686  *  GigabitEthernet0/8/0 in
687  *  GigabitEthernet0/a/0 out
688  * @cliexend
689 ?*/
690 VLIB_CLI_COMMAND (det44_show_interfaces_command, static) =
691 {
692   .path = "show det44 interfaces",
693   .short_help = "show det44 interfaces",
694   .function = det44_show_interfaces_command_fn,
695 };
696 /* *INDENT-ON* */
697
698 /*
699  * fd.io coding-style-patch-verification: ON
700  *
701  * Local Variables:
702  * eval: (c-set-style "gnu")
703  * End:
704  */