5e049af34267ff57d60583b70826ce45609078d9
[vpp.git] / src / vnet / ipip / ipip_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 #include "ipip.h"
17 #include <vppinfra/error.h>
18 #include <vnet/vnet.h>
19 #include <vnet/fib/fib_table.h>
20
21 static clib_error_t *
22 create_ipip_tunnel_command_fn (vlib_main_t * vm,
23                                unformat_input_t * input,
24                                vlib_cli_command_t * cmd)
25 {
26   unformat_input_t _line_input, *line_input = &_line_input;
27   ip46_address_t src = ip46_address_initializer, dst =
28     ip46_address_initializer;
29   u32 instance = ~0;
30   u32 fib_index = 0;
31   u32 table_id = 0;
32   int rv;
33   u32 num_m_args = 0;
34   u32 sw_if_index;
35   clib_error_t *error = NULL;
36   bool ip4_set = false, ip6_set = false;
37   tunnel_mode_t mode = TUNNEL_MODE_P2P;
38
39   /* Get a line of input. */
40   if (!unformat_user (input, unformat_line_input, line_input))
41     return 0;
42
43   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
44     {
45       if (unformat (line_input, "instance %d", &instance))
46         ;
47       else
48         if (unformat (line_input, "src %U", unformat_ip4_address, &src.ip4))
49         {
50           num_m_args++;
51           ip4_set = true;
52         }
53       else
54         if (unformat (line_input, "dst %U", unformat_ip4_address, &dst.ip4))
55         {
56           num_m_args++;
57           ip4_set = true;
58         }
59       else
60         if (unformat (line_input, "src %U", unformat_ip6_address, &src.ip6))
61         {
62           num_m_args++;
63           ip6_set = true;
64         }
65       else
66         if (unformat (line_input, "dst %U", unformat_ip6_address, &dst.ip6))
67         {
68           num_m_args++;
69           ip6_set = true;
70         }
71       else if (unformat (line_input, "%U", unformat_tunnel_mode, &mode))
72         {
73           num_m_args++;
74         }
75       else if (unformat (line_input, "outer-table-id %d", &table_id))
76         ;
77       else
78         {
79           error =
80             clib_error_return (0, "unknown input `%U'", format_unformat_error,
81                                line_input);
82           goto done;
83         }
84     }
85
86   if (num_m_args < 2)
87     {
88       error = clib_error_return (0, "mandatory argument(s) missing");
89       goto done;
90     }
91   if (ip4_set && ip6_set)
92     {
93       error =
94         clib_error_return (0,
95                            "source and destination must be of same address family");
96       goto done;
97     }
98
99   fib_index = fib_table_find (fib_ip_proto (ip6_set), table_id);
100
101   if (~0 == fib_index)
102     {
103       rv = VNET_API_ERROR_NO_SUCH_FIB;
104     }
105   else
106     {
107       rv = ipip_add_tunnel (ip6_set ? IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4,
108                             instance,
109                             &src,
110                             &dst,
111                             fib_index,
112                             TUNNEL_ENCAP_DECAP_FLAG_NONE,
113                             IP_DSCP_CS0, mode, &sw_if_index);
114     }
115
116   switch (rv)
117     {
118     case 0:
119       vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name,
120                        vnet_get_main (), sw_if_index);
121       break;
122     case VNET_API_ERROR_IF_ALREADY_EXISTS:
123       error = clib_error_return (0, "IPIP tunnel already exists...");
124       goto done;
125     case VNET_API_ERROR_NO_SUCH_FIB:
126       error =
127         clib_error_return (0, "outer fib ID %d doesn't exist\n", fib_index);
128       goto done;
129     case VNET_API_ERROR_NO_SUCH_ENTRY:
130       error = clib_error_return (0, "IPIP tunnel doesn't exist");
131       goto done;
132     case VNET_API_ERROR_INSTANCE_IN_USE:
133       error = clib_error_return (0, "Instance is in use");
134       goto done;
135     case VNET_API_ERROR_INVALID_DST_ADDRESS:
136       error =
137         clib_error_return (0,
138                            "destination IP address when mode is multi-point");
139       goto done;
140     default:
141       error =
142         clib_error_return (0, "vnet_ipip_add_del_tunnel returned %d", rv);
143       goto done;
144     }
145
146 done:
147   unformat_free (line_input);
148
149   return error;
150 }
151
152 static clib_error_t *
153 delete_ipip_tunnel_command_fn (vlib_main_t * vm,
154                                unformat_input_t * input,
155                                vlib_cli_command_t * cmd)
156 {
157   unformat_input_t _line_input, *line_input = &_line_input;
158   int rv;
159   u32 num_m_args = 0;
160   u32 sw_if_index = ~0;
161   clib_error_t *error = NULL;
162
163   /* Get a line of input. */
164   if (!unformat_user (input, unformat_line_input, line_input))
165     return 0;
166
167   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
168     {
169       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
170         num_m_args++;
171       else
172         {
173           error =
174             clib_error_return (0, "unknown input `%U'", format_unformat_error,
175                                line_input);
176           goto done;
177         }
178     }
179
180   if (num_m_args < 1)
181     {
182       error = clib_error_return (0, "mandatory argument(s) missing");
183       goto done;
184     }
185
186   rv = ipip_del_tunnel (sw_if_index);
187   printf ("RV %d\n", rv);
188
189 done:
190   unformat_free (line_input);
191
192   return error;
193 }
194
195 /* *INDENT-OFF* */
196 VLIB_CLI_COMMAND(create_ipip_tunnel_command, static) = {
197     .path = "create ipip tunnel",
198     .short_help = "create ipip tunnel src <addr> dst <addr> [instance <n>] "
199                   "[outer-table-id <ID>] [p2mp]",
200     .function = create_ipip_tunnel_command_fn,
201 };
202 VLIB_CLI_COMMAND(delete_ipip_tunnel_command, static) = {
203     .path = "delete ipip tunnel",
204     .short_help = "delete ipip tunnel sw_if_index <sw_if_index>",
205     .function = delete_ipip_tunnel_command_fn,
206 };
207 /* *INDENT-ON* */
208
209 static u8 *
210 format_ipip_tunnel (u8 * s, va_list * args)
211 {
212   ipip_tunnel_t *t = va_arg (*args, ipip_tunnel_t *);
213
214   ip46_type_t type =
215     (t->transport == IPIP_TRANSPORT_IP4) ? IP46_TYPE_IP4 : IP46_TYPE_IP6;
216   u32 table_id;
217
218   table_id = fib_table_get_table_id (t->fib_index,
219                                      fib_proto_from_ip46 (type));
220   switch (t->mode)
221     {
222     case IPIP_MODE_6RD:
223       s = format (s, "[%d] 6rd src %U ip6-pfx %U/%d ",
224                   t->dev_instance,
225                   format_ip46_address, &t->tunnel_src, type,
226                   format_ip6_address, &t->sixrd.ip6_prefix,
227                   t->sixrd.ip6_prefix_len);
228       break;
229     case IPIP_MODE_P2P:
230       s = format (s, "[%d] instance %d src %U dst %U ",
231                   t->dev_instance, t->user_instance,
232                   format_ip46_address, &t->tunnel_src, type,
233                   format_ip46_address, &t->tunnel_dst, type);
234       break;
235     case IPIP_MODE_P2MP:
236       s = format (s, "[%d] instance %d p2mp src %U ",
237                   t->dev_instance, t->user_instance,
238                   format_ip46_address, &t->tunnel_src, type);
239       break;
240     }
241
242   s = format (s, "table-ID %d sw-if-idx %d flags [%U] dscp %U",
243               table_id, t->sw_if_index,
244               format_tunnel_encap_decap_flags, t->flags,
245               format_ip_dscp, t->dscp);
246
247   return s;
248 }
249
250 static clib_error_t *
251 show_ipip_tunnel_command_fn (vlib_main_t * vm,
252                              unformat_input_t * input,
253                              vlib_cli_command_t * cmd)
254 {
255   ipip_main_t *gm = &ipip_main;
256   ipip_tunnel_t *t;
257   u32 ti = ~0;
258
259   if (pool_elts (gm->tunnels) == 0)
260     vlib_cli_output (vm, "No IPIP tunnels configured...");
261
262   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
263     {
264       if (unformat (input, "%d", &ti))
265         ;
266       else
267         break;
268     }
269
270   if (ti == ~0)
271     {
272     /* *INDENT-OFF* */
273     pool_foreach(t, gm->tunnels,
274                  ({vlib_cli_output(vm, "%U", format_ipip_tunnel, t); }));
275     /* *INDENT-ON* */
276     }
277   else
278     {
279       if (pool_is_free_index (gm->tunnels, ti))
280         return clib_error_return (0, "unknown index:%d", ti);
281       t = pool_elt_at_index (gm->tunnels, ti);
282       if (t)
283         vlib_cli_output (vm, "%U", format_ipip_tunnel, t);
284     }
285   return 0;
286 }
287
288 /* *INDENT-OFF* */
289 VLIB_CLI_COMMAND(show_ipip_tunnel_command, static) = {
290     .path = "show ipip tunnel",
291     .function = show_ipip_tunnel_command_fn,
292 };
293 /* *INDENT-ON* */
294
295 static u8 *
296 format_ipip_tunnel_key (u8 * s, va_list * args)
297 {
298   ipip_tunnel_key_t *t = va_arg (*args, ipip_tunnel_key_t *);
299
300   s = format (s, "src:%U dst:%U fib:%d transport:%d mode:%d",
301               format_ip46_address, &t->src, IP46_TYPE_ANY,
302               format_ip46_address, &t->dst, IP46_TYPE_ANY,
303               t->fib_index, t->transport, t->mode);
304
305   return (s);
306 }
307
308 static clib_error_t *
309 ipip_tunnel_hash_show (vlib_main_t * vm,
310                        unformat_input_t * input, vlib_cli_command_t * cmd)
311 {
312   ipip_main_t *im = &ipip_main;
313   ipip_tunnel_key_t *key;
314   u32 index;
315
316   /* *INDENT-OFF* */
317   hash_foreach(key, index, im->tunnel_by_key,
318   ({
319       vlib_cli_output (vm, " %U -> %d", format_ipip_tunnel_key, key, index);
320   }));
321   /* *INDENT-ON* */
322
323   return NULL;
324 }
325
326 /**
327  * show IPSEC tunnel protection hash tables
328  */
329 /* *INDENT-OFF* */
330 VLIB_CLI_COMMAND (ipip_tunnel_hash_show_node, static) =
331 {
332   .path = "show ipip tunnel-hash",
333   .function = ipip_tunnel_hash_show,
334   .short_help =  "show ipip tunnel-hash",
335 };
336 /* *INDENT-ON* */
337
338 static clib_error_t *
339 create_sixrd_tunnel_command_fn (vlib_main_t * vm,
340                                 unformat_input_t * input,
341                                 vlib_cli_command_t * cmd)
342 {
343   unformat_input_t _line_input, *line_input = &_line_input;
344   ip4_address_t ip4_prefix;
345   ip6_address_t ip6_prefix;
346   ip4_address_t ip4_src;
347   u32 ip6_prefix_len = 0, ip4_prefix_len = 0, sixrd_tunnel_index;
348   u32 num_m_args = 0;
349   /* Optional arguments */
350   u32 ip4_table_id = 0, ip4_fib_index;
351   u32 ip6_table_id = 0, ip6_fib_index;
352   clib_error_t *error = 0;
353   bool security_check = false;
354   int rv;
355
356   /* Get a line of input. */
357   if (!unformat_user (input, unformat_line_input, line_input))
358     return 0;
359   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
360     {
361       if (unformat (line_input, "security-check"))
362         security_check = true;
363       else if (unformat (line_input, "ip6-pfx %U/%d", unformat_ip6_address,
364                          &ip6_prefix, &ip6_prefix_len))
365         num_m_args++;
366       else if (unformat (line_input, "ip4-pfx %U/%d", unformat_ip4_address,
367                          &ip4_prefix, &ip4_prefix_len))
368         num_m_args++;
369       else
370         if (unformat
371             (line_input, "ip4-src %U", unformat_ip4_address, &ip4_src))
372         num_m_args++;
373       else if (unformat (line_input, "ip4-table-id %d", &ip4_table_id))
374         ;
375       else if (unformat (line_input, "ip6-table-id %d", &ip6_table_id))
376         ;
377       else
378         {
379           error =
380             clib_error_return (0, "unknown input `%U'", format_unformat_error,
381                                line_input);
382           goto done;
383         }
384     }
385
386   if (num_m_args < 3)
387     {
388       error = clib_error_return (0, "mandatory argument(s) missing");
389       goto done;
390     }
391   ip4_fib_index = fib_table_find (FIB_PROTOCOL_IP4, ip4_table_id);
392   ip6_fib_index = fib_table_find (FIB_PROTOCOL_IP6, ip6_table_id);
393
394   if (~0 == ip4_fib_index)
395     {
396       error = clib_error_return (0, "No such IP4 table %d", ip4_table_id);
397       rv = VNET_API_ERROR_NO_SUCH_FIB;
398     }
399   else if (~0 == ip6_fib_index)
400     {
401       error = clib_error_return (0, "No such IP6 table %d", ip6_table_id);
402       rv = VNET_API_ERROR_NO_SUCH_FIB;
403     }
404   else
405     {
406       rv = sixrd_add_tunnel (&ip6_prefix, ip6_prefix_len, &ip4_prefix,
407                              ip4_prefix_len, &ip4_src, security_check,
408                              ip4_fib_index, ip6_fib_index,
409                              &sixrd_tunnel_index);
410
411       if (rv)
412         error = clib_error_return (0, "adding tunnel failed %d", rv);
413     }
414
415 done:
416   unformat_free (line_input);
417
418   return error;
419 }
420
421 static clib_error_t *
422 delete_sixrd_tunnel_command_fn (vlib_main_t * vm,
423                                 unformat_input_t * input,
424                                 vlib_cli_command_t * cmd)
425 {
426   unformat_input_t _line_input, *line_input = &_line_input;
427   u32 num_m_args = 0;
428   /* Optional arguments */
429   clib_error_t *error = 0;
430   u32 sw_if_index = ~0;
431
432   /* Get a line of input. */
433   if (!unformat_user (input, unformat_line_input, line_input))
434     return 0;
435   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
436     {
437       if (unformat (line_input, "sw_if_index %d", &sw_if_index))
438         num_m_args++;
439       else
440         {
441           error =
442             clib_error_return (0, "unknown input `%U'", format_unformat_error,
443                                line_input);
444           goto done;
445         }
446     }
447
448   if (num_m_args < 1)
449     {
450       error = clib_error_return (0, "mandatory argument(s) missing");
451       goto done;
452     }
453   int rv = sixrd_del_tunnel (sw_if_index);
454   printf ("RV %d\n", rv);
455
456 done:
457   unformat_free (line_input);
458
459   return error;
460 }
461
462 /* *INDENT-OFF* */
463 VLIB_CLI_COMMAND(create_sixrd_tunnel_command, static) = {
464     .path = "create 6rd tunnel",
465     .short_help = "create 6rd tunnel ip6-pfx <ip6-pfx> ip4-pfx <ip4-pfx> "
466                   "ip4-src <ip4-addr> ip4-table-id <ID> ip6-table-id <ID> "
467                   "[security-check]",
468     .function = create_sixrd_tunnel_command_fn,
469 };
470 VLIB_CLI_COMMAND(delete_sixrd_tunnel_command, static) = {
471     .path = "delete 6rd tunnel",
472     .short_help = "delete 6rd tunnel sw_if_index <sw_if_index>",
473     .function = delete_sixrd_tunnel_command_fn,
474 };
475 /* *INDENT-ON* */
476
477 /*
478  * fd.io coding-style-patch-verification: ON
479  *
480  * Local Variables:
481  * eval: (c-set-style "gnu")
482  * End:
483  */