acl-plugin: bihash-based ACL lookup
[vpp.git] / src / plugins / snat / nat64_cli.c
1 /*
2  * Copyright (c) 2017 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 NAT64 CLI
18  */
19
20 #include <snat/nat64.h>
21 #include <snat/snat.h>
22 #include <vnet/fib/fib_table.h>
23
24 static clib_error_t *
25 nat64_add_del_pool_addr_command_fn (vlib_main_t * vm,
26                                     unformat_input_t * input,
27                                     vlib_cli_command_t * cmd)
28 {
29   unformat_input_t _line_input, *line_input = &_line_input;
30   ip4_address_t start_addr, end_addr, this_addr;
31   u32 start_host_order, end_host_order;
32   int i, count, rv;
33   u32 vrf_id = ~0;
34   u8 is_add = 1;
35   clib_error_t *error = 0;
36
37   /* Get a line of input. */
38   if (!unformat_user (input, unformat_line_input, line_input))
39     return 0;
40
41   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
42     {
43       if (unformat (line_input, "%U - %U",
44                     unformat_ip4_address, &start_addr,
45                     unformat_ip4_address, &end_addr))
46         ;
47       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
48         ;
49       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
50         end_addr = start_addr;
51       else if (unformat (line_input, "del"))
52         is_add = 0;
53       else
54         {
55           error = clib_error_return (0, "unknown input '%U'",
56                                      format_unformat_error, line_input);
57           goto done;
58         }
59     }
60
61   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
62   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
63
64   if (end_host_order < start_host_order)
65     {
66       error = clib_error_return (0, "end address less than start address");
67       goto done;
68     }
69
70   count = (end_host_order - start_host_order) + 1;
71   this_addr = start_addr;
72
73   for (i = 0; i < count; i++)
74     {
75       rv = nat64_add_del_pool_addr (&this_addr, vrf_id, is_add);
76
77       switch (rv)
78         {
79         case VNET_API_ERROR_NO_SUCH_ENTRY:
80           error =
81             clib_error_return (0, "NAT64 pool address %U not exist.",
82                                format_ip4_address, &this_addr);
83           goto done;
84         case VNET_API_ERROR_VALUE_EXIST:
85           error =
86             clib_error_return (0, "NAT64 pool address %U exist.",
87                                format_ip4_address, &this_addr);
88           goto done;
89         default:
90           break;
91
92         }
93       increment_v4_address (&this_addr);
94     }
95
96 done:
97   unformat_free (line_input);
98
99   return error;
100 }
101
102 static int
103 nat64_cli_pool_walk (snat_address_t * ap, void *ctx)
104 {
105   vlib_main_t *vm = ctx;
106
107   if (ap->fib_index != ~0)
108     {
109       fib_table_t *fib;
110       fib = fib_table_get (ap->fib_index, FIB_PROTOCOL_IP6);
111       if (!fib)
112         return -1;
113       vlib_cli_output (vm, " %U tenant VRF: %u", format_ip4_address,
114                        &ap->addr, fib->ft_table_id);
115     }
116   else
117     vlib_cli_output (vm, " %U", format_ip4_address, &ap->addr);
118
119   return 0;
120 }
121
122 static clib_error_t *
123 nat64_show_pool_command_fn (vlib_main_t * vm,
124                             unformat_input_t * input,
125                             vlib_cli_command_t * cmd)
126 {
127   vlib_cli_output (vm, "NAT64 pool:");
128   nat64_pool_addr_walk (nat64_cli_pool_walk, vm);
129
130   return 0;
131 }
132
133 static clib_error_t *
134 nat64_interface_feature_command_fn (vlib_main_t * vm,
135                                     unformat_input_t *
136                                     input, vlib_cli_command_t * cmd)
137 {
138   unformat_input_t _line_input, *line_input = &_line_input;
139   vnet_main_t *vnm = vnet_get_main ();
140   clib_error_t *error = 0;
141   u32 sw_if_index;
142   u32 *inside_sw_if_indices = 0;
143   u32 *outside_sw_if_indices = 0;
144   u8 is_add = 1;
145   int i, rv;
146
147   /* Get a line of input. */
148   if (!unformat_user (input, unformat_line_input, line_input))
149     return 0;
150
151   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
152     {
153       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
154                     vnm, &sw_if_index))
155         vec_add1 (inside_sw_if_indices, sw_if_index);
156       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
157                          vnm, &sw_if_index))
158         vec_add1 (outside_sw_if_indices, sw_if_index);
159       else if (unformat (line_input, "del"))
160         is_add = 0;
161       else
162         {
163           error = clib_error_return (0, "unknown input '%U'",
164                                      format_unformat_error, line_input);
165           goto done;
166         }
167     }
168
169   if (vec_len (inside_sw_if_indices))
170     {
171       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
172         {
173           sw_if_index = inside_sw_if_indices[i];
174           rv = nat64_add_del_interface (sw_if_index, 1, is_add);
175           switch (rv)
176             {
177             case VNET_API_ERROR_NO_SUCH_ENTRY:
178               error =
179                 clib_error_return (0, "%U NAT64 feature not enabled.",
180                                    format_vnet_sw_interface_name, vnm,
181                                    vnet_get_sw_interface (vnm, sw_if_index));
182               goto done;
183             case VNET_API_ERROR_VALUE_EXIST:
184               error =
185                 clib_error_return (0, "%U NAT64 feature already enabled.",
186                                    format_vnet_sw_interface_name, vnm,
187                                    vnet_get_sw_interface (vnm, sw_if_index));
188               goto done;
189             case VNET_API_ERROR_INVALID_VALUE:
190             case VNET_API_ERROR_INVALID_VALUE_2:
191               error =
192                 clib_error_return (0,
193                                    "%U NAT64 feature enable/disable failed.",
194                                    format_vnet_sw_interface_name, vnm,
195                                    vnet_get_sw_interface (vnm, sw_if_index));
196               goto done;
197             default:
198               break;
199
200             }
201         }
202     }
203
204   if (vec_len (outside_sw_if_indices))
205     {
206       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
207         {
208           sw_if_index = outside_sw_if_indices[i];
209           rv = nat64_add_del_interface (sw_if_index, 0, is_add);
210           switch (rv)
211             {
212             case VNET_API_ERROR_NO_SUCH_ENTRY:
213               error =
214                 clib_error_return (0, "%U NAT64 feature not enabled.",
215                                    format_vnet_sw_interface_name, vnm,
216                                    vnet_get_sw_interface (vnm, sw_if_index));
217               goto done;
218             case VNET_API_ERROR_VALUE_EXIST:
219               error =
220                 clib_error_return (0, "%U NAT64 feature already enabled.",
221                                    format_vnet_sw_interface_name, vnm,
222                                    vnet_get_sw_interface (vnm, sw_if_index));
223               goto done;
224             case VNET_API_ERROR_INVALID_VALUE:
225             case VNET_API_ERROR_INVALID_VALUE_2:
226               error =
227                 clib_error_return (0,
228                                    "%U NAT64 feature enable/disable failed.",
229                                    format_vnet_sw_interface_name, vnm,
230                                    vnet_get_sw_interface (vnm, sw_if_index));
231               goto done;
232             default:
233               break;
234
235             }
236         }
237     }
238
239 done:
240   unformat_free (line_input);
241   vec_free (inside_sw_if_indices);
242   vec_free (outside_sw_if_indices);
243
244   return error;
245 }
246
247 static int
248 nat64_cli_interface_walk (snat_interface_t * i, void *ctx)
249 {
250   vlib_main_t *vm = ctx;
251   vnet_main_t *vnm = vnet_get_main ();
252
253   vlib_cli_output (vm, " %U %s", format_vnet_sw_interface_name, vnm,
254                    vnet_get_sw_interface (vnm, i->sw_if_index),
255                    i->is_inside ? "in" : "out");
256   return 0;
257 }
258
259 static clib_error_t *
260 nat64_show_interfaces_command_fn (vlib_main_t * vm,
261                                   unformat_input_t *
262                                   input, vlib_cli_command_t * cmd)
263 {
264   vlib_cli_output (vm, "NAT64 interfaces:");
265   nat64_interfaces_walk (nat64_cli_interface_walk, vm);
266
267   return 0;
268 }
269
270 static clib_error_t *
271 nat64_add_del_static_bib_command_fn (vlib_main_t *
272                                      vm,
273                                      unformat_input_t
274                                      * input, vlib_cli_command_t * cmd)
275 {
276   unformat_input_t _line_input, *line_input = &_line_input;
277   clib_error_t *error = 0;
278   u8 is_add = 1;
279   ip6_address_t in_addr;
280   ip4_address_t out_addr;
281   u16 in_port = 0;
282   u16 out_port = 0;
283   u32 vrf_id = 0;
284   snat_protocol_t proto = 0;
285   u8 p = 0;
286   int rv;
287
288   if (!unformat_user (input, unformat_line_input, line_input))
289     return 0;
290
291   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
292     {
293       if (unformat (line_input, "%U %u", unformat_ip6_address,
294                     &in_addr, &in_port))
295         ;
296       else if (unformat (line_input, "%U %u", unformat_ip4_address,
297                          &out_addr, &out_port))
298         ;
299       else if (unformat (line_input, "vrf %u", &vrf_id))
300         ;
301       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
302         ;
303       else if (unformat (line_input, "del"))
304         is_add = 0;
305       else
306         {
307           error = clib_error_return (0, "unknown input: '%U'",
308                                      format_unformat_error, line_input);
309           goto done;
310         }
311     }
312
313   if (!in_port)
314     {
315       error = clib_error_return (0, "inside port and address  must be set");
316       goto done;
317     }
318
319   if (!out_port)
320     {
321       error = clib_error_return (0, "outside port and address  must be set");
322       goto done;
323     }
324
325   p = snat_proto_to_ip_proto (proto);
326
327   rv =
328     nat64_add_del_static_bib_entry (&in_addr, &out_addr, in_port, out_port, p,
329                                     vrf_id, is_add);
330
331   switch (rv)
332     {
333     case VNET_API_ERROR_NO_SUCH_ENTRY:
334       error = clib_error_return (0, "NAT64 BIB entry not exist.");
335       goto done;
336     case VNET_API_ERROR_VALUE_EXIST:
337       error = clib_error_return (0, "NAT64 BIB entry exist.");
338       goto done;
339     case VNET_API_ERROR_UNSPECIFIED:
340       error = clib_error_return (0, "Crerate NAT64 BIB entry failed.");
341       goto done;
342     case VNET_API_ERROR_INVALID_VALUE:
343       error =
344         clib_error_return (0, "Outside addres %U and port %u already in use.",
345                            format_ip4_address, &out_addr, out_port);
346       goto done;
347     default:
348       break;
349     }
350
351 done:
352   unformat_free (line_input);
353
354   return error;
355 }
356
357 static int
358 nat64_cli_bib_walk (nat64_db_bib_entry_t * bibe, void *ctx)
359 {
360   vlib_main_t *vm = ctx;
361   fib_table_t *fib;
362
363   fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
364   if (!fib)
365     return -1;
366
367   vlib_cli_output (vm, " %U %u %U %u %U vrf %u %s %u sessions",
368                    format_ip6_address, &bibe->in_addr,
369                    clib_net_to_host_u16 (bibe->in_port), format_ip4_address,
370                    &bibe->out_addr, clib_net_to_host_u16 (bibe->out_port),
371                    format_snat_protocol, bibe->proto, fib->ft_table_id,
372                    bibe->is_static ? "static" : "dynamic", bibe->ses_num);
373   return 0;
374 }
375
376 static clib_error_t *
377 nat64_show_bib_command_fn (vlib_main_t * vm,
378                            unformat_input_t * input, vlib_cli_command_t * cmd)
379 {
380   nat64_main_t *nm = &nat64_main;
381   unformat_input_t _line_input, *line_input = &_line_input;
382   clib_error_t *error = 0;
383   snat_protocol_t proto = 0;
384
385   if (!unformat_user (input, unformat_line_input, line_input))
386     return 0;
387
388   if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
389     ;
390   else
391     {
392       error = clib_error_return (0, "unknown input: '%U'",
393                                  format_unformat_error, line_input);
394       goto done;
395     }
396
397   vlib_cli_output (vm, "NAT64 %U BIB:", format_snat_protocol, proto);
398   nat64_db_bib_walk (&nm->db, proto, nat64_cli_bib_walk, vm);
399
400 done:
401   unformat_free (line_input);
402
403   return error;
404 }
405
406 static clib_error_t *
407 nat64_set_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input,
408                                vlib_cli_command_t * cmd)
409 {
410   unformat_input_t _line_input, *line_input = &_line_input;
411   clib_error_t *error = 0;
412   u32 timeout, tcp_trans, tcp_est, tcp_incoming_syn;
413
414   tcp_trans = nat64_get_tcp_trans_timeout ();
415   tcp_est = nat64_get_tcp_est_timeout ();
416   tcp_incoming_syn = nat64_get_tcp_incoming_syn_timeout ();
417
418   if (!unformat_user (input, unformat_line_input, line_input))
419     return 0;
420
421   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
422     {
423       if (unformat (line_input, "udp %u", &timeout))
424         {
425           if (nat64_set_udp_timeout (timeout))
426             {
427               error = clib_error_return (0, "Invalid UDP timeout value");
428               goto done;
429             }
430         }
431       else if (unformat (line_input, "icmp %u", &timeout))
432         {
433           if (nat64_set_icmp_timeout (timeout))
434             {
435               error = clib_error_return (0, "Invalid ICMP timeout value");
436               goto done;
437             }
438         }
439       else if (unformat (line_input, "tcp-trans %u", &tcp_trans))
440         {
441           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
442             {
443               error =
444                 clib_error_return (0, "Invalid TCP transitory tiemout value");
445               goto done;
446             }
447         }
448       else if (unformat (line_input, "tcp-est %u", &tcp_est))
449         {
450           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
451             {
452               error =
453                 clib_error_return (0,
454                                    "Invalid TCP established tiemout value");
455               goto done;
456             }
457         }
458       else
459         if (unformat (line_input, "tcp-incoming-syn %u", &tcp_incoming_syn))
460         {
461           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
462             {
463               error =
464                 clib_error_return (0,
465                                    "Invalid TCP incoming SYN tiemout value");
466               goto done;
467             }
468         }
469       else if (unformat (line_input, "reset"))
470         {
471           nat64_set_udp_timeout (0);
472           nat64_set_icmp_timeout (0);
473           nat64_set_tcp_timeouts (0, 0, 0);
474         }
475       else
476         {
477           error = clib_error_return (0, "unknown input '%U'",
478                                      format_unformat_error, line_input);
479           goto done;
480         }
481     }
482
483 done:
484   unformat_free (line_input);
485
486   return error;
487 }
488
489 static clib_error_t *
490 nat64_show_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input,
491                                 vlib_cli_command_t * cmd)
492 {
493   vlib_cli_output (vm, "NAT64 session timeouts:");
494   vlib_cli_output (vm, " UDP %usec", nat64_get_udp_timeout ());
495   vlib_cli_output (vm, " ICMP %usec", nat64_get_icmp_timeout ());
496   vlib_cli_output (vm, " TCP transitory %usec",
497                    nat64_get_tcp_trans_timeout ());
498   vlib_cli_output (vm, " TCP established %usec",
499                    nat64_get_tcp_est_timeout ());
500   vlib_cli_output (vm, " TCP incoming SYN %usec",
501                    nat64_get_tcp_incoming_syn_timeout ());
502
503   return 0;
504 }
505
506 static int
507 nat64_cli_st_walk (nat64_db_st_entry_t * ste, void *ctx)
508 {
509   vlib_main_t *vm = ctx;
510   nat64_main_t *nm = &nat64_main;
511   nat64_db_bib_entry_t *bibe;
512   fib_table_t *fib;
513
514   bibe = nat64_db_bib_entry_by_index (&nm->db, ste->proto, ste->bibe_index);
515   if (!bibe)
516     return -1;
517
518   fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
519   if (!fib)
520     return -1;
521
522   u32 vrf_id = fib->ft_table_id;
523
524   if (ste->proto == SNAT_PROTOCOL_ICMP)
525     vlib_cli_output (vm, " %U %U %u %U %U %u %U vrf %u",
526                      format_ip6_address, &bibe->in_addr,
527                      format_ip6_address, &ste->in_r_addr,
528                      clib_net_to_host_u16 (bibe->in_port),
529                      format_ip4_address, &bibe->out_addr,
530                      format_ip4_address, &ste->out_r_addr,
531                      clib_net_to_host_u16 (bibe->out_port),
532                      format_snat_protocol, bibe->proto, vrf_id);
533   else
534     vlib_cli_output (vm, " %U %u %U %u %U %u %U %u %U vrf %u",
535                      format_ip6_address, &bibe->in_addr,
536                      clib_net_to_host_u16 (bibe->in_port),
537                      format_ip6_address, &ste->in_r_addr,
538                      clib_net_to_host_u16 (ste->r_port),
539                      format_ip4_address, &bibe->out_addr,
540                      clib_net_to_host_u16 (bibe->out_port),
541                      format_ip4_address, &ste->out_r_addr,
542                      clib_net_to_host_u16 (ste->r_port),
543                      format_snat_protocol, bibe->proto, vrf_id);
544   return 0;
545 }
546
547 static clib_error_t *
548 nat64_show_st_command_fn (vlib_main_t * vm,
549                           unformat_input_t * input, vlib_cli_command_t * cmd)
550 {
551   nat64_main_t *nm = &nat64_main;
552   unformat_input_t _line_input, *line_input = &_line_input;
553   clib_error_t *error = 0;
554   snat_protocol_t proto = 0;
555
556   if (!unformat_user (input, unformat_line_input, line_input))
557     return 0;
558
559   if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
560     ;
561   else
562     {
563       error = clib_error_return (0, "unknown input: '%U'",
564                                  format_unformat_error, line_input);
565       goto done;
566     }
567
568   vlib_cli_output (vm, "NAT64 %U session table:", format_snat_protocol,
569                    proto);
570   nat64_db_st_walk (&nm->db, proto, nat64_cli_st_walk, vm);
571
572 done:
573   unformat_free (line_input);
574
575   return error;
576 }
577
578 /* *INDENT-OFF* */
579
580 VLIB_CLI_COMMAND (nat64_add_pool_address_command, static) = {
581   .path = "nat64 add pool address",
582   .short_help = "nat64 add pool address <ip4-range-start> [- <ip4-range-end>] "
583                 "[tenant-vrf <vrf-id>] [del]",
584   .function = nat64_add_del_pool_addr_command_fn,
585 };
586
587 VLIB_CLI_COMMAND (show_nat64_pool_command, static) = {
588   .path = "show nat64 pool",
589   .short_help = "show nat64 pool",
590   .function = nat64_show_pool_command_fn,
591 };
592
593 VLIB_CLI_COMMAND (set_interface_nat64_command, static) = {
594   .path = "set interface nat64",
595   .short_help = "set interface nat64 in|out <intfc> [del]",
596   .function = nat64_interface_feature_command_fn,
597 };
598
599 VLIB_CLI_COMMAND (show_nat64_interfaces_command, static) = {
600   .path = "show nat64 interfaces",
601   .short_help = "show nat64 interfaces",
602   .function = nat64_show_interfaces_command_fn,
603 };
604
605 VLIB_CLI_COMMAND (nat64_add_del_static_bib_command, static) = {
606   .path = "nat64 add static bib",
607   .short_help = "nat64 add static bib <ip6-addr> <port> <ip4-addr> <port> "
608                 "tcp|udp|icmp [vfr <table-id>] [del]",
609   .function = nat64_add_del_static_bib_command_fn,
610 };
611
612 VLIB_CLI_COMMAND (show_nat64_bib_command, static) = {
613   .path = "show nat64 bib",
614   .short_help = "show nat64 bib tcp|udp|icmp",
615   .function = nat64_show_bib_command_fn,
616 };
617
618 VLIB_CLI_COMMAND (set_nat64_timeouts_command, static) = {
619   .path = "set nat64 timeouts",
620   .short_help = "set nat64 timeouts udp <sec> icmp <sec> tcp-trans <sec> "
621                 "tcp-est <sec> tcp-incoming-syn <sec> | reset",
622   .function = nat64_set_timeouts_command_fn,
623 };
624
625 VLIB_CLI_COMMAND (show_nat64_timeouts_command, static) = {
626   .path = "show nat64 tiemouts",
627   .short_help = "show nat64 tiemouts",
628   .function = nat64_show_timeouts_command_fn,
629 };
630
631 VLIB_CLI_COMMAND (show_nat64_st_command, static) = {
632   .path = "show nat64 session table",
633   .short_help = "show nat64 session table tcp|udp|icmp",
634   .function = nat64_show_st_command_fn,
635 };
636
637 /* *INDENT-ON* */
638
639 /*
640  * fd.io coding-style-patch-verification: ON
641  *
642  * Local Variables:
643  * eval: (c-set-style "gnu")
644  * End:
645  */