ipsec: fix VPP-1333 - crash in ipsec policy cli
[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   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
152         {
153           error = clib_error_return (0, "parse error: '%U'",
154                                      format_unformat_error, line_input);
155           goto done;
156         }
157     }
158
159   if (sa.crypto_key_len > sizeof (sa.crypto_key))
160     sa.crypto_key_len = sizeof (sa.crypto_key);
161
162   if (sa.integ_key_len > sizeof (sa.integ_key))
163     sa.integ_key_len = sizeof (sa.integ_key);
164
165   if (ck)
166     strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len);
167
168   if (ik)
169     strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len);
170
171   if (is_add)
172     {
173       ASSERT (im->cb.check_support_cb);
174       error = im->cb.check_support_cb (&sa);
175       if (error)
176         goto done;
177     }
178
179   ipsec_add_del_sa (vm, &sa, is_add, 0 /* enable nat traversal */ );
180
181 done:
182   unformat_free (line_input);
183
184   return error;
185 }
186
187 /* *INDENT-OFF* */
188 VLIB_CLI_COMMAND (ipsec_sa_add_del_command, static) = {
189     .path = "ipsec sa",
190     .short_help =
191     "ipsec sa [add|del]",
192     .function = ipsec_sa_add_del_command_fn,
193 };
194 /* *INDENT-ON* */
195
196 static clib_error_t *
197 ipsec_spd_add_del_command_fn (vlib_main_t * vm,
198                               unformat_input_t * input,
199                               vlib_cli_command_t * cmd)
200 {
201   unformat_input_t _line_input, *line_input = &_line_input;
202   u32 spd_id = ~0;
203   int is_add = ~0;
204   clib_error_t *error = NULL;
205
206   if (!unformat_user (input, unformat_line_input, line_input))
207     return 0;
208
209   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
210     {
211       if (unformat (line_input, "add"))
212         is_add = 1;
213       else if (unformat (line_input, "del"))
214         is_add = 0;
215       else if (unformat (line_input, "%u", &spd_id))
216         ;
217       else
218         {
219           error = clib_error_return (0, "parse error: '%U'",
220                                      format_unformat_error, line_input);
221           goto done;
222         }
223     }
224
225   if (spd_id == ~0)
226     {
227       error = clib_error_return (0, "please specify SPD ID");
228       goto done;
229     }
230
231   ipsec_add_del_spd (vm, spd_id, is_add);
232
233 done:
234   unformat_free (line_input);
235
236   return error;
237 }
238
239 /* *INDENT-OFF* */
240 VLIB_CLI_COMMAND (ipsec_spd_add_del_command, static) = {
241     .path = "ipsec spd",
242     .short_help =
243     "ipsec spd [add|del] <id>",
244     .function = ipsec_spd_add_del_command_fn,
245 };
246 /* *INDENT-ON* */
247
248
249 static clib_error_t *
250 ipsec_policy_add_del_command_fn (vlib_main_t * vm,
251                                  unformat_input_t * input,
252                                  vlib_cli_command_t * cmd)
253 {
254   unformat_input_t _line_input, *line_input = &_line_input;
255   ipsec_policy_t p;
256   int is_add = 0;
257   int is_ip_any = 1;
258   u32 tmp, tmp2;
259   clib_error_t *error = NULL;
260
261   memset (&p, 0, sizeof (p));
262   p.lport.stop = p.rport.stop = ~0;
263   p.laddr.stop.ip4.as_u32 = p.raddr.stop.ip4.as_u32 = (u32) ~ 0;
264   p.laddr.stop.ip6.as_u64[0] = p.laddr.stop.ip6.as_u64[1] = (u64) ~ 0;
265   p.raddr.stop.ip6.as_u64[0] = p.raddr.stop.ip6.as_u64[1] = (u64) ~ 0;
266
267   if (!unformat_user (input, unformat_line_input, line_input))
268     return 0;
269
270   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
271     {
272       if (unformat (line_input, "add"))
273         is_add = 1;
274       else if (unformat (line_input, "del"))
275         is_add = 0;
276       else if (unformat (line_input, "spd %u", &p.id))
277         ;
278       else if (unformat (line_input, "inbound"))
279         p.is_outbound = 0;
280       else if (unformat (line_input, "outbound"))
281         p.is_outbound = 1;
282       else if (unformat (line_input, "priority %d", &p.priority))
283         ;
284       else if (unformat (line_input, "protocol %u", &tmp))
285         p.protocol = (u8) tmp;
286       else
287         if (unformat
288             (line_input, "action %U", unformat_ipsec_policy_action,
289              &p.policy))
290         {
291           if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
292             {
293               error = clib_error_return (0, "unsupported action: 'resolve'");
294               goto done;
295             }
296         }
297       else if (unformat (line_input, "sa %u", &p.sa_id))
298         ;
299       else if (unformat (line_input, "local-ip-range %U - %U",
300                          unformat_ip4_address, &p.laddr.start.ip4,
301                          unformat_ip4_address, &p.laddr.stop.ip4))
302         is_ip_any = 0;
303       else if (unformat (line_input, "remote-ip-range %U - %U",
304                          unformat_ip4_address, &p.raddr.start.ip4,
305                          unformat_ip4_address, &p.raddr.stop.ip4))
306         is_ip_any = 0;
307       else if (unformat (line_input, "local-ip-range %U - %U",
308                          unformat_ip6_address, &p.laddr.start.ip6,
309                          unformat_ip6_address, &p.laddr.stop.ip6))
310         {
311           p.is_ipv6 = 1;
312           is_ip_any = 0;
313         }
314       else if (unformat (line_input, "remote-ip-range %U - %U",
315                          unformat_ip6_address, &p.raddr.start.ip6,
316                          unformat_ip6_address, &p.raddr.stop.ip6))
317         {
318           p.is_ipv6 = 1;
319           is_ip_any = 0;
320         }
321       else if (unformat (line_input, "local-port-range %u - %u", &tmp, &tmp2))
322         {
323           p.lport.start = tmp;
324           p.lport.stop = tmp2;
325         }
326       else
327         if (unformat (line_input, "remote-port-range %u - %u", &tmp, &tmp2))
328         {
329           p.rport.start = tmp;
330           p.rport.stop = tmp2;
331         }
332       else
333         {
334           error = clib_error_return (0, "parse error: '%U'",
335                                      format_unformat_error, line_input);
336           goto done;
337         }
338     }
339
340   /* Check if SA is for IPv6/AH which is not supported. Return error if TRUE. */
341   if (p.sa_id)
342     {
343       uword *p1;
344       ipsec_main_t *im = &ipsec_main;
345       ipsec_sa_t *sa = 0;
346       p1 = hash_get (im->sa_index_by_sa_id, p.sa_id);
347       if (!p1)
348         {
349           error =
350             clib_error_return (0, "SA with index %u not found", p.sa_id);
351           goto done;
352         }
353       sa = pool_elt_at_index (im->sad, p1[0]);
354       if (sa && sa->protocol == IPSEC_PROTOCOL_AH && is_add && p.is_ipv6)
355         {
356           error = clib_error_return (0, "AH not supported for IPV6: '%U'",
357                                      format_unformat_error, line_input);
358           goto done;
359         }
360     }
361   ipsec_add_del_policy (vm, &p, is_add);
362   if (is_ip_any)
363     {
364       p.is_ipv6 = 1;
365       ipsec_add_del_policy (vm, &p, is_add);
366     }
367
368 done:
369   unformat_free (line_input);
370
371   return error;
372 }
373
374 /* *INDENT-OFF* */
375 VLIB_CLI_COMMAND (ipsec_policy_add_del_command, static) = {
376     .path = "ipsec policy",
377     .short_help =
378     "ipsec policy [add|del] spd <id> priority <n> ",
379     .function = ipsec_policy_add_del_command_fn,
380 };
381 /* *INDENT-ON* */
382
383 static clib_error_t *
384 set_ipsec_sa_key_command_fn (vlib_main_t * vm,
385                              unformat_input_t * input,
386                              vlib_cli_command_t * cmd)
387 {
388   unformat_input_t _line_input, *line_input = &_line_input;
389   ipsec_sa_t sa;
390   u8 *ck = 0, *ik = 0;
391   clib_error_t *error = NULL;
392
393   memset (&sa, 0, sizeof (sa));
394
395   if (!unformat_user (input, unformat_line_input, line_input))
396     return 0;
397
398   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
399     {
400       if (unformat (line_input, "%u", &sa.id))
401         ;
402       else
403         if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck))
404         sa.crypto_key_len = vec_len (ck);
405       else
406         if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik))
407         sa.integ_key_len = vec_len (ik);
408       else
409         {
410           error = clib_error_return (0, "parse error: '%U'",
411                                      format_unformat_error, line_input);
412           goto done;
413         }
414     }
415
416   if (sa.crypto_key_len > sizeof (sa.crypto_key))
417     sa.crypto_key_len = sizeof (sa.crypto_key);
418
419   if (sa.integ_key_len > sizeof (sa.integ_key))
420     sa.integ_key_len = sizeof (sa.integ_key);
421
422   if (ck)
423     strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len);
424
425   if (ik)
426     strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len);
427
428   ipsec_set_sa_key (vm, &sa);
429
430 done:
431   unformat_free (line_input);
432
433   return error;
434 }
435
436 /* *INDENT-OFF* */
437 VLIB_CLI_COMMAND (set_ipsec_sa_key_command, static) = {
438     .path = "set ipsec sa",
439     .short_help =
440     "set ipsec sa <id> crypto-key <key> integ-key <key>",
441     .function = set_ipsec_sa_key_command_fn,
442 };
443 /* *INDENT-ON* */
444
445 static clib_error_t *
446 show_ipsec_command_fn (vlib_main_t * vm,
447                        unformat_input_t * input, vlib_cli_command_t * cmd)
448 {
449   ipsec_spd_t *spd;
450   ipsec_sa_t *sa;
451   ipsec_policy_t *p;
452   ipsec_main_t *im = &ipsec_main;
453   u32 *i;
454   ipsec_tunnel_if_t *t;
455   vnet_hw_interface_t *hi;
456   u8 *protocol = NULL;
457   u8 *policy = NULL;
458
459   /* *INDENT-OFF* */
460   pool_foreach (sa, im->sad, ({
461     if (sa->id) {
462       vlib_cli_output(vm, "sa %u spi %u mode %s protocol %s%s", sa->id, sa->spi,
463                       sa->is_tunnel ? "tunnel" : "transport",
464                       sa->protocol ? "esp" : "ah",
465                       sa->udp_encap ? " udp-encap-enabled" : "");
466       if (sa->protocol == IPSEC_PROTOCOL_ESP) {
467         vlib_cli_output(vm, "  crypto alg %U%s%U integrity alg %U%s%U",
468                         format_ipsec_crypto_alg, sa->crypto_alg,
469                         sa->crypto_alg ? " key " : "",
470                         format_hex_bytes, sa->crypto_key, sa->crypto_key_len,
471                         format_ipsec_integ_alg, sa->integ_alg,
472                         sa->integ_alg ? " key " : "",
473                         format_hex_bytes, sa->integ_key, sa->integ_key_len);
474       }
475       if (sa->is_tunnel && sa->is_tunnel_ip6) {
476         vlib_cli_output(vm, "  tunnel src %U dst %U",
477                         format_ip6_address, &sa->tunnel_src_addr.ip6,
478                         format_ip6_address, &sa->tunnel_dst_addr.ip6);
479       } else if (sa->is_tunnel) {
480         vlib_cli_output(vm, "  tunnel src %U dst %U",
481                         format_ip4_address, &sa->tunnel_src_addr.ip4,
482                         format_ip4_address, &sa->tunnel_dst_addr.ip4);
483       }
484     }
485   }));
486   /* *INDENT-ON* */
487
488   /* *INDENT-OFF* */
489   pool_foreach (spd, im->spds, ({
490     vlib_cli_output(vm, "spd %u", spd->id);
491
492     vlib_cli_output(vm, " outbound policies");
493     vec_foreach(i, spd->ipv4_outbound_policies)
494       {
495         p = pool_elt_at_index(spd->policies, *i);
496         vec_reset_length(protocol);
497         vec_reset_length(policy);
498         if (p->protocol) {
499           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
500         } else {
501           protocol = format(protocol, "any");
502         }
503         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
504           policy = format(policy, " sa %u", p->sa_id);
505         }
506
507         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
508                         p->priority, format_ipsec_policy_action, p->policy,
509                         protocol, policy);
510         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
511                         format_ip4_address, &p->laddr.start.ip4,
512                         format_ip4_address, &p->laddr.stop.ip4,
513                         p->lport.start, p->lport.stop);
514         vlib_cli_output(vm, "   remte addr range %U - %U port range %u - %u",
515                         format_ip4_address, &p->raddr.start.ip4,
516                         format_ip4_address, &p->raddr.stop.ip4,
517                         p->rport.start, p->rport.stop);
518         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
519                         p->counter.bytes);
520       };
521     vec_foreach(i, spd->ipv6_outbound_policies)
522       {
523         p = pool_elt_at_index(spd->policies, *i);
524         vec_reset_length(protocol);
525         vec_reset_length(policy);
526         if (p->protocol) {
527           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
528         } else {
529           protocol = format(protocol, "any");
530         }
531         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
532           policy = format(policy, " sa %u", p->sa_id);
533         }
534         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
535                         p->priority, format_ipsec_policy_action, p->policy,
536                         protocol, policy);
537         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
538                         format_ip6_address, &p->laddr.start.ip6,
539                         format_ip6_address, &p->laddr.stop.ip6,
540                         p->lport.start, p->lport.stop);
541         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
542                         format_ip6_address, &p->raddr.start.ip6,
543                         format_ip6_address, &p->raddr.stop.ip6,
544                         p->rport.start, p->rport.stop);
545         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
546                         p->counter.bytes);
547       };
548     vlib_cli_output(vm, " inbound policies");
549     vec_foreach(i, spd->ipv4_inbound_protect_policy_indices)
550       {
551         p = pool_elt_at_index(spd->policies, *i);
552         vec_reset_length(protocol);
553         vec_reset_length(policy);
554         if (p->protocol) {
555           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
556         } else {
557           protocol = format(protocol, "any");
558         }
559         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
560           policy = format(policy, " sa %u", p->sa_id);
561         }
562         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
563                         p->priority, format_ipsec_policy_action, p->policy,
564                         protocol, policy);
565         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
566                         format_ip4_address, &p->laddr.start.ip4,
567                         format_ip4_address, &p->laddr.stop.ip4,
568                         p->lport.start, p->lport.stop);
569         vlib_cli_output(vm, "   remte addr range %U - %U port range %u - %u",
570                         format_ip4_address, &p->raddr.start.ip4,
571                         format_ip4_address, &p->raddr.stop.ip4,
572                         p->rport.start, p->rport.stop);
573         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
574                         p->counter.bytes);
575       };
576     vec_foreach(i, spd->ipv4_inbound_policy_discard_and_bypass_indices)
577       {
578         p = pool_elt_at_index(spd->policies, *i);
579         vec_reset_length(protocol);
580         vec_reset_length(policy);
581         if (p->protocol) {
582           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
583         } else {
584           protocol = format(protocol, "any");
585         }
586         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
587           policy = format(policy, " sa %u", p->sa_id);
588         }
589         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
590                         p->priority, format_ipsec_policy_action, p->policy,
591                         protocol, policy);
592         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
593                         format_ip4_address, &p->laddr.start.ip4,
594                         format_ip4_address, &p->laddr.stop.ip4,
595                         p->lport.start, p->lport.stop);
596         vlib_cli_output(vm, "   remte addr range %U - %U port range %u - %u",
597                         format_ip4_address, &p->raddr.start.ip4,
598                         format_ip4_address, &p->raddr.stop.ip4,
599                         p->rport.start, p->rport.stop);
600         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
601                         p->counter.bytes);
602       };
603     vec_foreach(i, spd->ipv6_inbound_protect_policy_indices)
604       {
605         p = pool_elt_at_index(spd->policies, *i);
606         vec_reset_length(protocol);
607         vec_reset_length(policy);
608         if (p->protocol) {
609           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
610         } else {
611           protocol = format(protocol, "any");
612         }
613         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
614           policy = format(policy, " sa %u", p->sa_id);
615         }
616         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
617                         p->priority, format_ipsec_policy_action, p->policy,
618                         protocol, policy);
619         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
620                         format_ip6_address, &p->laddr.start.ip6,
621                         format_ip6_address, &p->laddr.stop.ip6,
622                         p->lport.start, p->lport.stop);
623         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
624                         format_ip6_address, &p->raddr.start.ip6,
625                         format_ip6_address, &p->raddr.stop.ip6,
626                         p->rport.start, p->rport.stop);
627         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
628                         p->counter.bytes);
629       };
630     vec_foreach(i, spd->ipv6_inbound_policy_discard_and_bypass_indices)
631       {
632         p = pool_elt_at_index(spd->policies, *i);
633         vec_reset_length(protocol);
634         vec_reset_length(policy);
635         if (p->protocol) {
636           protocol = format(protocol, "%U", format_ip_protocol, p->protocol);
637         } else {
638           protocol = format(protocol, "any");
639         }
640         if (p->policy == IPSEC_POLICY_ACTION_PROTECT) {
641           policy = format(policy, " sa %u", p->sa_id);
642         }
643         vlib_cli_output(vm, "  priority %d action %U protocol %v%v",
644                         p->priority, format_ipsec_policy_action, p->policy,
645                         protocol, policy);
646         vlib_cli_output(vm, "   local addr range %U - %U port range %u - %u",
647                         format_ip6_address, &p->laddr.start.ip6,
648                         format_ip6_address, &p->laddr.stop.ip6,
649                         p->lport.start, p->lport.stop);
650         vlib_cli_output(vm, "   remote addr range %U - %U port range %u - %u",
651                         format_ip6_address, &p->raddr.start.ip6,
652                         format_ip6_address, &p->raddr.stop.ip6,
653                         p->rport.start, p->rport.stop);
654         vlib_cli_output(vm, "   packets %u bytes %u", p->counter.packets,
655                         p->counter.bytes);
656       };
657   }));
658   /* *INDENT-ON* */
659
660   vlib_cli_output (vm, "tunnel interfaces");
661   /* *INDENT-OFF* */
662   pool_foreach (t, im->tunnel_interfaces, ({
663     if (t->hw_if_index == ~0)
664       continue;
665     hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index);
666     vlib_cli_output(vm, "  %s seq", hi->name);
667     sa = pool_elt_at_index(im->sad, t->output_sa_index);
668     vlib_cli_output(vm, "   seq %u seq-hi %u esn %u anti-replay %u",
669                     sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay);
670     vlib_cli_output(vm, "   local-spi %u local-ip %U", sa->spi,
671                     format_ip4_address, &sa->tunnel_src_addr.ip4);
672     vlib_cli_output(vm, "   local-crypto %U %U",
673                     format_ipsec_crypto_alg, sa->crypto_alg,
674                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
675     vlib_cli_output(vm, "   local-integrity %U %U",
676                     format_ipsec_integ_alg, sa->integ_alg,
677                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
678     sa = pool_elt_at_index(im->sad, t->input_sa_index);
679     vlib_cli_output(vm, "   last-seq %u last-seq-hi %u esn %u anti-replay %u window %U",
680                     sa->last_seq, sa->last_seq_hi, sa->use_esn,
681                     sa->use_anti_replay,
682                     format_ipsec_replay_window, sa->replay_window);
683     vlib_cli_output(vm, "   remote-spi %u remote-ip %U", sa->spi,
684                     format_ip4_address, &sa->tunnel_src_addr.ip4);
685     vlib_cli_output(vm, "   remote-crypto %U %U",
686                     format_ipsec_crypto_alg, sa->crypto_alg,
687                     format_hex_bytes, sa->crypto_key, sa->crypto_key_len);
688     vlib_cli_output(vm, "   remote-integrity %U %U",
689                     format_ipsec_integ_alg, sa->integ_alg,
690                     format_hex_bytes, sa->integ_key, sa->integ_key_len);
691   }));
692   vec_free(policy);
693   vec_free(protocol);
694   /* *INDENT-ON* */
695   return 0;
696 }
697
698 /* *INDENT-OFF* */
699 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
700     .path = "show ipsec",
701     .short_help = "show ipsec",
702     .function = show_ipsec_command_fn,
703 };
704 /* *INDENT-ON* */
705
706 static clib_error_t *
707 clear_ipsec_counters_command_fn (vlib_main_t * vm,
708                                  unformat_input_t * input,
709                                  vlib_cli_command_t * cmd)
710 {
711   ipsec_main_t *im = &ipsec_main;
712   ipsec_spd_t *spd;
713   ipsec_policy_t *p;
714
715   /* *INDENT-OFF* */
716   pool_foreach (spd, im->spds, ({
717     pool_foreach(p, spd->policies, ({
718       p->counter.packets = p->counter.bytes = 0;
719     }));
720   }));
721   /* *INDENT-ON* */
722
723   return 0;
724 }
725
726 /* *INDENT-OFF* */
727 VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = {
728     .path = "clear ipsec counters",
729     .short_help = "clear ipsec counters",
730     .function = clear_ipsec_counters_command_fn,
731 };
732 /* *INDENT-ON* */
733
734 static clib_error_t *
735 create_ipsec_tunnel_command_fn (vlib_main_t * vm,
736                                 unformat_input_t * input,
737                                 vlib_cli_command_t * cmd)
738 {
739   unformat_input_t _line_input, *line_input = &_line_input;
740   ipsec_add_del_tunnel_args_t a;
741   int rv;
742   u32 num_m_args = 0;
743   clib_error_t *error = NULL;
744
745   memset (&a, 0, sizeof (a));
746   a.is_add = 1;
747
748   /* Get a line of input. */
749   if (!unformat_user (input, unformat_line_input, line_input))
750     return 0;
751
752   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
753     {
754       if (unformat
755           (line_input, "local-ip %U", unformat_ip4_address, &a.local_ip))
756         num_m_args++;
757       else
758         if (unformat
759             (line_input, "remote-ip %U", unformat_ip4_address, &a.remote_ip))
760         num_m_args++;
761       else if (unformat (line_input, "local-spi %u", &a.local_spi))
762         num_m_args++;
763       else if (unformat (line_input, "remote-spi %u", &a.remote_spi))
764         num_m_args++;
765       else if (unformat (line_input, "instance %u", &a.show_instance))
766         a.renumber = 1;
767       else if (unformat (line_input, "del"))
768         a.is_add = 0;
769       else
770         {
771           error = clib_error_return (0, "unknown input `%U'",
772                                      format_unformat_error, line_input);
773           goto done;
774         }
775     }
776
777   if (num_m_args < 4)
778     {
779       error = clib_error_return (0, "mandatory argument(s) missing");
780       goto done;
781     }
782
783   rv = ipsec_add_del_tunnel_if (&a);
784
785   switch (rv)
786     {
787     case 0:
788       break;
789     case VNET_API_ERROR_INVALID_VALUE:
790       if (a.is_add)
791         error = clib_error_return (0,
792                                    "IPSec tunnel interface already exists...");
793       else
794         error = clib_error_return (0, "IPSec tunnel interface not exists...");
795       goto done;
796     default:
797       error = clib_error_return (0, "ipsec_register_interface returned %d",
798                                  rv);
799       goto done;
800     }
801
802 done:
803   unformat_free (line_input);
804
805   return error;
806 }
807
808 /* *INDENT-OFF* */
809 VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
810   .path = "create ipsec tunnel",
811   .short_help = "create ipsec tunnel local-ip <addr> local-spi <spi> remote-ip <addr> remote-spi <spi> [instance <inst_num>]",
812   .function = create_ipsec_tunnel_command_fn,
813 };
814 /* *INDENT-ON* */
815
816 static clib_error_t *
817 set_interface_key_command_fn (vlib_main_t * vm,
818                               unformat_input_t * input,
819                               vlib_cli_command_t * cmd)
820 {
821   unformat_input_t _line_input, *line_input = &_line_input;
822   ipsec_main_t *im = &ipsec_main;
823   ipsec_if_set_key_type_t type = IPSEC_IF_SET_KEY_TYPE_NONE;
824   u32 hw_if_index = (u32) ~ 0;
825   u32 alg;
826   u8 *key = 0;
827   clib_error_t *error = NULL;
828
829   if (!unformat_user (input, unformat_line_input, line_input))
830     return 0;
831
832   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
833     {
834       if (unformat (line_input, "%U",
835                     unformat_vnet_hw_interface, im->vnet_main, &hw_if_index))
836         ;
837       else
838         if (unformat
839             (line_input, "local crypto %U", unformat_ipsec_crypto_alg, &alg))
840         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO;
841       else
842         if (unformat
843             (line_input, "remote crypto %U", unformat_ipsec_crypto_alg, &alg))
844         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO;
845       else
846         if (unformat
847             (line_input, "local integ %U", unformat_ipsec_integ_alg, &alg))
848         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG;
849       else
850         if (unformat
851             (line_input, "remote integ %U", unformat_ipsec_integ_alg, &alg))
852         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG;
853       else if (unformat (line_input, "%U", unformat_hex_string, &key))
854         ;
855       else
856         {
857           error = clib_error_return (0, "parse error: '%U'",
858                                      format_unformat_error, line_input);
859           goto done;
860         }
861     }
862
863   if (type == IPSEC_IF_SET_KEY_TYPE_NONE)
864     {
865       error = clib_error_return (0, "unknown key type");
866       goto done;
867     }
868
869   if (alg > 0 && vec_len (key) == 0)
870     {
871       error = clib_error_return (0, "key is not specified");
872       goto done;
873     }
874
875   if (hw_if_index == (u32) ~ 0)
876     {
877       error = clib_error_return (0, "interface not specified");
878       goto done;
879     }
880
881   ipsec_set_interface_key (im->vnet_main, hw_if_index, type, alg, key);
882
883 done:
884   vec_free (key);
885   unformat_free (line_input);
886
887   return error;
888 }
889
890 /* *INDENT-OFF* */
891 VLIB_CLI_COMMAND (set_interface_key_command, static) = {
892     .path = "set interface ipsec key",
893     .short_help =
894     "set interface ipsec key <int> <local|remote> <crypto|integ> <key type> <key>",
895     .function = set_interface_key_command_fn,
896 };
897 /* *INDENT-ON* */
898
899 clib_error_t *
900 ipsec_cli_init (vlib_main_t * vm)
901 {
902   return 0;
903 }
904
905 VLIB_INIT_FUNCTION (ipsec_cli_init);
906
907
908 /*
909  * fd.io coding-style-patch-verification: ON
910  *
911  * Local Variables:
912  * eval: (c-set-style "gnu")
913  * End:
914  */