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