ipsec: infra for selecting backends
[vpp.git] / src / vnet / ipsec / ipsec_cli.c
1 /*
2  * decap.c : IPSec tunnel support
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/interface.h>
22
23 #include <vnet/ipsec/ipsec.h>
24
25 static clib_error_t *
26 set_interface_spd_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   ipsec_main_t *im = &ipsec_main;
32   u32 sw_if_index = (u32) ~ 0;
33   u32 spd_id;
34   int is_add = 1;
35   clib_error_t *error = NULL;
36
37   if (!unformat_user (input, unformat_line_input, line_input))
38     return 0;
39
40   if (unformat
41       (line_input, "%U %u", unformat_vnet_sw_interface, im->vnet_main,
42        &sw_if_index, &spd_id))
43     ;
44   else if (unformat (line_input, "del"))
45     is_add = 0;
46   else
47     {
48       error = clib_error_return (0, "parse error: '%U'",
49                                  format_unformat_error, line_input);
50       goto done;
51     }
52
53   ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add);
54
55 done:
56   unformat_free (line_input);
57
58   return error;
59 }
60
61 /* *INDENT-OFF* */
62 VLIB_CLI_COMMAND (set_interface_spd_command, static) = {
63     .path = "set interface ipsec spd",
64     .short_help =
65     "set interface ipsec spd <int> <id>",
66     .function = set_interface_spd_command_fn,
67 };
68 /* *INDENT-ON* */
69
70 static clib_error_t *
71 ipsec_sa_add_del_command_fn (vlib_main_t * vm,
72                              unformat_input_t * input,
73                              vlib_cli_command_t * cmd)
74 {
75   ipsec_main_t *im = &ipsec_main;
76   unformat_input_t _line_input, *line_input = &_line_input;
77   ipsec_sa_t sa;
78   int is_add = ~0;
79   u8 *ck = 0, *ik = 0;
80   clib_error_t *error = NULL;
81
82   clib_memset (&sa, 0, sizeof (sa));
83
84   if (!unformat_user (input, unformat_line_input, line_input))
85     return 0;
86
87   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
88     {
89       if (unformat (line_input, "add %u", &sa.id))
90         is_add = 1;
91       else if (unformat (line_input, "del %u", &sa.id))
92         is_add = 0;
93       else if (unformat (line_input, "spi %u", &sa.spi))
94         ;
95       else if (unformat (line_input, "esp"))
96         sa.protocol = IPSEC_PROTOCOL_ESP;
97       else if (unformat (line_input, "ah"))
98         {
99           sa.protocol = IPSEC_PROTOCOL_AH;
100         }
101       else
102         if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck))
103         sa.crypto_key_len = vec_len (ck);
104       else
105         if (unformat
106             (line_input, "crypto-alg %U", unformat_ipsec_crypto_alg,
107              &sa.crypto_alg))
108         {
109           if (sa.crypto_alg < IPSEC_CRYPTO_ALG_NONE ||
110               sa.crypto_alg >= IPSEC_CRYPTO_N_ALG)
111             {
112               error = clib_error_return (0, "unsupported crypto-alg: '%U'",
113                                          format_ipsec_crypto_alg,
114                                          sa.crypto_alg);
115               goto done;
116             }
117         }
118       else
119         if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik))
120         sa.integ_key_len = vec_len (ik);
121       else if (unformat (line_input, "integ-alg %U", unformat_ipsec_integ_alg,
122                          &sa.integ_alg))
123         {
124           if (sa.integ_alg < IPSEC_INTEG_ALG_NONE ||
125               sa.integ_alg >= IPSEC_INTEG_N_ALG)
126             {
127               error = clib_error_return (0, "unsupported integ-alg: '%U'",
128                                          format_ipsec_integ_alg,
129                                          sa.integ_alg);
130               goto done;
131             }
132         }
133       else if (unformat (line_input, "tunnel-src %U",
134                          unformat_ip4_address, &sa.tunnel_src_addr.ip4))
135         sa.is_tunnel = 1;
136       else if (unformat (line_input, "tunnel-dst %U",
137                          unformat_ip4_address, &sa.tunnel_dst_addr.ip4))
138         sa.is_tunnel = 1;
139       else if (unformat (line_input, "tunnel-src %U",
140                          unformat_ip6_address, &sa.tunnel_src_addr.ip6))
141         {
142           sa.is_tunnel = 1;
143           sa.is_tunnel_ip6 = 1;
144         }
145       else if (unformat (line_input, "tunnel-dst %U",
146                          unformat_ip6_address, &sa.tunnel_dst_addr.ip6))
147         {
148           sa.is_tunnel = 1;
149           sa.is_tunnel_ip6 = 1;
150         }
151       else if (unformat (line_input, "udp-encap"))
152         {
153           sa.udp_encap = 1;
154         }
155       else
156         {
157           error = clib_error_return (0, "parse error: '%U'",
158                                      format_unformat_error, line_input);
159           goto done;
160         }
161     }
162
163   if (sa.crypto_key_len > sizeof (sa.crypto_key))
164     sa.crypto_key_len = sizeof (sa.crypto_key);
165
166   if (sa.integ_key_len > sizeof (sa.integ_key))
167     sa.integ_key_len = sizeof (sa.integ_key);
168
169   if (ck)
170     strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len);
171
172   if (ik)
173     strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len);
174
175   if (is_add)
176     {
177       error = ipsec_check_support_cb (im, &sa);
178       if (error)
179         goto done;
180     }
181
182   ipsec_add_del_sa (vm, &sa, is_add);
183
184 done:
185   unformat_free (line_input);
186
187   return error;
188 }
189
190 /* *INDENT-OFF* */
191 VLIB_CLI_COMMAND (ipsec_sa_add_del_command, static) = {
192     .path = "ipsec sa",
193     .short_help =
194     "ipsec sa [add|del]",
195     .function = ipsec_sa_add_del_command_fn,
196 };
197 /* *INDENT-ON* */
198
199 static clib_error_t *
200 ipsec_spd_add_del_command_fn (vlib_main_t * vm,
201                               unformat_input_t * input,
202                               vlib_cli_command_t * cmd)
203 {
204   unformat_input_t _line_input, *line_input = &_line_input;
205   u32 spd_id = ~0;
206   int is_add = ~0;
207   clib_error_t *error = NULL;
208
209   if (!unformat_user (input, unformat_line_input, line_input))
210     return 0;
211
212   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
213     {
214       if (unformat (line_input, "add"))
215         is_add = 1;
216       else if (unformat (line_input, "del"))
217         is_add = 0;
218       else if (unformat (line_input, "%u", &spd_id))
219         ;
220       else
221         {
222           error = clib_error_return (0, "parse error: '%U'",
223                                      format_unformat_error, line_input);
224           goto done;
225         }
226     }
227
228   if (spd_id == ~0)
229     {
230       error = clib_error_return (0, "please specify SPD ID");
231       goto done;
232     }
233
234   ipsec_add_del_spd (vm, spd_id, is_add);
235
236 done:
237   unformat_free (line_input);
238
239   return error;
240 }
241
242 /* *INDENT-OFF* */
243 VLIB_CLI_COMMAND (ipsec_spd_add_del_command, static) = {
244     .path = "ipsec spd",
245     .short_help =
246     "ipsec spd [add|del] <id>",
247     .function = ipsec_spd_add_del_command_fn,
248 };
249 /* *INDENT-ON* */
250
251
252 static clib_error_t *
253 ipsec_policy_add_del_command_fn (vlib_main_t * vm,
254                                  unformat_input_t * input,
255                                  vlib_cli_command_t * cmd)
256 {
257   unformat_input_t _line_input, *line_input = &_line_input;
258   ipsec_policy_t p;
259   int is_add = 0;
260   int is_ip_any = 1;
261   u32 tmp, tmp2;
262   clib_error_t *error = NULL;
263
264   clib_memset (&p, 0, sizeof (p));
265   p.lport.stop = p.rport.stop = ~0;
266   p.laddr.stop.ip4.as_u32 = p.raddr.stop.ip4.as_u32 = (u32) ~ 0;
267   p.laddr.stop.ip6.as_u64[0] = p.laddr.stop.ip6.as_u64[1] = (u64) ~ 0;
268   p.raddr.stop.ip6.as_u64[0] = p.raddr.stop.ip6.as_u64[1] = (u64) ~ 0;
269
270   if (!unformat_user (input, unformat_line_input, line_input))
271     return 0;
272
273   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
274     {
275       if (unformat (line_input, "add"))
276         is_add = 1;
277       else if (unformat (line_input, "del"))
278         is_add = 0;
279       else if (unformat (line_input, "spd %u", &p.id))
280         ;
281       else if (unformat (line_input, "inbound"))
282         p.is_outbound = 0;
283       else if (unformat (line_input, "outbound"))
284         p.is_outbound = 1;
285       else if (unformat (line_input, "priority %d", &p.priority))
286         ;
287       else if (unformat (line_input, "protocol %u", &tmp))
288         p.protocol = (u8) tmp;
289       else
290         if (unformat
291             (line_input, "action %U", unformat_ipsec_policy_action,
292              &p.policy))
293         {
294           if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
295             {
296               error = clib_error_return (0, "unsupported action: 'resolve'");
297               goto done;
298             }
299         }
300       else if (unformat (line_input, "sa %u", &p.sa_id))
301         ;
302       else if (unformat (line_input, "local-ip-range %U - %U",
303                          unformat_ip4_address, &p.laddr.start.ip4,
304                          unformat_ip4_address, &p.laddr.stop.ip4))
305         is_ip_any = 0;
306       else if (unformat (line_input, "remote-ip-range %U - %U",
307                          unformat_ip4_address, &p.raddr.start.ip4,
308                          unformat_ip4_address, &p.raddr.stop.ip4))
309         is_ip_any = 0;
310       else if (unformat (line_input, "local-ip-range %U - %U",
311                          unformat_ip6_address, &p.laddr.start.ip6,
312                          unformat_ip6_address, &p.laddr.stop.ip6))
313         {
314           p.is_ipv6 = 1;
315           is_ip_any = 0;
316         }
317       else if (unformat (line_input, "remote-ip-range %U - %U",
318                          unformat_ip6_address, &p.raddr.start.ip6,
319                          unformat_ip6_address, &p.raddr.stop.ip6))
320         {
321           p.is_ipv6 = 1;
322           is_ip_any = 0;
323         }
324       else if (unformat (line_input, "local-port-range %u - %u", &tmp, &tmp2))
325         {
326           p.lport.start = tmp;
327           p.lport.stop = tmp2;
328         }
329       else
330         if (unformat (line_input, "remote-port-range %u - %u", &tmp, &tmp2))
331         {
332           p.rport.start = tmp;
333           p.rport.stop = tmp2;
334         }
335       else
336         {
337           error = clib_error_return (0, "parse error: '%U'",
338                                      format_unformat_error, line_input);
339           goto done;
340         }
341     }
342
343   /* Check if SA is for IPv6/AH which is not supported. Return error if TRUE. */
344   if (p.sa_id)
345     {
346       uword *p1;
347       ipsec_main_t *im = &ipsec_main;
348       ipsec_sa_t *sa = 0;
349       p1 = hash_get (im->sa_index_by_sa_id, p.sa_id);
350       if (!p1)
351         {
352           error =
353             clib_error_return (0, "SA with index %u not found", p.sa_id);
354           goto done;
355         }
356       sa = pool_elt_at_index (im->sad, p1[0]);
357       if (sa && sa->protocol == IPSEC_PROTOCOL_AH && is_add && p.is_ipv6)
358         {
359           error = clib_error_return (0, "AH not supported for IPV6: '%U'",
360                                      format_unformat_error, line_input);
361           goto done;
362         }
363     }
364   ipsec_add_del_policy (vm, &p, is_add);
365   if (is_ip_any)
366     {
367       p.is_ipv6 = 1;
368       ipsec_add_del_policy (vm, &p, is_add);
369     }
370
371 done:
372   unformat_free (line_input);
373
374   return error;
375 }
376
377 /* *INDENT-OFF* */
378 VLIB_CLI_COMMAND (ipsec_policy_add_del_command, static) = {
379     .path = "ipsec policy",
380     .short_help =
381     "ipsec policy [add|del] spd <id> priority <n> ",
382     .function = ipsec_policy_add_del_command_fn,
383 };
384 /* *INDENT-ON* */
385
386 static clib_error_t *
387 set_ipsec_sa_key_command_fn (vlib_main_t * vm,
388                              unformat_input_t * input,
389                              vlib_cli_command_t * cmd)
390 {
391   unformat_input_t _line_input, *line_input = &_line_input;
392   ipsec_sa_t sa;
393   u8 *ck = 0, *ik = 0;
394   clib_error_t *error = NULL;
395
396   clib_memset (&sa, 0, sizeof (sa));
397
398   if (!unformat_user (input, unformat_line_input, line_input))
399     return 0;
400
401   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
402     {
403       if (unformat (line_input, "%u", &sa.id))
404         ;
405       else
406         if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck))
407         sa.crypto_key_len = vec_len (ck);
408       else
409         if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik))
410         sa.integ_key_len = vec_len (ik);
411       else
412         {
413           error = clib_error_return (0, "parse error: '%U'",
414                                      format_unformat_error, line_input);
415           goto done;
416         }
417     }
418
419   if (sa.crypto_key_len > sizeof (sa.crypto_key))
420     sa.crypto_key_len = sizeof (sa.crypto_key);
421
422   if (sa.integ_key_len > sizeof (sa.integ_key))
423     sa.integ_key_len = sizeof (sa.integ_key);
424
425   if (ck)
426     strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len);
427
428   if (ik)
429     strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len);
430
431   ipsec_set_sa_key (vm, &sa);
432
433 done:
434   unformat_free (line_input);
435
436   return error;
437 }
438
439 /* *INDENT-OFF* */
440 VLIB_CLI_COMMAND (set_ipsec_sa_key_command, static) = {
441     .path = "set ipsec sa",
442     .short_help =
443     "set ipsec sa <id> crypto-key <key> integ-key <key>",
444     .function = set_ipsec_sa_key_command_fn,
445 };
446 /* *INDENT-ON* */
447
448 static clib_error_t *
449 show_ipsec_command_fn (vlib_main_t * vm,
450                        unformat_input_t * input, vlib_cli_command_t * cmd)
451 {
452   ipsec_spd_t *spd;
453   ipsec_sa_t *sa;
454   ipsec_policy_t *p;
455   ipsec_main_t *im = &ipsec_main;
456   u32 *i;
457   ipsec_tunnel_if_t *t;
458   vnet_hw_interface_t *hi;
459   u8 *protocol = NULL;
460   u8 *policy = NULL;
461
462   /* *INDENT-OFF* */
463   pool_foreach (sa, im->sad, ({
464     if (sa->id) {
465       vlib_cli_output(vm, "sa %u spi %u mode %s protocol %s%s", sa->id, sa->spi,
466                       sa->is_tunnel ? "tunnel" : "transport",
467                       sa->protocol ? "esp" : "ah",
468                       sa->udp_encap ? " udp-encap-enabled" : "");
469       if (sa->protocol == IPSEC_PROTOCOL_ESP) {
470         vlib_cli_output(vm, "  crypto alg %U%s%U integrity alg %U%s%U",
471                         format_ipsec_crypto_alg, sa->crypto_alg,
472                         sa->crypto_alg ? " key " : "",
473                         format_hex_bytes, sa->crypto_key, sa->crypto_key_len,
474                         format_ipsec_integ_alg, sa->integ_alg,
475                         sa->integ_alg ? " key " : "",
476                         format_hex_bytes, sa->integ_key, sa->integ_key_len);
477       }
478       if (sa->is_tunnel && sa->is_tunnel_ip6) {
479         vlib_cli_output(vm, "  tunnel src %U dst %U",
480                         format_ip6_address, &sa->tunnel_src_addr.ip6,
481                         format_ip6_address, &sa->tunnel_dst_addr.ip6);
482       } else if (sa->is_tunnel) {
483         vlib_cli_output(vm, "  tunnel src %U dst %U",
484                         format_ip4_address, &sa->tunnel_src_addr.ip4,
485                         format_ip4_address, &sa->tunnel_dst_addr.ip4);
486       }
487     }
488   }));
489   /* *INDENT-ON* */
490
491   /* *INDENT-OFF* */
492   pool_foreach (spd, im->spds, ({
493     vlib_cli_output(vm, "spd %u", spd->id);
494
495     vlib_cli_output(vm, " outbound policies");
496     vec_foreach(i, spd->ipv4_outbound_policies)
497       {
498         p = pool_elt_at_index(spd->policies, *i);
499         vec_reset_length(protocol);
500         vec_reset_length(policy);
501         if (p->protocol) {
502           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
503         } else {
504           protocol = format(protocol, "any");
505         }
506         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
507           policy = format(policy, " sa %u", p->sa_id);
508         }
509
510         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
511                         p->priority, format_ipsec_policy_action, p->policy,
512                         protocol, policy);
513         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
514                         format_ip4_address, &p->laddr.start.ip4,
515                         format_ip4_address, &p->laddr.stop.ip4,
516                         p->lport.start, p->lport.stop);
517         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
518                         format_ip4_address, &p->raddr.start.ip4,
519                         format_ip4_address, &p->raddr.stop.ip4,
520                         p->rport.start, p->rport.stop);
521         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
522                         p->counter.bytes);
523       };
524     vec_foreach(i, spd->ipv6_outbound_policies)
525       {
526         p = pool_elt_at_index(spd->policies, *i);
527         vec_reset_length(protocol);
528         vec_reset_length(policy);
529         if (p->protocol) {
530           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
531         } else {
532           protocol = format(protocol, "any");
533         }
534         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
535           policy = format(policy, " sa %u", p->sa_id);
536         }
537         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
538                         p->priority, format_ipsec_policy_action, p->policy,
539                         protocol, policy);
540         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
541                         format_ip6_address, &p->laddr.start.ip6,
542                         format_ip6_address, &p->laddr.stop.ip6,
543                         p->lport.start, p->lport.stop);
544         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
545                         format_ip6_address, &p->raddr.start.ip6,
546                         format_ip6_address, &p->raddr.stop.ip6,
547                         p->rport.start, p->rport.stop);
548         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
549                         p->counter.bytes);
550       };
551     vlib_cli_output(vm, " inbound policies");
552     vec_foreach(i, spd->ipv4_inbound_protect_policy_indices)
553       {
554         p = pool_elt_at_index(spd->policies, *i);
555         vec_reset_length(protocol);
556         vec_reset_length(policy);
557         if (p->protocol) {
558           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
559         } else {
560           protocol = format(protocol, "any");
561         }
562         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
563           policy = format(policy, " sa %u", p->sa_id);
564         }
565         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
566                         p->priority, format_ipsec_policy_action, p->policy,
567                         protocol, policy);
568         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
569                         format_ip4_address, &p->laddr.start.ip4,
570                         format_ip4_address, &p->laddr.stop.ip4,
571                         p->lport.start, p->lport.stop);
572         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
573                         format_ip4_address, &p->raddr.start.ip4,
574                         format_ip4_address, &p->raddr.stop.ip4,
575                         p->rport.start, p->rport.stop);
576         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
577                         p->counter.bytes);
578       };
579     vec_foreach(i, spd->ipv4_inbound_policy_discard_and_bypass_indices)
580       {
581         p = pool_elt_at_index(spd->policies, *i);
582         vec_reset_length(protocol);
583         vec_reset_length(policy);
584         if (p->protocol) {
585           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
586         } else {
587           protocol = format(protocol, "any");
588         }
589         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
590           policy = format(policy, " sa %u", p->sa_id);
591         }
592         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
593                         p->priority, format_ipsec_policy_action, p->policy,
594                         protocol, policy);
595         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
596                         format_ip4_address, &p->laddr.start.ip4,
597                         format_ip4_address, &p->laddr.stop.ip4,
598                         p->lport.start, p->lport.stop);
599         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
600                         format_ip4_address, &p->raddr.start.ip4,
601                         format_ip4_address, &p->raddr.stop.ip4,
602                         p->rport.start, p->rport.stop);
603         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
604                         p->counter.bytes);
605       };
606     vec_foreach(i, spd->ipv6_inbound_protect_policy_indices)
607       {
608         p = pool_elt_at_index(spd->policies, *i);
609         vec_reset_length(protocol);
610         vec_reset_length(policy);
611         if (p->protocol) {
612           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
613         } else {
614           protocol = format(protocol, "any");
615         }
616         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
617           policy = format(policy, " sa %u", p->sa_id);
618         }
619         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
620                         p->priority, format_ipsec_policy_action, p->policy,
621                         protocol, policy);
622         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
623                         format_ip6_address, &p->laddr.start.ip6,
624                         format_ip6_address, &p->laddr.stop.ip6,
625                         p->lport.start, p->lport.stop);
626         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
627                         format_ip6_address, &p->raddr.start.ip6,
628                         format_ip6_address, &p->raddr.stop.ip6,
629                         p->rport.start, p->rport.stop);
630         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
631                         p->counter.bytes);
632       };
633     vec_foreach(i, spd->ipv6_inbound_policy_discard_and_bypass_indices)
634       {
635         p = pool_elt_at_index(spd->policies, *i);
636         vec_reset_length(protocol);
637         vec_reset_length(policy);
638         if (p->protocol) {
639           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
640         } else {
641           protocol = format(protocol, "any");
642         }
643         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
644           policy = format(policy, " sa %u", p->sa_id);
645         }
646         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
647                         p->priority, format_ipsec_policy_action, p->policy,
648                         protocol, policy);
649         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
650                         format_ip6_address, &p->laddr.start.ip6,
651                         format_ip6_address, &p->laddr.stop.ip6,
652                         p->lport.start, p->lport.stop);
653         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
654                         format_ip6_address, &p->raddr.start.ip6,
655                         format_ip6_address, &p->raddr.stop.ip6,
656                         p->rport.start, p->rport.stop);
657         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
658                         p->counter.bytes);
659       };
660   }));
661   /* *INDENT-ON* */
662
663   vlib_cli_output (vm, "tunnel interfaces");
664   /* *INDENT-OFF* */
665   pool_foreach (t, im->tunnel_interfaces, ({
666     if (t->hw_if_index == ~0)
667       continue;
668     hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index);
669     vlib_cli_output(vm, "  %s seq", hi->name);
670     sa = pool_elt_at_index(im->sad, t->output_sa_index);
671     vlib_cli_output(vm, "   seq %u seq-hi %u esn %u anti-replay %u udp-encap %u",
672                     sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay, sa->udp_encap);
673     vlib_cli_output(vm, "   local-spi %u local-ip %U", sa->spi,
674                     format_ip4_address, &sa->tunnel_src_addr.ip4);
675     vlib_cli_output(vm, "   local-crypto %U %U",
676                     format_ipsec_crypto_alg, sa->crypto_alg,
677                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
678     vlib_cli_output(vm, "   local-integrity %U %U",
679                     format_ipsec_integ_alg, sa->integ_alg,
680                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
681     sa = pool_elt_at_index(im->sad, t->input_sa_index);
682     vlib_cli_output(vm, "   last-seq %u last-seq-hi %u esn %u anti-replay %u window %U",
683                     sa->last_seq, sa->last_seq_hi, sa->use_esn,
684                     sa->use_anti_replay,
685                     format_ipsec_replay_window, sa->replay_window);
686     vlib_cli_output(vm, "   remote-spi %u remote-ip %U", sa->spi,
687                     format_ip4_address, &sa->tunnel_src_addr.ip4);
688     vlib_cli_output(vm, "   remote-crypto %U %U",
689                     format_ipsec_crypto_alg, sa->crypto_alg,
690                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
691     vlib_cli_output(vm, "   remote-integrity %U %U",
692                     format_ipsec_integ_alg, sa->integ_alg,
693                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
694   }));
695   vec_free(policy);
696   vec_free(protocol);
697   /* *INDENT-ON* */
698   return 0;
699 }
700
701 /* *INDENT-OFF* */
702 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
703     .path = "show ipsec",
704     .short_help = "show ipsec [backends]",
705     .function = show_ipsec_command_fn,
706 };
707 /* *INDENT-ON* */
708
709 static clib_error_t *
710 ipsec_show_backends_command_fn (vlib_main_t * vm,
711                                 unformat_input_t * input,
712                                 vlib_cli_command_t * cmd)
713 {
714   ipsec_main_t *im = &ipsec_main;
715   u32 verbose = 0;
716
717   (void) unformat (input, "verbose %u", &verbose);
718
719   vlib_cli_output (vm, "IPsec AH backends available:");
720   u8 *s = format (NULL, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
721   ipsec_ah_backend_t *ab;
722   /* *INDENT-OFF* */
723   pool_foreach (ab, im->ah_backends, {
724     s = format (s, "%=25s %=25u %=10s\n", ab->name, ab - im->ah_backends,
725                 ab - im->ah_backends == im->ah_current_backend ? "yes" : "no");
726     if (verbose) {
727         vlib_node_t *n;
728         n = vlib_get_node (vm, ab->ah4_encrypt_node_index);
729         s = format (s, "     enc4 %s (next %d)\n", n->name, ab->ah4_encrypt_next_index);
730         n = vlib_get_node (vm, ab->ah4_decrypt_node_index);
731         s = format (s, "     dec4 %s (next %d)\n", n->name, ab->ah4_decrypt_next_index);
732         n = vlib_get_node (vm, ab->ah6_encrypt_node_index);
733         s = format (s, "     enc6 %s (next %d)\n", n->name, ab->ah6_encrypt_next_index);
734         n = vlib_get_node (vm, ab->ah6_decrypt_node_index);
735         s = format (s, "     dec6 %s (next %d)\n", n->name, ab->ah6_decrypt_next_index);
736     }
737   });
738   /* *INDENT-ON* */
739   vlib_cli_output (vm, "%v", s);
740   _vec_len (s) = 0;
741   vlib_cli_output (vm, "IPsec ESP backends available:");
742   s = format (s, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
743   ipsec_esp_backend_t *eb;
744   /* *INDENT-OFF* */
745   pool_foreach (eb, im->esp_backends, {
746     s = format (s, "%=25s %=25u %=10s\n", eb->name, eb - im->esp_backends,
747                 eb - im->esp_backends == im->esp_current_backend ? "yes"
748                                                                  : "no");
749     if (verbose) {
750         vlib_node_t *n;
751         n = vlib_get_node (vm, eb->esp4_encrypt_node_index);
752         s = format (s, "     enc4 %s (next %d)\n", n->name, eb->esp4_encrypt_next_index);
753         n = vlib_get_node (vm, eb->esp4_decrypt_node_index);
754         s = format (s, "     dec4 %s (next %d)\n", n->name, eb->esp4_decrypt_next_index);
755         n = vlib_get_node (vm, eb->esp6_encrypt_node_index);
756         s = format (s, "     enc6 %s (next %d)\n", n->name, eb->esp6_encrypt_next_index);
757         n = vlib_get_node (vm, eb->esp6_decrypt_node_index);
758         s = format (s, "     dec6 %s (next %d)\n", n->name, eb->esp6_decrypt_next_index);
759     }
760   });
761   /* *INDENT-ON* */
762   vlib_cli_output (vm, "%v", s);
763
764   vec_free (s);
765   return 0;
766 }
767
768 /* *INDENT-OFF* */
769 VLIB_CLI_COMMAND (ipsec_show_backends_command, static) = {
770     .path = "show ipsec backends",
771     .short_help = "show ipsec backends",
772     .function = ipsec_show_backends_command_fn,
773 };
774 /* *INDENT-ON* */
775
776 static clib_error_t *
777 ipsec_select_backend_command_fn (vlib_main_t * vm,
778                                  unformat_input_t * input,
779                                  vlib_cli_command_t * cmd)
780 {
781   u32 backend_index;
782   ipsec_main_t *im = &ipsec_main;
783
784   if (pool_elts (im->sad) > 0)
785     {
786       return clib_error_return (0,
787                                 "Cannot change IPsec backend, while %u SA entries are configured",
788                                 pool_elts (im->sad));
789     }
790
791   unformat_input_t _line_input, *line_input = &_line_input;
792   /* Get a line of input. */
793   if (!unformat_user (input, unformat_line_input, line_input))
794     return 0;
795
796   if (unformat (line_input, "ah"))
797     {
798       if (unformat (line_input, "%u", &backend_index))
799         {
800           if (ipsec_select_ah_backend (im, backend_index) < 0)
801             {
802               return clib_error_return (0, "Invalid AH backend index `%u'",
803                                         backend_index);
804             }
805         }
806       else
807         {
808           return clib_error_return (0, "Invalid backend index `%U'",
809                                     format_unformat_error, line_input);
810         }
811     }
812   else if (unformat (line_input, "esp"))
813     {
814       if (unformat (line_input, "%u", &backend_index))
815         {
816           if (ipsec_select_esp_backend (im, backend_index) < 0)
817             {
818               return clib_error_return (0, "Invalid ESP backend index `%u'",
819                                         backend_index);
820             }
821         }
822       else
823         {
824           return clib_error_return (0, "Invalid backend index `%U'",
825                                     format_unformat_error, line_input);
826         }
827     }
828   else
829     {
830       return clib_error_return (0, "Unknown input `%U'",
831                                 format_unformat_error, line_input);
832     }
833
834   return 0;
835 }
836
837 /* *INDENT-OFF* */
838 VLIB_CLI_COMMAND (ipsec_select_backend_command, static) = {
839     .path = "ipsec select backend",
840     .short_help = "ipsec select backend <ah|esp> <backend index>",
841     .function = ipsec_select_backend_command_fn,
842 };
843
844 /* *INDENT-ON* */
845
846 static clib_error_t *
847 clear_ipsec_counters_command_fn (vlib_main_t * vm,
848                                  unformat_input_t * input,
849                                  vlib_cli_command_t * cmd)
850 {
851   ipsec_main_t *im = &ipsec_main;
852   ipsec_spd_t *spd;
853   ipsec_policy_t *p;
854
855   /* *INDENT-OFF* */
856   pool_foreach (spd, im->spds, ({
857     pool_foreach(p, spd->policies, ({
858       p->counter.packets = p->counter.bytes = 0;
859     }));
860   }));
861   /* *INDENT-ON* */
862
863   return 0;
864 }
865
866 /* *INDENT-OFF* */
867 VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = {
868     .path = "clear ipsec counters",
869     .short_help = "clear ipsec counters",
870     .function = clear_ipsec_counters_command_fn,
871 };
872 /* *INDENT-ON* */
873
874 static clib_error_t *
875 create_ipsec_tunnel_command_fn (vlib_main_t * vm,
876                                 unformat_input_t * input,
877                                 vlib_cli_command_t * cmd)
878 {
879   unformat_input_t _line_input, *line_input = &_line_input;
880   ipsec_add_del_tunnel_args_t a;
881   int rv;
882   u32 num_m_args = 0;
883   clib_error_t *error = NULL;
884
885   clib_memset (&a, 0, sizeof (a));
886   a.is_add = 1;
887
888   /* Get a line of input. */
889   if (!unformat_user (input, unformat_line_input, line_input))
890     return 0;
891
892   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
893     {
894       if (unformat
895           (line_input, "local-ip %U", unformat_ip4_address, &a.local_ip))
896         num_m_args++;
897       else
898         if (unformat
899             (line_input, "remote-ip %U", unformat_ip4_address, &a.remote_ip))
900         num_m_args++;
901       else if (unformat (line_input, "local-spi %u", &a.local_spi))
902         num_m_args++;
903       else if (unformat (line_input, "remote-spi %u", &a.remote_spi))
904         num_m_args++;
905       else if (unformat (line_input, "instance %u", &a.show_instance))
906         a.renumber = 1;
907       else if (unformat (line_input, "del"))
908         a.is_add = 0;
909       else if (unformat (line_input, "udp-encap"))
910         a.udp_encap = 1;
911       else
912         {
913           error = clib_error_return (0, "unknown input `%U'",
914                                      format_unformat_error, line_input);
915           goto done;
916         }
917     }
918
919   if (num_m_args < 4)
920     {
921       error = clib_error_return (0, "mandatory argument(s) missing");
922       goto done;
923     }
924
925   rv = ipsec_add_del_tunnel_if (&a);
926
927   switch (rv)
928     {
929     case 0:
930       break;
931     case VNET_API_ERROR_INVALID_VALUE:
932       if (a.is_add)
933         error = clib_error_return (0,
934                                    "IPSec tunnel interface already exists...");
935       else
936         error = clib_error_return (0, "IPSec tunnel interface not exists...");
937       goto done;
938     default:
939       error = clib_error_return (0, "ipsec_register_interface returned %d",
940                                  rv);
941       goto done;
942     }
943
944 done:
945   unformat_free (line_input);
946
947   return error;
948 }
949
950 /* *INDENT-OFF* */
951 VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
952   .path = "create ipsec tunnel",
953   .short_help = "create ipsec tunnel local-ip <addr> local-spi <spi> remote-ip <addr> remote-spi <spi> [instance <inst_num>] [udp-encap]",
954   .function = create_ipsec_tunnel_command_fn,
955 };
956 /* *INDENT-ON* */
957
958 static clib_error_t *
959 set_interface_key_command_fn (vlib_main_t * vm,
960                               unformat_input_t * input,
961                               vlib_cli_command_t * cmd)
962 {
963   unformat_input_t _line_input, *line_input = &_line_input;
964   ipsec_main_t *im = &ipsec_main;
965   ipsec_if_set_key_type_t type = IPSEC_IF_SET_KEY_TYPE_NONE;
966   u32 hw_if_index = (u32) ~ 0;
967   u32 alg;
968   u8 *key = 0;
969   clib_error_t *error = NULL;
970
971   if (!unformat_user (input, unformat_line_input, line_input))
972     return 0;
973
974   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
975     {
976       if (unformat (line_input, "%U",
977                     unformat_vnet_hw_interface, im->vnet_main, &hw_if_index))
978         ;
979       else
980         if (unformat
981             (line_input, "local crypto %U", unformat_ipsec_crypto_alg, &alg))
982         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO;
983       else
984         if (unformat
985             (line_input, "remote crypto %U", unformat_ipsec_crypto_alg, &alg))
986         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO;
987       else
988         if (unformat
989             (line_input, "local integ %U", unformat_ipsec_integ_alg, &alg))
990         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG;
991       else
992         if (unformat
993             (line_input, "remote integ %U", unformat_ipsec_integ_alg, &alg))
994         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG;
995       else if (unformat (line_input, "%U", unformat_hex_string, &key))
996         ;
997       else
998         {
999           error = clib_error_return (0, "parse error: '%U'",
1000                                      format_unformat_error, line_input);
1001           goto done;
1002         }
1003     }
1004
1005   if (type == IPSEC_IF_SET_KEY_TYPE_NONE)
1006     {
1007       error = clib_error_return (0, "unknown key type");
1008       goto done;
1009     }
1010
1011   if (alg > 0 && vec_len (key) == 0)
1012     {
1013       error = clib_error_return (0, "key is not specified");
1014       goto done;
1015     }
1016
1017   if (hw_if_index == (u32) ~ 0)
1018     {
1019       error = clib_error_return (0, "interface not specified");
1020       goto done;
1021     }
1022
1023   ipsec_set_interface_key (im->vnet_main, hw_if_index, type, alg, key);
1024
1025 done:
1026   vec_free (key);
1027   unformat_free (line_input);
1028
1029   return error;
1030 }
1031
1032 /* *INDENT-OFF* */
1033 VLIB_CLI_COMMAND (set_interface_key_command, static) = {
1034     .path = "set interface ipsec key",
1035     .short_help =
1036     "set interface ipsec key <int> <local|remote> <crypto|integ> <key type> <key>",
1037     .function = set_interface_key_command_fn,
1038 };
1039 /* *INDENT-ON* */
1040
1041 clib_error_t *
1042 ipsec_cli_init (vlib_main_t * vm)
1043 {
1044   return 0;
1045 }
1046
1047 VLIB_INIT_FUNCTION (ipsec_cli_init);
1048
1049
1050 /*
1051  * fd.io coding-style-patch-verification: ON
1052  *
1053  * Local Variables:
1054  * eval: (c-set-style "gnu")
1055  * End:
1056  */