NAT44: code cleanup and refactor (VPP-1285)
[vpp.git] / src / plugins / nat / 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 <nat/nat64.h>
21 #include <nat/nat.h>
22 #include <nat/nat_inlines.h>
23 #include <vnet/fib/fib_table.h>
24
25 static clib_error_t *
26 nat64_add_del_pool_addr_command_fn (vlib_main_t * vm,
27                                     unformat_input_t * input,
28                                     vlib_cli_command_t * cmd)
29 {
30   unformat_input_t _line_input, *line_input = &_line_input;
31   ip4_address_t start_addr, end_addr, this_addr;
32   u32 start_host_order, end_host_order;
33   int i, count, rv;
34   u32 vrf_id = ~0;
35   u8 is_add = 1;
36   clib_error_t *error = 0;
37
38   /* Get a line of input. */
39   if (!unformat_user (input, unformat_line_input, line_input))
40     return 0;
41
42   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
43     {
44       if (unformat (line_input, "%U - %U",
45                     unformat_ip4_address, &start_addr,
46                     unformat_ip4_address, &end_addr))
47         ;
48       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
49         ;
50       else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr))
51         end_addr = start_addr;
52       else if (unformat (line_input, "del"))
53         is_add = 0;
54       else
55         {
56           error = clib_error_return (0, "unknown input '%U'",
57                                      format_unformat_error, line_input);
58           goto done;
59         }
60     }
61
62   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
63   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
64
65   if (end_host_order < start_host_order)
66     {
67       error = clib_error_return (0, "end address less than start address");
68       goto done;
69     }
70
71   count = (end_host_order - start_host_order) + 1;
72   this_addr = start_addr;
73
74   for (i = 0; i < count; i++)
75     {
76       rv = nat64_add_del_pool_addr (&this_addr, vrf_id, is_add);
77
78       switch (rv)
79         {
80         case VNET_API_ERROR_NO_SUCH_ENTRY:
81           error =
82             clib_error_return (0, "NAT64 pool address %U not exist.",
83                                format_ip4_address, &this_addr);
84           goto done;
85         case VNET_API_ERROR_VALUE_EXIST:
86           error =
87             clib_error_return (0, "NAT64 pool address %U exist.",
88                                format_ip4_address, &this_addr);
89           goto done;
90         default:
91           break;
92
93         }
94       increment_v4_address (&this_addr);
95     }
96
97 done:
98   unformat_free (line_input);
99
100   return error;
101 }
102
103 static int
104 nat64_cli_pool_walk (snat_address_t * ap, void *ctx)
105 {
106   vlib_main_t *vm = ctx;
107
108   if (ap->fib_index != ~0)
109     {
110       fib_table_t *fib;
111       fib = fib_table_get (ap->fib_index, FIB_PROTOCOL_IP6);
112       if (!fib)
113         return -1;
114       vlib_cli_output (vm, " %U tenant VRF: %u", format_ip4_address,
115                        &ap->addr, fib->ft_table_id);
116     }
117   else
118     vlib_cli_output (vm, " %U", format_ip4_address, &ap->addr);
119
120 #define _(N, i, n, s) \
121   vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
122   foreach_snat_protocol
123 #undef _
124     return 0;
125 }
126
127 static clib_error_t *
128 nat64_show_pool_command_fn (vlib_main_t * vm,
129                             unformat_input_t * input,
130                             vlib_cli_command_t * cmd)
131 {
132   vlib_cli_output (vm, "NAT64 pool:");
133   nat64_pool_addr_walk (nat64_cli_pool_walk, vm);
134
135   return 0;
136 }
137
138 static clib_error_t *
139 nat64_interface_feature_command_fn (vlib_main_t * vm,
140                                     unformat_input_t *
141                                     input, vlib_cli_command_t * cmd)
142 {
143   unformat_input_t _line_input, *line_input = &_line_input;
144   vnet_main_t *vnm = vnet_get_main ();
145   clib_error_t *error = 0;
146   u32 sw_if_index;
147   u32 *inside_sw_if_indices = 0;
148   u32 *outside_sw_if_indices = 0;
149   u8 is_add = 1;
150   int i, rv;
151
152   /* Get a line of input. */
153   if (!unformat_user (input, unformat_line_input, line_input))
154     return 0;
155
156   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
157     {
158       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
159                     vnm, &sw_if_index))
160         vec_add1 (inside_sw_if_indices, sw_if_index);
161       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
162                          vnm, &sw_if_index))
163         vec_add1 (outside_sw_if_indices, sw_if_index);
164       else if (unformat (line_input, "del"))
165         is_add = 0;
166       else
167         {
168           error = clib_error_return (0, "unknown input '%U'",
169                                      format_unformat_error, line_input);
170           goto done;
171         }
172     }
173
174   if (vec_len (inside_sw_if_indices))
175     {
176       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
177         {
178           sw_if_index = inside_sw_if_indices[i];
179           rv = nat64_add_del_interface (sw_if_index, 1, is_add);
180           switch (rv)
181             {
182             case VNET_API_ERROR_NO_SUCH_ENTRY:
183               error =
184                 clib_error_return (0, "%U NAT64 feature not enabled.",
185                                    format_vnet_sw_if_index_name, vnm,
186                                    sw_if_index);
187               goto done;
188             case VNET_API_ERROR_VALUE_EXIST:
189               error =
190                 clib_error_return (0, "%U NAT64 feature already enabled.",
191                                    format_vnet_sw_if_index_name, vnm,
192                                    vnm, sw_if_index);
193               goto done;
194             case VNET_API_ERROR_INVALID_VALUE:
195             case VNET_API_ERROR_INVALID_VALUE_2:
196               error =
197                 clib_error_return (0,
198                                    "%U NAT64 feature enable/disable failed.",
199                                    format_vnet_sw_if_index_name, vnm,
200                                    sw_if_index);
201               goto done;
202             default:
203               break;
204
205             }
206         }
207     }
208
209   if (vec_len (outside_sw_if_indices))
210     {
211       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
212         {
213           sw_if_index = outside_sw_if_indices[i];
214           rv = nat64_add_del_interface (sw_if_index, 0, is_add);
215           switch (rv)
216             {
217             case VNET_API_ERROR_NO_SUCH_ENTRY:
218               error =
219                 clib_error_return (0, "%U NAT64 feature not enabled.",
220                                    format_vnet_sw_if_index_name, vnm,
221                                    sw_if_index);
222               goto done;
223             case VNET_API_ERROR_VALUE_EXIST:
224               error =
225                 clib_error_return (0, "%U NAT64 feature already enabled.",
226                                    format_vnet_sw_if_index_name, vnm,
227                                    sw_if_index);
228               goto done;
229             case VNET_API_ERROR_INVALID_VALUE:
230             case VNET_API_ERROR_INVALID_VALUE_2:
231               error =
232                 clib_error_return (0,
233                                    "%U NAT64 feature enable/disable failed.",
234                                    format_vnet_sw_if_index_name, vnm,
235                                    sw_if_index);
236               goto done;
237             default:
238               break;
239
240             }
241         }
242     }
243
244 done:
245   unformat_free (line_input);
246   vec_free (inside_sw_if_indices);
247   vec_free (outside_sw_if_indices);
248
249   return error;
250 }
251
252 static int
253 nat64_cli_interface_walk (snat_interface_t * i, void *ctx)
254 {
255   vlib_main_t *vm = ctx;
256   vnet_main_t *vnm = vnet_get_main ();
257
258   vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
259                    i->sw_if_index,
260                    (nat_interface_is_inside (i)
261                     && nat_interface_is_outside (i)) ? "in out" :
262                    nat_interface_is_inside (i) ? "in" : "out");
263   return 0;
264 }
265
266 static clib_error_t *
267 nat64_show_interfaces_command_fn (vlib_main_t * vm,
268                                   unformat_input_t *
269                                   input, vlib_cli_command_t * cmd)
270 {
271   vlib_cli_output (vm, "NAT64 interfaces:");
272   nat64_interfaces_walk (nat64_cli_interface_walk, vm);
273
274   return 0;
275 }
276
277 static clib_error_t *
278 nat64_add_del_static_bib_command_fn (vlib_main_t *
279                                      vm,
280                                      unformat_input_t
281                                      * input, vlib_cli_command_t * cmd)
282 {
283   unformat_input_t _line_input, *line_input = &_line_input;
284   clib_error_t *error = 0;
285   u8 is_add = 1;
286   ip6_address_t in_addr;
287   ip4_address_t out_addr;
288   u32 in_port = 0;
289   u32 out_port = 0;
290   u32 vrf_id = 0, protocol;
291   snat_protocol_t proto = 0;
292   u8 p = 0;
293   int rv;
294
295   if (!unformat_user (input, unformat_line_input, line_input))
296     return 0;
297
298   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
299     {
300       if (unformat (line_input, "%U %u", unformat_ip6_address,
301                     &in_addr, &in_port))
302         ;
303       else if (unformat (line_input, "%U %u", unformat_ip4_address,
304                          &out_addr, &out_port))
305         ;
306       else if (unformat (line_input, "vrf %u", &vrf_id))
307         ;
308       else if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
309         ;
310       else
311         if (unformat
312             (line_input, "%U %U %u", unformat_ip6_address, &in_addr,
313              unformat_ip4_address, &out_addr, &protocol))
314         p = (u8) protocol;
315       else if (unformat (line_input, "del"))
316         is_add = 0;
317       else
318         {
319           error = clib_error_return (0, "unknown input: '%U'",
320                                      format_unformat_error, line_input);
321           goto done;
322         }
323     }
324
325   if (!p)
326     {
327       if (!in_port)
328         {
329           error =
330             clib_error_return (0, "inside port and address  must be set");
331           goto done;
332         }
333
334       if (!out_port)
335         {
336           error =
337             clib_error_return (0, "outside port and address  must be set");
338           goto done;
339         }
340
341       p = snat_proto_to_ip_proto (proto);
342     }
343
344   rv =
345     nat64_add_del_static_bib_entry (&in_addr, &out_addr, (u16) in_port,
346                                     (u16) out_port, p, vrf_id, is_add);
347
348   switch (rv)
349     {
350     case VNET_API_ERROR_NO_SUCH_ENTRY:
351       error = clib_error_return (0, "NAT64 BIB entry not exist.");
352       goto done;
353     case VNET_API_ERROR_VALUE_EXIST:
354       error = clib_error_return (0, "NAT64 BIB entry exist.");
355       goto done;
356     case VNET_API_ERROR_UNSPECIFIED:
357       error = clib_error_return (0, "Crerate NAT64 BIB entry failed.");
358       goto done;
359     case VNET_API_ERROR_INVALID_VALUE:
360       error =
361         clib_error_return (0, "Outside addres %U and port %u already in use.",
362                            format_ip4_address, &out_addr, out_port);
363       goto done;
364     case VNET_API_ERROR_INVALID_VALUE_2:
365       error = clib_error_return (0, "Invalid outside port.");
366     default:
367       break;
368     }
369
370 done:
371   unformat_free (line_input);
372
373   return error;
374 }
375
376 static int
377 nat64_cli_bib_walk (nat64_db_bib_entry_t * bibe, void *ctx)
378 {
379   vlib_main_t *vm = ctx;
380   fib_table_t *fib;
381
382   fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
383   if (!fib)
384     return -1;
385
386   switch (bibe->proto)
387     {
388     case IP_PROTOCOL_ICMP:
389     case IP_PROTOCOL_TCP:
390     case IP_PROTOCOL_UDP:
391       vlib_cli_output (vm, " %U %u %U %u protocol %U vrf %u %s %u sessions",
392                        format_ip6_address, &bibe->in_addr,
393                        clib_net_to_host_u16 (bibe->in_port),
394                        format_ip4_address, &bibe->out_addr,
395                        clib_net_to_host_u16 (bibe->out_port),
396                        format_snat_protocol,
397                        ip_proto_to_snat_proto (bibe->proto), fib->ft_table_id,
398                        bibe->is_static ? "static" : "dynamic", bibe->ses_num);
399       break;
400     default:
401       vlib_cli_output (vm, " %U %U protocol %u vrf %u %s %u sessions",
402                        format_ip6_address, &bibe->in_addr,
403                        format_ip4_address, &bibe->out_addr,
404                        bibe->proto, fib->ft_table_id,
405                        bibe->is_static ? "static" : "dynamic", bibe->ses_num);
406     }
407   return 0;
408 }
409
410 static clib_error_t *
411 nat64_show_bib_command_fn (vlib_main_t * vm,
412                            unformat_input_t * input, vlib_cli_command_t * cmd)
413 {
414   nat64_main_t *nm = &nat64_main;
415   unformat_input_t _line_input, *line_input = &_line_input;
416   clib_error_t *error = 0;
417   u32 proto = ~0;
418   u8 p = 255;
419   nat64_db_t *db;
420
421   if (!unformat_user (input, unformat_line_input, line_input))
422     return 0;
423
424   if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
425     p = snat_proto_to_ip_proto (proto);
426   else if (unformat (line_input, "unknown"))
427     p = 0;
428   else if (unformat (line_input, "all"))
429     ;
430   else
431     {
432       error = clib_error_return (0, "unknown input: '%U'",
433                                  format_unformat_error, line_input);
434       goto done;
435     }
436
437   if (p == 255)
438     vlib_cli_output (vm, "NAT64 BIB entries:");
439   else
440     vlib_cli_output (vm, "NAT64 %U BIB entries:", format_snat_protocol,
441                      proto);
442
443   /* *INDENT-OFF* */
444   vec_foreach (db, nm->db)
445     nat64_db_bib_walk (db, p, nat64_cli_bib_walk, vm);
446   /* *INDENT-ON* */
447
448 done:
449   unformat_free (line_input);
450
451   return error;
452 }
453
454 static clib_error_t *
455 nat64_set_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input,
456                                vlib_cli_command_t * cmd)
457 {
458   unformat_input_t _line_input, *line_input = &_line_input;
459   clib_error_t *error = 0;
460   u32 timeout, tcp_trans, tcp_est, tcp_incoming_syn;
461
462   tcp_trans = nat64_get_tcp_trans_timeout ();
463   tcp_est = nat64_get_tcp_est_timeout ();
464   tcp_incoming_syn = nat64_get_tcp_incoming_syn_timeout ();
465
466   if (!unformat_user (input, unformat_line_input, line_input))
467     return 0;
468
469   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
470     {
471       if (unformat (line_input, "udp %u", &timeout))
472         {
473           if (nat64_set_udp_timeout (timeout))
474             {
475               error = clib_error_return (0, "Invalid UDP timeout value");
476               goto done;
477             }
478         }
479       else if (unformat (line_input, "icmp %u", &timeout))
480         {
481           if (nat64_set_icmp_timeout (timeout))
482             {
483               error = clib_error_return (0, "Invalid ICMP timeout value");
484               goto done;
485             }
486         }
487       else if (unformat (line_input, "tcp-trans %u", &tcp_trans))
488         {
489           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
490             {
491               error =
492                 clib_error_return (0,
493                                    "Invalid TCP transitory timeouts value");
494               goto done;
495             }
496         }
497       else if (unformat (line_input, "tcp-est %u", &tcp_est))
498         {
499           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
500             {
501               error =
502                 clib_error_return (0,
503                                    "Invalid TCP established timeouts value");
504               goto done;
505             }
506         }
507       else
508         if (unformat (line_input, "tcp-incoming-syn %u", &tcp_incoming_syn))
509         {
510           if (nat64_set_tcp_timeouts (tcp_trans, tcp_est, tcp_incoming_syn))
511             {
512               error =
513                 clib_error_return (0,
514                                    "Invalid TCP incoming SYN timeouts value");
515               goto done;
516             }
517         }
518       else if (unformat (line_input, "reset"))
519         {
520           nat64_set_udp_timeout (0);
521           nat64_set_icmp_timeout (0);
522           nat64_set_tcp_timeouts (0, 0, 0);
523         }
524       else
525         {
526           error = clib_error_return (0, "unknown input '%U'",
527                                      format_unformat_error, line_input);
528           goto done;
529         }
530     }
531
532 done:
533   unformat_free (line_input);
534
535   return error;
536 }
537
538 static clib_error_t *
539 nat64_show_timeouts_command_fn (vlib_main_t * vm, unformat_input_t * input,
540                                 vlib_cli_command_t * cmd)
541 {
542   vlib_cli_output (vm, "NAT64 session timeouts:");
543   vlib_cli_output (vm, " UDP %usec", nat64_get_udp_timeout ());
544   vlib_cli_output (vm, " ICMP %usec", nat64_get_icmp_timeout ());
545   vlib_cli_output (vm, " TCP transitory %usec",
546                    nat64_get_tcp_trans_timeout ());
547   vlib_cli_output (vm, " TCP established %usec",
548                    nat64_get_tcp_est_timeout ());
549   vlib_cli_output (vm, " TCP incoming SYN %usec",
550                    nat64_get_tcp_incoming_syn_timeout ());
551
552   return 0;
553 }
554
555 typedef struct nat64_cli_st_walk_ctx_t_
556 {
557   vlib_main_t *vm;
558   nat64_db_t *db;
559 } nat64_cli_st_walk_ctx_t;
560
561 static int
562 nat64_cli_st_walk (nat64_db_st_entry_t * ste, void *arg)
563 {
564   nat64_cli_st_walk_ctx_t *ctx = arg;
565   vlib_main_t *vm = ctx->vm;
566   nat64_db_bib_entry_t *bibe;
567   fib_table_t *fib;
568
569   bibe = nat64_db_bib_entry_by_index (ctx->db, ste->proto, ste->bibe_index);
570   if (!bibe)
571     return -1;
572
573   fib = fib_table_get (bibe->fib_index, FIB_PROTOCOL_IP6);
574   if (!fib)
575     return -1;
576
577   u32 vrf_id = fib->ft_table_id;
578
579   if (ste->proto == IP_PROTOCOL_ICMP)
580     vlib_cli_output (vm, " %U %U %u %U %U %u protocol %U vrf %u",
581                      format_ip6_address, &bibe->in_addr,
582                      format_ip6_address, &ste->in_r_addr,
583                      clib_net_to_host_u16 (bibe->in_port),
584                      format_ip4_address, &bibe->out_addr,
585                      format_ip4_address, &ste->out_r_addr,
586                      clib_net_to_host_u16 (bibe->out_port),
587                      format_snat_protocol,
588                      ip_proto_to_snat_proto (bibe->proto), vrf_id);
589   else if (ste->proto == IP_PROTOCOL_TCP || ste->proto == IP_PROTOCOL_UDP)
590     vlib_cli_output (vm, " %U %u %U %u %U %u %U %u protcol %U vrf %u",
591                      format_ip6_address, &bibe->in_addr,
592                      clib_net_to_host_u16 (bibe->in_port),
593                      format_ip6_address, &ste->in_r_addr,
594                      clib_net_to_host_u16 (ste->r_port),
595                      format_ip4_address, &bibe->out_addr,
596                      clib_net_to_host_u16 (bibe->out_port),
597                      format_ip4_address, &ste->out_r_addr,
598                      clib_net_to_host_u16 (ste->r_port),
599                      format_snat_protocol,
600                      ip_proto_to_snat_proto (bibe->proto), vrf_id);
601   else
602     vlib_cli_output (vm, " %U %U %U %U protocol %u vrf %u",
603                      format_ip6_address, &bibe->in_addr,
604                      format_ip6_address, &ste->in_r_addr,
605                      format_ip4_address, &bibe->out_addr,
606                      format_ip4_address, &ste->out_r_addr,
607                      bibe->proto, vrf_id);
608
609   return 0;
610 }
611
612 static clib_error_t *
613 nat64_show_st_command_fn (vlib_main_t * vm,
614                           unformat_input_t * input, vlib_cli_command_t * cmd)
615 {
616   nat64_main_t *nm = &nat64_main;
617   unformat_input_t _line_input, *line_input = &_line_input;
618   clib_error_t *error = 0;
619   u32 proto = ~0;
620   u8 p = 255;
621   nat64_db_t *db;
622   nat64_cli_st_walk_ctx_t ctx = {
623     .vm = vm,
624   };
625
626   if (!unformat_user (input, unformat_line_input, line_input))
627     return 0;
628
629   if (unformat (line_input, "%U", unformat_snat_protocol, &proto))
630     p = snat_proto_to_ip_proto (proto);
631   else if (unformat (line_input, "unknown"))
632     p = 0;
633   else if (unformat (line_input, "all"))
634     ;
635   else
636     {
637       error = clib_error_return (0, "unknown input: '%U'",
638                                  format_unformat_error, line_input);
639       goto done;
640     }
641
642   if (p == 255)
643     vlib_cli_output (vm, "NAT64 sessions:");
644   else
645     vlib_cli_output (vm, "NAT64 %U sessions:", format_snat_protocol, proto);
646   /* *INDENT-OFF* */
647   vec_foreach (db, nm->db)
648     {
649       ctx.db = db;
650       nat64_db_st_walk (db, p, nat64_cli_st_walk, &ctx);
651     }
652   /* *INDENT-ON* */
653
654 done:
655   unformat_free (line_input);
656
657   return error;
658 }
659
660 static clib_error_t *
661 nat64_add_del_prefix_command_fn (vlib_main_t * vm, unformat_input_t * input,
662                                  vlib_cli_command_t * cmd)
663 {
664   vnet_main_t *vnm = vnet_get_main ();
665   clib_error_t *error = 0;
666   unformat_input_t _line_input, *line_input = &_line_input;
667   u8 is_add = 1;
668   u32 vrf_id = 0, sw_if_index = ~0;
669   ip6_address_t prefix;
670   u32 plen = 0;
671   int rv;
672
673   if (!unformat_user (input, unformat_line_input, line_input))
674     return 0;
675
676   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
677     {
678       if (unformat
679           (line_input, "%U/%u", unformat_ip6_address, &prefix, &plen))
680         ;
681       else if (unformat (line_input, "tenant-vrf %u", &vrf_id))
682         ;
683       else if (unformat (line_input, "del"))
684         is_add = 0;
685       else
686         if (unformat
687             (line_input, "interface %U", unformat_vnet_sw_interface, vnm,
688              &sw_if_index))
689         ;
690       else
691         {
692           error = clib_error_return (0, "unknown input: '%U'",
693                                      format_unformat_error, line_input);
694           goto done;
695         }
696     }
697
698   if (!plen)
699     {
700       error = clib_error_return (0, "NAT64 prefix must be set.");
701       goto done;
702     }
703
704   rv = nat64_add_del_prefix (&prefix, (u8) plen, vrf_id, is_add);
705
706   switch (rv)
707     {
708     case VNET_API_ERROR_NO_SUCH_ENTRY:
709       error = clib_error_return (0, "NAT64 prefix not exist.");
710       goto done;
711     case VNET_API_ERROR_INVALID_VALUE:
712       error = clib_error_return (0, "Invalid prefix length.");
713       goto done;
714     default:
715       break;
716     }
717
718   /*
719    * Add RX interface route, whenNAT isn't running on the real input
720    * interface
721    */
722   if (sw_if_index != ~0)
723     {
724       u32 fib_index;
725       fib_prefix_t fibpfx = {
726         .fp_len = plen,
727         .fp_proto = FIB_PROTOCOL_IP6,
728         .fp_addr = {
729                     .ip6 = prefix}
730       };
731
732       if (is_add)
733         {
734           fib_index =
735             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6,
736                                                vrf_id, FIB_SOURCE_PLUGIN_HI);
737           fib_table_entry_update_one_path (fib_index, &fibpfx,
738                                            FIB_SOURCE_PLUGIN_HI,
739                                            FIB_ENTRY_FLAG_NONE,
740                                            DPO_PROTO_IP6, NULL,
741                                            sw_if_index, ~0, 0,
742                                            NULL, FIB_ROUTE_PATH_INTF_RX);
743         }
744       else
745         {
746           fib_index = fib_table_find (FIB_PROTOCOL_IP6, vrf_id);
747           fib_table_entry_path_remove (fib_index, &fibpfx,
748                                        FIB_SOURCE_PLUGIN_HI,
749                                        DPO_PROTO_IP6, NULL,
750                                        sw_if_index, ~0, 1,
751                                        FIB_ROUTE_PATH_INTF_RX);
752           fib_table_unlock (fib_index, FIB_PROTOCOL_IP6,
753                             FIB_SOURCE_PLUGIN_HI);
754         }
755     }
756
757 done:
758   unformat_free (line_input);
759
760   return error;
761 }
762
763 static int
764 nat64_cli_prefix_walk (nat64_prefix_t * p, void *ctx)
765 {
766   vlib_main_t *vm = ctx;
767
768   vlib_cli_output (vm, " %U/%u tenant-vrf %u",
769                    format_ip6_address, &p->prefix, p->plen, p->vrf_id);
770
771   return 0;
772 }
773
774 static clib_error_t *
775 nat64_show_prefix_command_fn (vlib_main_t * vm,
776                               unformat_input_t * input,
777                               vlib_cli_command_t * cmd)
778 {
779   vlib_cli_output (vm, "NAT64 prefix:");
780   nat64_prefix_walk (nat64_cli_prefix_walk, vm);
781
782   return 0;
783 }
784
785 static clib_error_t *
786 nat64_add_interface_address_command_fn (vlib_main_t * vm,
787                                         unformat_input_t * input,
788                                         vlib_cli_command_t * cmd)
789 {
790   vnet_main_t *vnm = vnet_get_main ();
791   unformat_input_t _line_input, *line_input = &_line_input;
792   u32 sw_if_index;
793   int rv;
794   int is_add = 1;
795   clib_error_t *error = 0;
796
797   /* Get a line of input. */
798   if (!unformat_user (input, unformat_line_input, line_input))
799     return 0;
800
801   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
802     {
803       if (unformat
804           (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index));
805       else if (unformat (line_input, "del"))
806         is_add = 0;
807       else
808         {
809           error = clib_error_return (0, "unknown input '%U'",
810                                      format_unformat_error, line_input);
811           goto done;
812         }
813     }
814
815   rv = nat64_add_interface_address (sw_if_index, is_add);
816
817   switch (rv)
818     {
819     case VNET_API_ERROR_NO_SUCH_ENTRY:
820       error = clib_error_return (0, "entry not exist");
821       break;
822     case VNET_API_ERROR_VALUE_EXIST:
823       error = clib_error_return (0, "entry exist");
824       break;
825     default:
826       break;
827     }
828
829 done:
830   unformat_free (line_input);
831
832   return error;
833 }
834
835 /* *INDENT-OFF* */
836
837 /*?
838  * @cliexpar
839  * @cliexstart{nat64 add pool address}
840  * Add/delete NAT64 pool address.
841  * To add single NAT64 pool address use:
842  *  vpp# nat64 add pool address 10.1.1.10
843  * To add NAT64 pool address range use:
844  *  vpp# nat64 add pool address 10.1.1.2 - 10.1.1.5
845  * To add NAT64 pool address for specific tenant use:
846  *  vpp# nat64 add pool address 10.1.1.100 tenant-vrf 100
847  * @cliexend
848 ?*/
849 VLIB_CLI_COMMAND (nat64_add_pool_address_command, static) = {
850   .path = "nat64 add pool address",
851   .short_help = "nat64 add pool address <ip4-range-start> [- <ip4-range-end>] "
852                 "[tenant-vrf <vrf-id>] [del]",
853   .function = nat64_add_del_pool_addr_command_fn,
854 };
855
856 /*?
857  * @cliexpar
858  * @cliexstart{show nat64 pool}
859  * Show NAT64 pool.
860  *  vpp# show nat64 pool
861  *  NAT64 pool:
862  *   10.1.1.3 tenant VRF: 0
863  *   10.1.1.10 tenant VRF: 10
864  * @cliexend
865 ?*/
866 VLIB_CLI_COMMAND (show_nat64_pool_command, static) = {
867   .path = "show nat64 pool",
868   .short_help = "show nat64 pool",
869   .function = nat64_show_pool_command_fn,
870 };
871
872 /*?
873  * @cliexpar
874  * @cliexstart{set interface nat64}
875  * Enable/disable NAT64 feature on the interface.
876  * To enable NAT64 feature with local (IPv6) network interface
877  * GigabitEthernet0/8/0 and external (IPv4) network interface
878  * GigabitEthernet0/a/0 use:
879  *  vpp# set interface nat64 in GigabitEthernet0/8/0 out GigabitEthernet0/a/0
880  * @cliexend
881 ?*/
882 VLIB_CLI_COMMAND (set_interface_nat64_command, static) = {
883   .path = "set interface nat64",
884   .short_help = "set interface nat64 in|out <intfc> [del]",
885   .function = nat64_interface_feature_command_fn,
886 };
887
888 /*?
889  * @cliexpar
890  * @cliexstart{show nat64 interfaces}
891  * Show interfaces with NAT64 feature.
892  * To show interfaces with NAT64 feature use:
893  *  vpp# show nat64 interfaces
894  *  NAT64 interfaces:
895  *   GigabitEthernet0/8/0 in
896  *   GigabitEthernet0/a/0 out
897  * @cliexend
898 ?*/
899 VLIB_CLI_COMMAND (show_nat64_interfaces_command, static) = {
900   .path = "show nat64 interfaces",
901   .short_help = "show nat64 interfaces",
902   .function = nat64_show_interfaces_command_fn,
903 };
904
905 /*?
906  * @cliexpar
907  * @cliexstart{nat64 add static bib}
908  * Add/delete NAT64 static BIB entry.
909  * To create NAT64 satatic BIB entry use:
910  *  vpp# nat64 add static bib 2001:db8:c000:221:: 1234 10.1.1.3 5678 tcp
911  *  vpp# nat64 add static bib 2001:db8:c000:221:: 1234 10.1.1.3 5678 udp vrf 10
912  * @cliexend
913 ?*/
914 VLIB_CLI_COMMAND (nat64_add_del_static_bib_command, static) = {
915   .path = "nat64 add static bib",
916   .short_help = "nat64 add static bib <ip6-addr> <port> <ip4-addr> <port> "
917                 "tcp|udp|icmp [vfr <table-id>] [del]",
918   .function = nat64_add_del_static_bib_command_fn,
919 };
920
921 /*?
922  * @cliexpar
923  * @cliexstart{show nat64 bib}
924  * Show NAT64 BIB entries.
925  * To show NAT64 TCP BIB entries use:
926  *  vpp# show nat64 bib tcp
927  *  NAT64 tcp BIB:
928  *   fd01:1::2 6303 10.0.0.3 62303 tcp vrf 0 dynamic 1 sessions
929  *   2001:db8:c000:221:: 1234 10.1.1.3 5678 tcp vrf 0 static 2 sessions
930  * To show NAT64 UDP BIB entries use:
931  *  vpp# show nat64 bib udp
932  *  NAT64 udp BIB:
933  *   fd01:1::2 6304 10.0.0.3 10546 udp vrf 0 dynamic 10 sessions
934  *   2001:db8:c000:221:: 1234 10.1.1.3 5678 udp vrf 10 static 0 sessions
935  * To show NAT64 ICMP BIB entries use:
936  *  vpp# show nat64 bib icmp
937  *  NAT64 icmp BIB:
938  *   fd01:1::2 6305 10.0.0.3 63209 icmp vrf 10 dynamic 1 sessions
939  * @cliexend
940 ?*/
941 VLIB_CLI_COMMAND (show_nat64_bib_command, static) = {
942   .path = "show nat64 bib",
943   .short_help = "show nat64 bib all|tcp|udp|icmp|unknown",
944   .function = nat64_show_bib_command_fn,
945 };
946
947 /*?
948  * @cliexpar
949  * @cliexstart{set nat64 timeouts}
950  * Set NAT64 session timeouts (in seconds).
951  * To set NAT64 session timeoutes use use:
952  *  vpp# set nat64 timeouts udp 200 icmp 30 tcp-trans 250 tcp-est 7450
953  * To reset NAT64 session timeoutes to default values use:
954  *  vpp# set nat64 timeouts reset
955  * @cliexend
956 ?*/
957 VLIB_CLI_COMMAND (set_nat64_timeouts_command, static) = {
958   .path = "set nat64 timeouts",
959   .short_help = "set nat64 timeouts udp <sec> icmp <sec> tcp-trans <sec> "
960                 "tcp-est <sec> tcp-incoming-syn <sec> | reset",
961   .function = nat64_set_timeouts_command_fn,
962 };
963
964 /*?
965  * @cliexpar
966  * @cliexstart{show nat64 timeoutss}
967  * Show NAT64 session timeouts:
968  *  vpp# show nat64 timeouts
969  *  NAT64 session timeouts:
970  *   UDP 300sec
971  *   ICMP 60sec
972  *   TCP transitory 240sec
973  *   TCP established 7440sec
974  *   TCP incoming SYN 6sec
975  * @cliexend
976 ?*/
977 VLIB_CLI_COMMAND (show_nat64_timeouts_command, static) = {
978   .path = "show nat64 timeouts",
979   .short_help = "show nat64 timeouts",
980   .function = nat64_show_timeouts_command_fn,
981 };
982
983 /*?
984  * @cliexpar
985  * @cliexstart{show nat64 session table}
986  * Show NAT64 session table.
987  * To show NAT64 TCP session table use:
988  *  vpp# show nat64 session table tcp
989  *  NAT64 tcp session table:
990  *   fd01:1::2 6303 64:ff9b::ac10:202 20 10.0.0.3 62303 172.16.2.2 20 tcp vrf 0
991  *   fd01:3::2 6303 64:ff9b::ac10:202 20 10.0.10.3 21300 172.16.2.2 20 tcp vrf 10
992  * To show NAT64 UDP session table use:
993  * #vpp show nat64 session table udp
994  * NAT64 udp session table:
995  *  fd01:1::2 6304 64:ff9b::ac10:202 20 10.0.0.3 10546 172.16.2.2 20 udp vrf 0
996  *  fd01:3::2 6304 64:ff9b::ac10:202 20 10.0.10.3 58627 172.16.2.2 20 udp vrf 10
997  *  fd01:1::2 1235 64:ff9b::a00:3 4023 10.0.0.3 24488 10.0.0.3 4023 udp vrf 0
998  *  fd01:1::3 23 64:ff9b::a00:3 24488 10.0.0.3 4023 10.0.0.3 24488 udp vrf 0
999  * To show NAT64 ICMP session table use:
1000  * #vpp show nat64 session table icmp
1001  * NAT64 icmp session table:
1002  *  fd01:1::2 64:ff9b::ac10:202 6305 10.0.0.3 172.16.2.2 63209 icmp vrf 0
1003  * @cliexend
1004 ?*/
1005 VLIB_CLI_COMMAND (show_nat64_st_command, static) = {
1006   .path = "show nat64 session table",
1007   .short_help = "show nat64 session table all|tcp|udp|icmp|unknown",
1008   .function = nat64_show_st_command_fn,
1009 };
1010
1011 /*?
1012  * @cliexpar
1013  * @cliexstart{nat64 add prefix}
1014  * Set NAT64 prefix for generating IPv6 representations of IPv4 addresses.
1015  * To set NAT64 global prefix use:
1016  *  vpp# nat64 add prefix 2001:db8::/32
1017  * To set NAT64 prefix for specific tenant use:
1018  *  vpp# nat64 add prefix 2001:db8:122:300::/56 tenant-vrf 10
1019  * @cliexend
1020 ?*/
1021 VLIB_CLI_COMMAND (nat64_add_del_prefix_command, static) = {
1022   .path = "nat64 add prefix",
1023   .short_help = "nat64 add prefix <ip6-prefix>/<plen> [tenant-vrf <vrf-id>] "
1024                 "[del] [interface <interface]",
1025   .function = nat64_add_del_prefix_command_fn,
1026 };
1027
1028 /*?
1029  * @cliexpar
1030  * @cliexstart{show nat64 prefix}
1031  * Show NAT64 prefix.
1032  * To show NAT64 prefix use:
1033  *  vpp# show nat64 prefix
1034  *  NAT64 prefix:
1035  *   2001:db8::/32 tenant-vrf 0
1036  *   2001:db8:122:300::/56 tenant-vrf 10
1037  * @cliexend
1038 ?*/
1039 VLIB_CLI_COMMAND (show_nat64_prefix_command, static) = {
1040   .path = "show nat64 prefix",
1041   .short_help = "show nat64 prefix",
1042   .function = nat64_show_prefix_command_fn,
1043 };
1044
1045 /*?
1046  * @cliexpar
1047  * @cliexstart{nat64 add interface address}
1048  * Add/delete NAT64 pool address from specific (DHCP addressed) interface.
1049  * To add NAT64 pool address from specific interface use:
1050  *  vpp# nat64 add interface address GigabitEthernet0/8/0
1051  * @cliexend
1052 ?*/
1053 VLIB_CLI_COMMAND (nat64_add_interface_address_command, static) = {
1054     .path = "nat64 add interface address",
1055     .short_help = "nat64 add interface address <interface> [del]",
1056     .function = nat64_add_interface_address_command_fn,
1057 };
1058 /* *INDENT-ON* */
1059
1060 /*
1061  * fd.io coding-style-patch-verification: ON
1062  *
1063  * Local Variables:
1064  * eval: (c-set-style "gnu")
1065  * End:
1066  */