IPSEC-AH: anti-replay testing
[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     memcpy (sa.crypto_key, ck, sa.crypto_key_len);
171
172   if (ik)
173     memcpy (sa.integ_key, 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%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                       sa->use_anti_replay ? " anti-replay" : "",
470                       sa->use_esn ? " extended-sequence-number" : "");
471       if (sa->protocol == IPSEC_PROTOCOL_ESP) {
472         vlib_cli_output(vm, "  crypto alg %U%s%U integrity alg %U%s%U",
473                         format_ipsec_crypto_alg, sa->crypto_alg,
474                         sa->crypto_alg ? " key " : "",
475                         format_hex_bytes, sa->crypto_key, sa->crypto_key_len,
476                         format_ipsec_integ_alg, sa->integ_alg,
477                         sa->integ_alg ? " key " : "",
478                         format_hex_bytes, sa->integ_key, sa->integ_key_len);
479       }
480       if (sa->is_tunnel && sa->is_tunnel_ip6) {
481         vlib_cli_output(vm, "  tunnel src %U dst %U",
482                         format_ip6_address, &sa->tunnel_src_addr.ip6,
483                         format_ip6_address, &sa->tunnel_dst_addr.ip6);
484       } else if (sa->is_tunnel) {
485         vlib_cli_output(vm, "  tunnel src %U dst %U",
486                         format_ip4_address, &sa->tunnel_src_addr.ip4,
487                         format_ip4_address, &sa->tunnel_dst_addr.ip4);
488       }
489     }
490   }));
491   /* *INDENT-ON* */
492
493   /* *INDENT-OFF* */
494   pool_foreach (spd, im->spds, ({
495     vlib_cli_output(vm, "spd %u", spd->id);
496
497     vlib_cli_output(vm, " outbound policies");
498     vec_foreach(i, spd->ipv4_outbound_policies)
499       {
500         p = pool_elt_at_index(spd->policies, *i);
501         vec_reset_length(protocol);
502         vec_reset_length(policy);
503         if (p->protocol) {
504           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
505         } else {
506           protocol = format(protocol, "any");
507         }
508         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
509           policy = format(policy, " sa %u", p->sa_id);
510         }
511
512         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
513                         p->priority, format_ipsec_policy_action, p->policy,
514                         protocol, policy);
515         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
516                         format_ip4_address, &p->laddr.start.ip4,
517                         format_ip4_address, &p->laddr.stop.ip4,
518                         p->lport.start, p->lport.stop);
519         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
520                         format_ip4_address, &p->raddr.start.ip4,
521                         format_ip4_address, &p->raddr.stop.ip4,
522                         p->rport.start, p->rport.stop);
523         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
524                         p->counter.bytes);
525       };
526     vec_foreach(i, spd->ipv6_outbound_policies)
527       {
528         p = pool_elt_at_index(spd->policies, *i);
529         vec_reset_length(protocol);
530         vec_reset_length(policy);
531         if (p->protocol) {
532           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
533         } else {
534           protocol = format(protocol, "any");
535         }
536         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
537           policy = format(policy, " sa %u", p->sa_id);
538         }
539         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
540                         p->priority, format_ipsec_policy_action, p->policy,
541                         protocol, policy);
542         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
543                         format_ip6_address, &p->laddr.start.ip6,
544                         format_ip6_address, &p->laddr.stop.ip6,
545                         p->lport.start, p->lport.stop);
546         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
547                         format_ip6_address, &p->raddr.start.ip6,
548                         format_ip6_address, &p->raddr.stop.ip6,
549                         p->rport.start, p->rport.stop);
550         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
551                         p->counter.bytes);
552       };
553     vlib_cli_output(vm, " inbound policies");
554     vec_foreach(i, spd->ipv4_inbound_protect_policy_indices)
555       {
556         p = pool_elt_at_index(spd->policies, *i);
557         vec_reset_length(protocol);
558         vec_reset_length(policy);
559         if (p->protocol) {
560           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
561         } else {
562           protocol = format(protocol, "any");
563         }
564         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
565           policy = format(policy, " sa %u", p->sa_id);
566         }
567         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
568                         p->priority, format_ipsec_policy_action, p->policy,
569                         protocol, policy);
570         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
571                         format_ip4_address, &p->laddr.start.ip4,
572                         format_ip4_address, &p->laddr.stop.ip4,
573                         p->lport.start, p->lport.stop);
574         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
575                         format_ip4_address, &p->raddr.start.ip4,
576                         format_ip4_address, &p->raddr.stop.ip4,
577                         p->rport.start, p->rport.stop);
578         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
579                         p->counter.bytes);
580       };
581     vec_foreach(i, spd->ipv4_inbound_policy_discard_and_bypass_indices)
582       {
583         p = pool_elt_at_index(spd->policies, *i);
584         vec_reset_length(protocol);
585         vec_reset_length(policy);
586         if (p->protocol) {
587           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
588         } else {
589           protocol = format(protocol, "any");
590         }
591         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
592           policy = format(policy, " sa %u", p->sa_id);
593         }
594         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
595                         p->priority, format_ipsec_policy_action, p->policy,
596                         protocol, policy);
597         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
598                         format_ip4_address, &p->laddr.start.ip4,
599                         format_ip4_address, &p->laddr.stop.ip4,
600                         p->lport.start, p->lport.stop);
601         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
602                         format_ip4_address, &p->raddr.start.ip4,
603                         format_ip4_address, &p->raddr.stop.ip4,
604                         p->rport.start, p->rport.stop);
605         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
606                         p->counter.bytes);
607       };
608     vec_foreach(i, spd->ipv6_inbound_protect_policy_indices)
609       {
610         p = pool_elt_at_index(spd->policies, *i);
611         vec_reset_length(protocol);
612         vec_reset_length(policy);
613         if (p->protocol) {
614           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
615         } else {
616           protocol = format(protocol, "any");
617         }
618         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
619           policy = format(policy, " sa %u", p->sa_id);
620         }
621         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
622                         p->priority, format_ipsec_policy_action, p->policy,
623                         protocol, policy);
624         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
625                         format_ip6_address, &p->laddr.start.ip6,
626                         format_ip6_address, &p->laddr.stop.ip6,
627                         p->lport.start, p->lport.stop);
628         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
629                         format_ip6_address, &p->raddr.start.ip6,
630                         format_ip6_address, &p->raddr.stop.ip6,
631                         p->rport.start, p->rport.stop);
632         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
633                         p->counter.bytes);
634       };
635     vec_foreach(i, spd->ipv6_inbound_policy_discard_and_bypass_indices)
636       {
637         p = pool_elt_at_index(spd->policies, *i);
638         vec_reset_length(protocol);
639         vec_reset_length(policy);
640         if (p->protocol) {
641           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
642         } else {
643           protocol = format(protocol, "any");
644         }
645         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
646           policy = format(policy, " sa %u", p->sa_id);
647         }
648         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
649                         p->priority, format_ipsec_policy_action, p->policy,
650                         protocol, policy);
651         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
652                         format_ip6_address, &p->laddr.start.ip6,
653                         format_ip6_address, &p->laddr.stop.ip6,
654                         p->lport.start, p->lport.stop);
655         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
656                         format_ip6_address, &p->raddr.start.ip6,
657                         format_ip6_address, &p->raddr.stop.ip6,
658                         p->rport.start, p->rport.stop);
659         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
660                         p->counter.bytes);
661       };
662   }));
663   /* *INDENT-ON* */
664
665   vlib_cli_output (vm, "tunnel interfaces");
666   /* *INDENT-OFF* */
667   pool_foreach (t, im->tunnel_interfaces, ({
668     if (t->hw_if_index == ~0)
669       continue;
670     hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index);
671     vlib_cli_output(vm, "  %s seq", hi->name);
672     sa = pool_elt_at_index(im->sad, t->output_sa_index);
673     vlib_cli_output(vm, "   seq %u seq-hi %u esn %u anti-replay %u udp-encap %u",
674                     sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay, sa->udp_encap);
675     vlib_cli_output(vm, "   local-spi %u local-ip %U", sa->spi,
676                     format_ip4_address, &sa->tunnel_src_addr.ip4);
677     vlib_cli_output(vm, "   local-crypto %U %U",
678                     format_ipsec_crypto_alg, sa->crypto_alg,
679                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
680     vlib_cli_output(vm, "   local-integrity %U %U",
681                     format_ipsec_integ_alg, sa->integ_alg,
682                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
683     sa = pool_elt_at_index(im->sad, t->input_sa_index);
684     vlib_cli_output(vm, "   last-seq %u last-seq-hi %u esn %u anti-replay %u window %U",
685                     sa->last_seq, sa->last_seq_hi, sa->use_esn,
686                     sa->use_anti_replay,
687                     format_ipsec_replay_window, sa->replay_window);
688     vlib_cli_output(vm, "   remote-spi %u remote-ip %U", sa->spi,
689                     format_ip4_address, &sa->tunnel_src_addr.ip4);
690     vlib_cli_output(vm, "   remote-crypto %U %U",
691                     format_ipsec_crypto_alg, sa->crypto_alg,
692                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
693     vlib_cli_output(vm, "   remote-integrity %U %U",
694                     format_ipsec_integ_alg, sa->integ_alg,
695                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
696   }));
697   vec_free(policy);
698   vec_free(protocol);
699   /* *INDENT-ON* */
700   return 0;
701 }
702
703 /* *INDENT-OFF* */
704 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
705     .path = "show ipsec",
706     .short_help = "show ipsec [backends]",
707     .function = show_ipsec_command_fn,
708 };
709 /* *INDENT-ON* */
710
711 static clib_error_t *
712 ipsec_show_backends_command_fn (vlib_main_t * vm,
713                                 unformat_input_t * input,
714                                 vlib_cli_command_t * cmd)
715 {
716   ipsec_main_t *im = &ipsec_main;
717   u32 verbose = 0;
718
719   (void) unformat (input, "verbose %u", &verbose);
720
721   vlib_cli_output (vm, "IPsec AH backends available:");
722   u8 *s = format (NULL, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
723   ipsec_ah_backend_t *ab;
724   /* *INDENT-OFF* */
725   pool_foreach (ab, im->ah_backends, {
726     s = format (s, "%=25s %=25u %=10s\n", ab->name, ab - im->ah_backends,
727                 ab - im->ah_backends == im->ah_current_backend ? "yes" : "no");
728     if (verbose) {
729         vlib_node_t *n;
730         n = vlib_get_node (vm, ab->ah4_encrypt_node_index);
731         s = format (s, "     enc4 %s (next %d)\n", n->name, ab->ah4_encrypt_next_index);
732         n = vlib_get_node (vm, ab->ah4_decrypt_node_index);
733         s = format (s, "     dec4 %s (next %d)\n", n->name, ab->ah4_decrypt_next_index);
734         n = vlib_get_node (vm, ab->ah6_encrypt_node_index);
735         s = format (s, "     enc6 %s (next %d)\n", n->name, ab->ah6_encrypt_next_index);
736         n = vlib_get_node (vm, ab->ah6_decrypt_node_index);
737         s = format (s, "     dec6 %s (next %d)\n", n->name, ab->ah6_decrypt_next_index);
738     }
739   });
740   /* *INDENT-ON* */
741   vlib_cli_output (vm, "%v", s);
742   _vec_len (s) = 0;
743   vlib_cli_output (vm, "IPsec ESP backends available:");
744   s = format (s, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
745   ipsec_esp_backend_t *eb;
746   /* *INDENT-OFF* */
747   pool_foreach (eb, im->esp_backends, {
748     s = format (s, "%=25s %=25u %=10s\n", eb->name, eb - im->esp_backends,
749                 eb - im->esp_backends == im->esp_current_backend ? "yes"
750                                                                  : "no");
751     if (verbose) {
752         vlib_node_t *n;
753         n = vlib_get_node (vm, eb->esp4_encrypt_node_index);
754         s = format (s, "     enc4 %s (next %d)\n", n->name, eb->esp4_encrypt_next_index);
755         n = vlib_get_node (vm, eb->esp4_decrypt_node_index);
756         s = format (s, "     dec4 %s (next %d)\n", n->name, eb->esp4_decrypt_next_index);
757         n = vlib_get_node (vm, eb->esp6_encrypt_node_index);
758         s = format (s, "     enc6 %s (next %d)\n", n->name, eb->esp6_encrypt_next_index);
759         n = vlib_get_node (vm, eb->esp6_decrypt_node_index);
760         s = format (s, "     dec6 %s (next %d)\n", n->name, eb->esp6_decrypt_next_index);
761     }
762   });
763   /* *INDENT-ON* */
764   vlib_cli_output (vm, "%v", s);
765
766   vec_free (s);
767   return 0;
768 }
769
770 /* *INDENT-OFF* */
771 VLIB_CLI_COMMAND (ipsec_show_backends_command, static) = {
772     .path = "show ipsec backends",
773     .short_help = "show ipsec backends",
774     .function = ipsec_show_backends_command_fn,
775 };
776 /* *INDENT-ON* */
777
778 static clib_error_t *
779 ipsec_select_backend_command_fn (vlib_main_t * vm,
780                                  unformat_input_t * input,
781                                  vlib_cli_command_t * cmd)
782 {
783   u32 backend_index;
784   ipsec_main_t *im = &ipsec_main;
785
786   if (pool_elts (im->sad) > 0)
787     {
788       return clib_error_return (0,
789                                 "Cannot change IPsec backend, while %u SA entries are configured",
790                                 pool_elts (im->sad));
791     }
792
793   unformat_input_t _line_input, *line_input = &_line_input;
794   /* Get a line of input. */
795   if (!unformat_user (input, unformat_line_input, line_input))
796     return 0;
797
798   if (unformat (line_input, "ah"))
799     {
800       if (unformat (line_input, "%u", &backend_index))
801         {
802           if (ipsec_select_ah_backend (im, backend_index) < 0)
803             {
804               return clib_error_return (0, "Invalid AH backend index `%u'",
805                                         backend_index);
806             }
807         }
808       else
809         {
810           return clib_error_return (0, "Invalid backend index `%U'",
811                                     format_unformat_error, line_input);
812         }
813     }
814   else if (unformat (line_input, "esp"))
815     {
816       if (unformat (line_input, "%u", &backend_index))
817         {
818           if (ipsec_select_esp_backend (im, backend_index) < 0)
819             {
820               return clib_error_return (0, "Invalid ESP backend index `%u'",
821                                         backend_index);
822             }
823         }
824       else
825         {
826           return clib_error_return (0, "Invalid backend index `%U'",
827                                     format_unformat_error, line_input);
828         }
829     }
830   else
831     {
832       return clib_error_return (0, "Unknown input `%U'",
833                                 format_unformat_error, line_input);
834     }
835
836   return 0;
837 }
838
839 /* *INDENT-OFF* */
840 VLIB_CLI_COMMAND (ipsec_select_backend_command, static) = {
841     .path = "ipsec select backend",
842     .short_help = "ipsec select backend <ah|esp> <backend index>",
843     .function = ipsec_select_backend_command_fn,
844 };
845
846 /* *INDENT-ON* */
847
848 static clib_error_t *
849 clear_ipsec_counters_command_fn (vlib_main_t * vm,
850                                  unformat_input_t * input,
851                                  vlib_cli_command_t * cmd)
852 {
853   ipsec_main_t *im = &ipsec_main;
854   ipsec_spd_t *spd;
855   ipsec_policy_t *p;
856
857   /* *INDENT-OFF* */
858   pool_foreach (spd, im->spds, ({
859     pool_foreach(p, spd->policies, ({
860       p->counter.packets = p->counter.bytes = 0;
861     }));
862   }));
863   /* *INDENT-ON* */
864
865   return 0;
866 }
867
868 /* *INDENT-OFF* */
869 VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = {
870     .path = "clear ipsec counters",
871     .short_help = "clear ipsec counters",
872     .function = clear_ipsec_counters_command_fn,
873 };
874 /* *INDENT-ON* */
875
876 static clib_error_t *
877 create_ipsec_tunnel_command_fn (vlib_main_t * vm,
878                                 unformat_input_t * input,
879                                 vlib_cli_command_t * cmd)
880 {
881   unformat_input_t _line_input, *line_input = &_line_input;
882   ipsec_add_del_tunnel_args_t a;
883   int rv;
884   u32 num_m_args = 0;
885   clib_error_t *error = NULL;
886
887   clib_memset (&a, 0, sizeof (a));
888   a.is_add = 1;
889
890   /* Get a line of input. */
891   if (!unformat_user (input, unformat_line_input, line_input))
892     return 0;
893
894   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
895     {
896       if (unformat
897           (line_input, "local-ip %U", unformat_ip4_address, &a.local_ip))
898         num_m_args++;
899       else
900         if (unformat
901             (line_input, "remote-ip %U", unformat_ip4_address, &a.remote_ip))
902         num_m_args++;
903       else if (unformat (line_input, "local-spi %u", &a.local_spi))
904         num_m_args++;
905       else if (unformat (line_input, "remote-spi %u", &a.remote_spi))
906         num_m_args++;
907       else if (unformat (line_input, "instance %u", &a.show_instance))
908         a.renumber = 1;
909       else if (unformat (line_input, "del"))
910         a.is_add = 0;
911       else if (unformat (line_input, "udp-encap"))
912         a.udp_encap = 1;
913       else
914         {
915           error = clib_error_return (0, "unknown input `%U'",
916                                      format_unformat_error, line_input);
917           goto done;
918         }
919     }
920
921   if (num_m_args < 4)
922     {
923       error = clib_error_return (0, "mandatory argument(s) missing");
924       goto done;
925     }
926
927   rv = ipsec_add_del_tunnel_if (&a);
928
929   switch (rv)
930     {
931     case 0:
932       break;
933     case VNET_API_ERROR_INVALID_VALUE:
934       if (a.is_add)
935         error = clib_error_return (0,
936                                    "IPSec tunnel interface already exists...");
937       else
938         error = clib_error_return (0, "IPSec tunnel interface not exists...");
939       goto done;
940     default:
941       error = clib_error_return (0, "ipsec_register_interface returned %d",
942                                  rv);
943       goto done;
944     }
945
946 done:
947   unformat_free (line_input);
948
949   return error;
950 }
951
952 /* *INDENT-OFF* */
953 VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
954   .path = "create ipsec tunnel",
955   .short_help = "create ipsec tunnel local-ip <addr> local-spi <spi> remote-ip <addr> remote-spi <spi> [instance <inst_num>] [udp-encap]",
956   .function = create_ipsec_tunnel_command_fn,
957 };
958 /* *INDENT-ON* */
959
960 static clib_error_t *
961 set_interface_key_command_fn (vlib_main_t * vm,
962                               unformat_input_t * input,
963                               vlib_cli_command_t * cmd)
964 {
965   unformat_input_t _line_input, *line_input = &_line_input;
966   ipsec_main_t *im = &ipsec_main;
967   ipsec_if_set_key_type_t type = IPSEC_IF_SET_KEY_TYPE_NONE;
968   u32 hw_if_index = (u32) ~ 0;
969   u32 alg;
970   u8 *key = 0;
971   clib_error_t *error = NULL;
972
973   if (!unformat_user (input, unformat_line_input, line_input))
974     return 0;
975
976   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
977     {
978       if (unformat (line_input, "%U",
979                     unformat_vnet_hw_interface, im->vnet_main, &hw_if_index))
980         ;
981       else
982         if (unformat
983             (line_input, "local crypto %U", unformat_ipsec_crypto_alg, &alg))
984         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO;
985       else
986         if (unformat
987             (line_input, "remote crypto %U", unformat_ipsec_crypto_alg, &alg))
988         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO;
989       else
990         if (unformat
991             (line_input, "local integ %U", unformat_ipsec_integ_alg, &alg))
992         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG;
993       else
994         if (unformat
995             (line_input, "remote integ %U", unformat_ipsec_integ_alg, &alg))
996         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG;
997       else if (unformat (line_input, "%U", unformat_hex_string, &key))
998         ;
999       else
1000         {
1001           error = clib_error_return (0, "parse error: '%U'",
1002                                      format_unformat_error, line_input);
1003           goto done;
1004         }
1005     }
1006
1007   if (type == IPSEC_IF_SET_KEY_TYPE_NONE)
1008     {
1009       error = clib_error_return (0, "unknown key type");
1010       goto done;
1011     }
1012
1013   if (alg > 0 && vec_len (key) == 0)
1014     {
1015       error = clib_error_return (0, "key is not specified");
1016       goto done;
1017     }
1018
1019   if (hw_if_index == (u32) ~ 0)
1020     {
1021       error = clib_error_return (0, "interface not specified");
1022       goto done;
1023     }
1024
1025   ipsec_set_interface_key (im->vnet_main, hw_if_index, type, alg, key);
1026
1027 done:
1028   vec_free (key);
1029   unformat_free (line_input);
1030
1031   return error;
1032 }
1033
1034 /* *INDENT-OFF* */
1035 VLIB_CLI_COMMAND (set_interface_key_command, static) = {
1036     .path = "set interface ipsec key",
1037     .short_help =
1038     "set interface ipsec key <int> <local|remote> <crypto|integ> <key type> <key>",
1039     .function = set_interface_key_command_fn,
1040 };
1041 /* *INDENT-ON* */
1042
1043 clib_error_t *
1044 ipsec_cli_init (vlib_main_t * vm)
1045 {
1046   return 0;
1047 }
1048
1049 VLIB_INIT_FUNCTION (ipsec_cli_init);
1050
1051
1052 /*
1053  * fd.io coding-style-patch-verification: ON
1054  *
1055  * Local Variables:
1056  * eval: (c-set-style "gnu")
1057  * End:
1058  */