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