nat: fixing cfg file parsing cli issues
[vpp.git] / src / plugins / nat / nat66 / nat66_cli.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT66 CLI
18  */
19
20 #include <nat/nat66/nat66.h>
21 #include <vnet/fib/fib_table.h>
22
23 #define NAT66_EXPECTED_ARGUMENT "expected required argument(s)"
24 #define NAT66_PLUGIN_DISABLED   "error plugin disabled"
25
26 #define CHECK_ENABLED()                                                       \
27   do                                                                          \
28     {                                                                         \
29       if (PREDICT_FALSE (!nat66_main.enabled))                                \
30         {                                                                     \
31           return clib_error_return (0, NAT66_PLUGIN_DISABLED);                \
32         }                                                                     \
33     }                                                                         \
34   while (0)
35
36 static clib_error_t *
37 nat66_enable_disable_command_fn (vlib_main_t *vm, unformat_input_t *input,
38                                  vlib_cli_command_t *cmd)
39 {
40   nat66_main_t *nm = &nat66_main;
41   unformat_input_t _line_input, *line_input = &_line_input;
42   clib_error_t *error = 0;
43
44   u32 outside_vrf = 0;
45   u8 enable_set = 0, enable = 0;
46
47   if (!unformat_user (input, unformat_line_input, line_input))
48     return clib_error_return (0, NAT66_EXPECTED_ARGUMENT);
49
50   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
51     {
52       if (unformat (line_input, "outside-vrf %u", &outside_vrf))
53         ;
54       else if (!enable_set)
55         {
56           enable_set = 1;
57           if (unformat (line_input, "disable"))
58             ;
59           else if (unformat (line_input, "enable"))
60             enable = 1;
61         }
62       else
63         {
64           error = clib_error_return (0, "unknown input '%U'",
65                                      format_unformat_error, line_input);
66           goto done;
67         }
68     }
69
70   if (!enable_set)
71     {
72       error = clib_error_return (0, "expected enable | disable");
73       goto done;
74     }
75
76   if (enable)
77     {
78       if (nm->enabled)
79         {
80           error = clib_error_return (0, "already enabled");
81           goto done;
82         }
83
84       if (nat66_plugin_enable (outside_vrf) != 0)
85         error = clib_error_return (0, "enable failed");
86     }
87   else
88     {
89       if (!nm->enabled)
90         {
91           error = clib_error_return (0, "already disabled");
92           goto done;
93         }
94
95       if (nat66_plugin_disable () != 0)
96         error = clib_error_return (0, "disable failed");
97     }
98
99 done:
100   unformat_free (line_input);
101   return error;
102 }
103
104 static clib_error_t *
105 nat66_interface_feature_command_fn (vlib_main_t * vm,
106                                     unformat_input_t * input,
107                                     vlib_cli_command_t * cmd)
108 {
109   unformat_input_t _line_input, *line_input = &_line_input;
110   vnet_main_t *vnm = vnet_get_main ();
111   clib_error_t *error = 0;
112   u32 sw_if_index;
113   u32 *inside_sw_if_indices = 0;
114   u32 *outside_sw_if_indices = 0;
115   u8 is_add = 1;
116   int i, rv;
117
118   CHECK_ENABLED ();
119
120   if (!unformat_user (input, unformat_line_input, line_input))
121     return clib_error_return (0, NAT66_EXPECTED_ARGUMENT);
122
123   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
124     {
125       if (unformat (line_input, "in %U", unformat_vnet_sw_interface,
126                     vnm, &sw_if_index))
127         vec_add1 (inside_sw_if_indices, sw_if_index);
128       else if (unformat (line_input, "out %U", unformat_vnet_sw_interface,
129                          vnm, &sw_if_index))
130         vec_add1 (outside_sw_if_indices, sw_if_index);
131       else if (unformat (line_input, "del"))
132         is_add = 0;
133       else
134         {
135           error = clib_error_return (0, "unknown input '%U'",
136                                      format_unformat_error, line_input);
137           goto done;
138         }
139     }
140
141   if (vec_len (inside_sw_if_indices))
142     {
143       for (i = 0; i < vec_len (inside_sw_if_indices); i++)
144         {
145           sw_if_index = inside_sw_if_indices[i];
146           rv = nat66_interface_add_del (sw_if_index, 1, is_add);
147           switch (rv)
148             {
149             case VNET_API_ERROR_NO_SUCH_ENTRY:
150               error =
151                 clib_error_return (0, "%U NAT66 feature not enabled.",
152                                    format_vnet_sw_interface_name, vnm,
153                                    vnet_get_sw_interface (vnm, sw_if_index));
154               goto done;
155             case VNET_API_ERROR_VALUE_EXIST:
156               error =
157                 clib_error_return (0, "%U NAT66 feature already enabled.",
158                                    format_vnet_sw_interface_name, vnm,
159                                    vnet_get_sw_interface (vnm, sw_if_index));
160               goto done;
161             case VNET_API_ERROR_INVALID_VALUE:
162             case VNET_API_ERROR_INVALID_VALUE_2:
163               error =
164                 clib_error_return (0,
165                                    "%U NAT66 feature enable/disable failed.",
166                                    format_vnet_sw_interface_name, vnm,
167                                    vnet_get_sw_interface (vnm, sw_if_index));
168               goto done;
169             default:
170               break;
171
172             }
173         }
174     }
175
176   if (vec_len (outside_sw_if_indices))
177     {
178       for (i = 0; i < vec_len (outside_sw_if_indices); i++)
179         {
180           sw_if_index = outside_sw_if_indices[i];
181           rv = nat66_interface_add_del (sw_if_index, 0, is_add);
182           switch (rv)
183             {
184             case VNET_API_ERROR_NO_SUCH_ENTRY:
185               error =
186                 clib_error_return (0, "%U NAT66 feature not enabled.",
187                                    format_vnet_sw_interface_name, vnm,
188                                    vnet_get_sw_interface (vnm, sw_if_index));
189               goto done;
190             case VNET_API_ERROR_VALUE_EXIST:
191               error =
192                 clib_error_return (0, "%U NAT66 feature already enabled.",
193                                    format_vnet_sw_interface_name, vnm,
194                                    vnet_get_sw_interface (vnm, sw_if_index));
195               goto done;
196             case VNET_API_ERROR_INVALID_VALUE:
197             case VNET_API_ERROR_INVALID_VALUE_2:
198               error =
199                 clib_error_return (0,
200                                    "%U NAT66 feature enable/disable failed.",
201                                    format_vnet_sw_interface_name, vnm,
202                                    vnet_get_sw_interface (vnm, sw_if_index));
203               goto done;
204             default:
205               break;
206
207             }
208         }
209     }
210
211 done:
212   unformat_free (line_input);
213   vec_free (inside_sw_if_indices);
214   vec_free (outside_sw_if_indices);
215
216   return error;
217 }
218
219 static int
220 nat66_cli_interface_walk (nat66_interface_t * i, void *ctx)
221 {
222   vlib_main_t *vm = ctx;
223   vnet_main_t *vnm = vnet_get_main ();
224   vlib_cli_output (vm, " %U %s", format_vnet_sw_interface_name, vnm,
225                    vnet_get_sw_interface (vnm, i->sw_if_index),
226                    nat66_interface_is_inside (i) ? "in" : "out");
227   return 0;
228 }
229
230 static clib_error_t *
231 nat66_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
232                                   vlib_cli_command_t * cmd)
233 {
234   CHECK_ENABLED ();
235   vlib_cli_output (vm, "NAT66 interfaces:");
236   nat66_interfaces_walk (nat66_cli_interface_walk, vm);
237   return 0;
238 }
239
240 static clib_error_t *
241 nat66_add_del_static_mapping_command_fn (vlib_main_t * vm,
242                                          unformat_input_t * input,
243                                          vlib_cli_command_t * cmd)
244 {
245   unformat_input_t _line_input, *line_input = &_line_input;
246   clib_error_t *error = 0;
247   ip6_address_t l_addr, e_addr;
248   u32 vrf_id = 0;
249   u8 is_add = 1;
250   int rv;
251
252   CHECK_ENABLED ();
253
254   if (!unformat_user (input, unformat_line_input, line_input))
255     return clib_error_return (0, NAT66_EXPECTED_ARGUMENT);
256
257   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
258     {
259       if (unformat (line_input, "local %U external %U",
260                     unformat_ip6_address, &l_addr,
261                     unformat_ip6_address, &e_addr))
262         ;
263       else if (unformat (line_input, "vrf %u", &vrf_id))
264         ;
265       else if (unformat (line_input, "del"))
266         is_add = 0;
267       else
268         {
269           error = clib_error_return (0, "unknown input: '%U'",
270                                      format_unformat_error, line_input);
271           goto done;
272         }
273     }
274
275   rv = nat66_static_mapping_add_del (&l_addr, &e_addr, vrf_id, is_add);
276
277   switch (rv)
278     {
279     case VNET_API_ERROR_NO_SUCH_ENTRY:
280       error = clib_error_return (0, "NAT66 static mapping entry not exist.");
281       goto done;
282     case VNET_API_ERROR_VALUE_EXIST:
283       error = clib_error_return (0, "NAT66 static mapping entry exist.");
284       goto done;
285     default:
286       break;
287     }
288
289 done:
290   unformat_free (line_input);
291
292   return error;
293 }
294
295 static int
296 nat66_cli_static_mapping_walk (nat66_static_mapping_t * sm, void *ctx)
297 {
298   nat66_main_t *nm = &nat66_main;
299   vlib_main_t *vm = ctx;
300   fib_table_t *fib;
301   vlib_counter_t vc;
302
303   fib = fib_table_get (sm->fib_index, FIB_PROTOCOL_IP6);
304   if (!fib)
305     return -1;
306
307   vlib_get_combined_counter (&nm->session_counters, sm - nm->sm, &vc);
308
309   vlib_cli_output (vm, " local %U external %U vrf %d",
310                    format_ip6_address, &sm->l_addr,
311                    format_ip6_address, &sm->e_addr, fib->ft_table_id);
312   vlib_cli_output (vm, "  total pkts %lld, total bytes %lld", vc.packets,
313                    vc.bytes);
314
315   return 0;
316 }
317
318 static clib_error_t *
319 nat66_show_static_mappings_command_fn (vlib_main_t * vm,
320                                        unformat_input_t * input,
321                                        vlib_cli_command_t * cmd)
322 {
323   CHECK_ENABLED ();
324   vlib_cli_output (vm, "NAT66 static mappings:");
325   nat66_static_mappings_walk (nat66_cli_static_mapping_walk, vm);
326   return 0;
327 }
328
329 /*?
330  * @cliexpar
331  * @cliexstart{nat66}
332  * To enable NAT66 plugin
333  *  vpp# nat66 enable
334  * To disable NAT66 plugin
335  *  vpp# nat66 disable
336  * To enable NAT66 plugin with outside-vrf id 10
337  *  vpp# nat66 enable outside-vrf 10
338  * @cliexend
339 ?*/
340 VLIB_CLI_COMMAND (nat66_enable_disable_command, static) = {
341   .path = "nat66",
342   .short_help = "nat66 <enable [outside-vrf <vrf-id>]>|disable",
343   .function = nat66_enable_disable_command_fn,
344 };
345
346 /*?
347  * @cliexpar
348  * @cliexstart{set interface nat66}
349  * Enable/disable NAT66 feature on the interface.
350  * To enable NAT66 feature with local (IPv6) network interface
351  * GigabitEthernet0/8/0 and external (IPv4) network interface
352  * GigabitEthernet0/a/0 use:
353  *  vpp# set interface nat66 in GigabitEthernet0/8/0 out GigabitEthernet0/a/0
354  * @cliexend
355 ?*/
356 VLIB_CLI_COMMAND (set_interface_nat66_command, static) = {
357   .path = "set interface nat66",
358   .short_help = "set interface nat66 in|out <intfc> [del]",
359   .function = nat66_interface_feature_command_fn,
360 };
361
362 /*?
363  * @cliexpar
364  * @cliexstart{show nat66 interfaces}
365  * Show interfaces with NAT66 feature.
366  * To show interfaces with NAT66 feature use:
367  *  vpp# show nat66 interfaces
368  *  NAT66 interfaces:
369  *   GigabitEthernet0/8/0 in
370  *   GigabitEthernet0/a/0 out
371  * @cliexend
372 ?*/
373 VLIB_CLI_COMMAND (show_nat66_interfaces_command, static) = {
374   .path = "show nat66 interfaces",
375   .short_help = "show nat66 interfaces",
376   .function = nat66_show_interfaces_command_fn,
377 };
378
379 /*?
380  * @cliexpar
381  * @cliexstart{nat66 add static mapping}
382  * Add/delete NAT66 static mapping entry.
383  * To add NAT66 static mapping entry use:
384  *  vpp# nat66 add static mapping local fd01:1::4 external 2001:db8:c000:223::
385  *  vpp# nat66 add static mapping local fd01:1::2 external 2001:db8:c000:221:: vrf 10
386  * @cliexend
387 ?*/
388 VLIB_CLI_COMMAND (show_nat66_add_del_static_mapping_command, static) = {
389   .path = "nat66 add static mapping",
390   .short_help = "nat66 add static mapping local <ip6-addr> external <ip6-addr>"
391                 " [vfr <table-id>] [del]",
392   .function = nat66_add_del_static_mapping_command_fn,
393 };
394
395 /*?
396  * @cliexpar
397  * @cliexstart{show nat66 static mappings}
398  * Show NAT66 static mappings.
399  * To show NAT66 static mappings use:
400  *  vpp# show nat66 static mappings
401  *  NAT66 static mappings:
402  *   local fd01:1::4 external 2001:db8:c000:223:: vrf 0
403  *   local fd01:1::2 external 2001:db8:c000:221:: vrf 10
404  * @cliexend
405 ?*/
406 VLIB_CLI_COMMAND (show_nat66_static_mappings_command, static) = {
407   .path = "show nat66 static mappings",
408   .short_help = "show nat66 static mappings",
409   .function = nat66_show_static_mappings_command_fn,
410 };
411
412 /*
413  * fd.io coding-style-patch-verification: ON
414  *
415  * Local Variables:
416  * eval: (c-set-style "gnu")
417  * End:
418  */