ip: add support for buffer offload metadata in ip midchain
[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 #include <vnet/fib/fib.h>
23 #include <vnet/ipip/ipip.h>
24
25 #include <vnet/ipsec/ipsec.h>
26 #include <vnet/ipsec/ipsec_tun.h>
27
28 static clib_error_t *
29 set_interface_spd_command_fn (vlib_main_t * vm,
30                               unformat_input_t * input,
31                               vlib_cli_command_t * cmd)
32 {
33   unformat_input_t _line_input, *line_input = &_line_input;
34   ipsec_main_t *im = &ipsec_main;
35   u32 sw_if_index = (u32) ~ 0;
36   u32 spd_id;
37   int is_add = 1;
38   clib_error_t *error = NULL;
39   int err;
40
41   if (!unformat_user (input, unformat_line_input, line_input))
42     return 0;
43
44   if (unformat
45       (line_input, "%U %u", unformat_vnet_sw_interface, im->vnet_main,
46        &sw_if_index, &spd_id))
47     ;
48   else if (unformat (line_input, "del"))
49     is_add = 0;
50   else
51     {
52       error = clib_error_return (0, "parse error: '%U'",
53                                  format_unformat_error, line_input);
54       goto done;
55     }
56
57   err = ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add);
58   switch (err)
59     {
60     case VNET_API_ERROR_SYSCALL_ERROR_1:
61       error = clib_error_return (0, "no such spd-id");
62       break;
63     case VNET_API_ERROR_SYSCALL_ERROR_2:
64       error = clib_error_return (0, "spd already assigned");
65       break;
66     }
67
68 done:
69   unformat_free (line_input);
70
71   return error;
72 }
73
74 VLIB_CLI_COMMAND (set_interface_spd_command, static) = {
75     .path = "set interface ipsec spd",
76     .short_help =
77     "set interface ipsec spd <int> <id>",
78     .function = set_interface_spd_command_fn,
79 };
80
81 static clib_error_t *
82 ipsec_sa_add_del_command_fn (vlib_main_t * vm,
83                              unformat_input_t * input,
84                              vlib_cli_command_t * cmd)
85 {
86   unformat_input_t _line_input, *line_input = &_line_input;
87   ipsec_crypto_alg_t crypto_alg;
88   ipsec_integ_alg_t integ_alg;
89   u32 anti_replay_window_size;
90   ipsec_protocol_t proto;
91   ipsec_sa_flags_t flags;
92   clib_error_t *error;
93   ipsec_key_t ck = { 0 };
94   ipsec_key_t ik = { 0 };
95   u32 id, spi, salt, sai;
96   int i = 0;
97   u16 udp_src, udp_dst;
98   int is_add, rv;
99   u32 m_args = 0;
100   tunnel_t tun = {};
101
102   salt = 0;
103   error = NULL;
104   is_add = 0;
105   flags = IPSEC_SA_FLAG_NONE;
106   proto = IPSEC_PROTOCOL_ESP;
107   anti_replay_window_size = 0;
108   integ_alg = IPSEC_INTEG_ALG_NONE;
109   crypto_alg = IPSEC_CRYPTO_ALG_NONE;
110   udp_src = udp_dst = IPSEC_UDP_PORT_NONE;
111
112   if (!unformat_user (input, unformat_line_input, line_input))
113     return 0;
114
115   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
116     {
117       if (unformat (line_input, "add %u", &id))
118         {
119           is_add = 1;
120           m_args |= 1 << 0;
121         }
122       else if (unformat (line_input, "del %u", &id))
123         {
124           is_add = 0;
125           m_args |= 1 << 0;
126         }
127       else if (unformat (line_input, "spi %u", &spi))
128         m_args |= 1 << 1;
129       else if (unformat (line_input, "salt 0x%x", &salt))
130         ;
131       else if (unformat (line_input, "esp"))
132         proto = IPSEC_PROTOCOL_ESP;
133       else if (unformat (line_input, "ah"))
134         proto = IPSEC_PROTOCOL_AH;
135       else if (unformat (line_input, "crypto-key %U",
136                          unformat_ipsec_key, &ck))
137         ;
138       else if (unformat (line_input, "crypto-alg %U",
139                          unformat_ipsec_crypto_alg, &crypto_alg))
140         ;
141       else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik))
142         ;
143       else if (unformat (line_input, "integ-alg %U",
144                          unformat_ipsec_integ_alg, &integ_alg))
145         ;
146       else if (unformat (line_input, "%U", unformat_tunnel, &tun))
147         {
148           flags |= IPSEC_SA_FLAG_IS_TUNNEL;
149           if (AF_IP6 == tunnel_get_af (&tun))
150             flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
151         }
152       else if (unformat (line_input, "udp-src-port %d", &i))
153         udp_src = i;
154       else if (unformat (line_input, "udp-dst-port %d", &i))
155         udp_dst = i;
156       else if (unformat (line_input, "anti-replay-size %d",
157                          &anti_replay_window_size))
158         flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
159       else if (unformat (line_input, "inbound"))
160         flags |= IPSEC_SA_FLAG_IS_INBOUND;
161       else if (unformat (line_input, "use-anti-replay"))
162         flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
163       else if (unformat (line_input, "use-esn"))
164         flags |= IPSEC_SA_FLAG_USE_ESN;
165       else if (unformat (line_input, "udp-encap"))
166         flags |= IPSEC_SA_FLAG_UDP_ENCAP;
167       else if (unformat (line_input, "async"))
168         flags |= IPSEC_SA_FLAG_IS_ASYNC;
169       else
170         {
171           error = clib_error_return (0, "parse error: '%U'",
172                                      format_unformat_error, line_input);
173           goto done;
174         }
175     }
176
177   if (!(m_args & 1))
178     {
179       error = clib_error_return (0, "missing id");
180       goto done;
181     }
182
183   if (is_add)
184     {
185       if (!(m_args & 2))
186         {
187           error = clib_error_return (0, "missing spi");
188           goto done;
189         }
190       rv =
191         ipsec_sa_add_and_lock (id, spi, proto, crypto_alg, &ck, integ_alg, &ik,
192                                flags, clib_host_to_net_u32 (salt), udp_src,
193                                udp_dst, anti_replay_window_size, &tun, &sai);
194     }
195   else
196     {
197       rv = ipsec_sa_unlock_id (id);
198     }
199
200   if (rv)
201     error = clib_error_return (0, "failed: %d", rv);
202
203 done:
204   unformat_free (line_input);
205
206   return error;
207 }
208
209 VLIB_CLI_COMMAND (ipsec_sa_add_del_command, static) = {
210     .path = "ipsec sa",
211     .short_help =
212     "ipsec sa [add|del]",
213     .function = ipsec_sa_add_del_command_fn,
214 };
215
216 static clib_error_t *
217 ipsec_sa_bind_cli (vlib_main_t *vm, unformat_input_t *input,
218                    vlib_cli_command_t *cmd)
219 {
220   unformat_input_t _line_input, *line_input = &_line_input;
221   u32 id = ~0;
222   u32 worker = ~0;
223   bool bind = 1;
224   int rv;
225   clib_error_t *error = NULL;
226
227   if (!unformat_user (input, unformat_line_input, line_input))
228     return 0;
229
230   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
231     {
232       if (unformat (line_input, "unbind"))
233         bind = 0;
234       else if (id == ~0 && unformat (line_input, "%u", &id))
235         ;
236       else if (unformat (line_input, "%u", &worker))
237         ;
238       else
239         {
240           error = clib_error_return (0, "parse error: '%U'",
241                                      format_unformat_error, line_input);
242           goto done;
243         }
244     }
245
246   if (id == ~0)
247     {
248       error = clib_error_return (0, "please specify SA ID");
249       goto done;
250     }
251
252   if (bind && ~0 == worker)
253     {
254       error = clib_error_return (0, "please specify worker to bind to");
255       goto done;
256     }
257
258   rv = ipsec_sa_bind (id, worker, bind);
259   switch (rv)
260     {
261     case VNET_API_ERROR_INVALID_VALUE:
262       error = clib_error_return (0, "please specify a valid SA ID");
263       break;
264     case VNET_API_ERROR_INVALID_WORKER:
265       error = clib_error_return (0, "please specify a valid worker index");
266       break;
267     }
268
269 done:
270   unformat_free (line_input);
271
272   return error;
273 }
274
275 VLIB_CLI_COMMAND (ipsec_sa_bind_cmd, static) = {
276   .path = "ipsec sa bind",
277   .short_help = "ipsec sa [unbind] <sa-id> <worker>",
278   .function = ipsec_sa_bind_cli,
279 };
280
281 static clib_error_t *
282 ipsec_spd_add_del_command_fn (vlib_main_t * vm,
283                               unformat_input_t * input,
284                               vlib_cli_command_t * cmd)
285 {
286   unformat_input_t _line_input, *line_input = &_line_input;
287   u32 spd_id = ~0;
288   int is_add = ~0;
289   clib_error_t *error = NULL;
290
291   if (!unformat_user (input, unformat_line_input, line_input))
292     return 0;
293
294   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
295     {
296       if (unformat (line_input, "add"))
297         is_add = 1;
298       else if (unformat (line_input, "del"))
299         is_add = 0;
300       else if (unformat (line_input, "%u", &spd_id))
301         ;
302       else
303         {
304           error = clib_error_return (0, "parse error: '%U'",
305                                      format_unformat_error, line_input);
306           goto done;
307         }
308     }
309
310   if (spd_id == ~0)
311     {
312       error = clib_error_return (0, "please specify SPD ID");
313       goto done;
314     }
315
316   ipsec_add_del_spd (vm, spd_id, is_add);
317
318 done:
319   unformat_free (line_input);
320
321   return error;
322 }
323
324 VLIB_CLI_COMMAND (ipsec_spd_add_del_command, static) = {
325     .path = "ipsec spd",
326     .short_help =
327     "ipsec spd [add|del] <id>",
328     .function = ipsec_spd_add_del_command_fn,
329 };
330
331
332 static clib_error_t *
333 ipsec_policy_add_del_command_fn (vlib_main_t * vm,
334                                  unformat_input_t * input,
335                                  vlib_cli_command_t * cmd)
336 {
337   unformat_input_t _line_input, *line_input = &_line_input;
338   ipsec_policy_t p;
339   int rv, is_add = 0;
340   u32 tmp, tmp2, stat_index, local_range_set, remote_range_set;
341   clib_error_t *error = NULL;
342   u32 is_outbound;
343
344   clib_memset (&p, 0, sizeof (p));
345   p.lport.stop = p.rport.stop = ~0;
346   remote_range_set = local_range_set = is_outbound = 0;
347   p.protocol = IPSEC_POLICY_PROTOCOL_ANY;
348
349   if (!unformat_user (input, unformat_line_input, line_input))
350     return 0;
351
352   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
353     {
354       if (unformat (line_input, "add"))
355         is_add = 1;
356       else if (unformat (line_input, "del"))
357         is_add = 0;
358       else if (unformat (line_input, "ip6"))
359         p.is_ipv6 = 1;
360       else if (unformat (line_input, "spd %u", &p.id))
361         ;
362       else if (unformat (line_input, "inbound"))
363         is_outbound = 0;
364       else if (unformat (line_input, "outbound"))
365         is_outbound = 1;
366       else if (unformat (line_input, "priority %d", &p.priority))
367         ;
368       else if (unformat (line_input, "protocol %u", &tmp))
369         p.protocol = (u8) tmp;
370       else
371         if (unformat
372             (line_input, "action %U", unformat_ipsec_policy_action,
373              &p.policy))
374         {
375           if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
376             {
377               error = clib_error_return (0, "unsupported action: 'resolve'");
378               goto done;
379             }
380         }
381       else if (unformat (line_input, "sa %u", &p.sa_id))
382         ;
383       else if (unformat (line_input, "local-ip-range %U - %U",
384                          unformat_ip4_address, &p.laddr.start.ip4,
385                          unformat_ip4_address, &p.laddr.stop.ip4))
386         local_range_set = 1;
387       else if (unformat (line_input, "remote-ip-range %U - %U",
388                          unformat_ip4_address, &p.raddr.start.ip4,
389                          unformat_ip4_address, &p.raddr.stop.ip4))
390         remote_range_set = 1;
391       else if (unformat (line_input, "local-ip-range %U - %U",
392                          unformat_ip6_address, &p.laddr.start.ip6,
393                          unformat_ip6_address, &p.laddr.stop.ip6))
394         {
395           p.is_ipv6 = 1;
396           local_range_set = 1;
397         }
398       else if (unformat (line_input, "remote-ip-range %U - %U",
399                          unformat_ip6_address, &p.raddr.start.ip6,
400                          unformat_ip6_address, &p.raddr.stop.ip6))
401         {
402           p.is_ipv6 = 1;
403           remote_range_set = 1;
404         }
405       else if (unformat (line_input, "local-port-range %u - %u", &tmp, &tmp2))
406         {
407           p.lport.start = tmp;
408           p.lport.stop = tmp2;
409         }
410       else
411         if (unformat (line_input, "remote-port-range %u - %u", &tmp, &tmp2))
412         {
413           p.rport.start = tmp;
414           p.rport.stop = tmp2;
415         }
416       else
417         {
418           error = clib_error_return (0, "parse error: '%U'",
419                                      format_unformat_error, line_input);
420           goto done;
421         }
422     }
423
424   if (!remote_range_set)
425     {
426       if (p.is_ipv6)
427         clib_memset (&p.raddr.stop.ip6, 0xff, 16);
428       else
429         clib_memset (&p.raddr.stop.ip4, 0xff, 4);
430     }
431   if (!local_range_set)
432     {
433       if (p.is_ipv6)
434         clib_memset (&p.laddr.stop.ip6, 0xff, 16);
435       else
436         clib_memset (&p.laddr.stop.ip4, 0xff, 4);
437     }
438
439   rv = ipsec_policy_mk_type (is_outbound, p.is_ipv6, p.policy, &p.type);
440
441   if (rv)
442     {
443       error = clib_error_return (0, "unsupported policy type for:",
444                                  " outboud:%s %s action:%U",
445                                  (is_outbound ? "yes" : "no"),
446                                  (p.is_ipv6 ? "IPv4" : "IPv6"),
447                                  format_ipsec_policy_action, p.policy);
448       goto done;
449     }
450
451   rv = ipsec_add_del_policy (vm, &p, is_add, &stat_index);
452
453   if (!rv)
454     vlib_cli_output (vm, "policy-index:%d", stat_index);
455   else
456     vlib_cli_output (vm, "error:%d", rv);
457
458 done:
459   unformat_free (line_input);
460
461   return error;
462 }
463
464 VLIB_CLI_COMMAND (ipsec_policy_add_del_command, static) = {
465     .path = "ipsec policy",
466     .short_help =
467     "ipsec policy [add|del] spd <id> priority <n> ",
468     .function = ipsec_policy_add_del_command_fn,
469 };
470
471 static void
472 ipsec_sa_show_all (vlib_main_t * vm, ipsec_main_t * im, u8 detail)
473 {
474   u32 sai;
475
476   pool_foreach_index (sai, ipsec_sa_pool)
477     {
478       vlib_cli_output (vm, "%U", format_ipsec_sa, sai,
479                        (detail ? IPSEC_FORMAT_DETAIL : IPSEC_FORMAT_BRIEF));
480     }
481 }
482
483 static void
484 ipsec_spd_show_all (vlib_main_t * vm, ipsec_main_t * im)
485 {
486   u32 spdi;
487
488   pool_foreach_index (spdi, im->spds)  {
489     vlib_cli_output(vm, "%U", format_ipsec_spd, spdi);
490   }
491
492   if (im->output_flow_cache_flag)
493     {
494       vlib_cli_output (vm, "%U", format_ipsec_out_spd_flow_cache);
495     }
496   if (im->input_flow_cache_flag)
497     {
498       vlib_cli_output (vm, "%U", format_ipsec_in_spd_flow_cache);
499     }
500 }
501
502 static void
503 ipsec_spd_bindings_show_all (vlib_main_t * vm, ipsec_main_t * im)
504 {
505   u32 spd_id, sw_if_index;
506   ipsec_spd_t *spd;
507
508   vlib_cli_output (vm, "SPD Bindings:");
509
510   hash_foreach(sw_if_index, spd_id, im->spd_index_by_sw_if_index, ({
511     spd = pool_elt_at_index (im->spds, spd_id);
512     vlib_cli_output (vm, "  %d -> %U", spd->id,
513                      format_vnet_sw_if_index_name, im->vnet_main,
514                      sw_if_index);
515   }));
516 }
517
518 static walk_rc_t
519 ipsec_tun_protect_show_one (index_t itpi, void *ctx)
520 {
521   vlib_cli_output (ctx, "%U", format_ipsec_tun_protect_index, itpi);
522
523   return (WALK_CONTINUE);
524 }
525
526 static void
527 ipsec_tunnel_show_all (vlib_main_t * vm)
528 {
529   ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm);
530 }
531
532 static clib_error_t *
533 show_ipsec_command_fn (vlib_main_t * vm,
534                        unformat_input_t * input, vlib_cli_command_t * cmd)
535 {
536   ipsec_main_t *im = &ipsec_main;
537
538   ipsec_sa_show_all (vm, im, 0);
539   ipsec_spd_show_all (vm, im);
540   ipsec_spd_bindings_show_all (vm, im);
541   ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm);
542
543   vlib_cli_output (vm, "IPSec async mode: %s",
544                    (im->async_mode ? "on" : "off"));
545
546   return 0;
547 }
548
549 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
550     .path = "show ipsec all",
551     .short_help = "show ipsec all",
552     .function = show_ipsec_command_fn,
553 };
554
555 static clib_error_t *
556 show_ipsec_sa_command_fn (vlib_main_t * vm,
557                           unformat_input_t * input, vlib_cli_command_t * cmd)
558 {
559   ipsec_main_t *im = &ipsec_main;
560   u32 sai = ~0;
561   u8 detail = 0;
562
563   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
564     {
565       if (unformat (input, "%u", &sai))
566         ;
567       if (unformat (input, "detail"))
568         detail = 1;
569       else
570         break;
571     }
572
573   if (~0 == sai)
574     ipsec_sa_show_all (vm, im, detail);
575   else
576     vlib_cli_output (vm, "%U", format_ipsec_sa, sai,
577                      IPSEC_FORMAT_DETAIL | IPSEC_FORMAT_INSECURE);
578
579   return 0;
580 }
581
582 static clib_error_t *
583 clear_ipsec_sa_command_fn (vlib_main_t * vm,
584                            unformat_input_t * input, vlib_cli_command_t * cmd)
585 {
586   u32 sai = ~0;
587
588   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
589     {
590       if (unformat (input, "%u", &sai))
591         ;
592       else
593         break;
594     }
595
596   if (~0 == sai)
597     {
598       pool_foreach_index (sai, ipsec_sa_pool)
599         {
600           ipsec_sa_clear (sai);
601         }
602     }
603   else
604     {
605       if (pool_is_free_index (ipsec_sa_pool, sai))
606         return clib_error_return (0, "unknown SA index: %d", sai);
607       else
608         ipsec_sa_clear (sai);
609     }
610
611   return 0;
612 }
613
614 VLIB_CLI_COMMAND (show_ipsec_sa_command, static) = {
615     .path = "show ipsec sa",
616     .short_help = "show ipsec sa [index]",
617     .function = show_ipsec_sa_command_fn,
618 };
619
620 VLIB_CLI_COMMAND (clear_ipsec_sa_command, static) = {
621     .path = "clear ipsec sa",
622     .short_help = "clear ipsec sa [index]",
623     .function = clear_ipsec_sa_command_fn,
624 };
625
626 static clib_error_t *
627 show_ipsec_spd_command_fn (vlib_main_t * vm,
628                            unformat_input_t * input, vlib_cli_command_t * cmd)
629 {
630   ipsec_main_t *im = &ipsec_main;
631   u8 show_bindings = 0;
632   u32 spdi = ~0;
633
634   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
635     {
636       if (unformat (input, "%u", &spdi))
637         ;
638       else if (unformat (input, "bindings"))
639         show_bindings = 1;
640       else
641         break;
642     }
643
644   if (show_bindings)
645     ipsec_spd_bindings_show_all (vm, im);
646   else if (~0 != spdi)
647     vlib_cli_output (vm, "%U", format_ipsec_spd, spdi);
648   else
649     ipsec_spd_show_all (vm, im);
650
651   return 0;
652 }
653
654 VLIB_CLI_COMMAND (show_ipsec_spd_command, static) = {
655     .path = "show ipsec spd",
656     .short_help = "show ipsec spd [index]",
657     .function = show_ipsec_spd_command_fn,
658 };
659
660 static clib_error_t *
661 show_ipsec_tunnel_command_fn (vlib_main_t * vm,
662                               unformat_input_t * input,
663                               vlib_cli_command_t * cmd)
664 {
665   ipsec_tunnel_show_all (vm);
666
667   return 0;
668 }
669
670 VLIB_CLI_COMMAND (show_ipsec_tunnel_command, static) = {
671     .path = "show ipsec tunnel",
672     .short_help = "show ipsec tunnel",
673     .function = show_ipsec_tunnel_command_fn,
674 };
675
676 static clib_error_t *
677 ipsec_show_backends_command_fn (vlib_main_t * vm,
678                                 unformat_input_t * input,
679                                 vlib_cli_command_t * cmd)
680 {
681   ipsec_main_t *im = &ipsec_main;
682   u32 verbose = 0;
683
684   (void) unformat (input, "verbose %u", &verbose);
685
686   vlib_cli_output (vm, "IPsec AH backends available:");
687   u8 *s = format (NULL, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
688   ipsec_ah_backend_t *ab;
689   pool_foreach (ab, im->ah_backends) {
690     s = format (s, "%=25s %=25u %=10s\n", ab->name, ab - im->ah_backends,
691                 ab - im->ah_backends == im->ah_current_backend ? "yes" : "no");
692     if (verbose) {
693         vlib_node_t *n;
694         n = vlib_get_node (vm, ab->ah4_encrypt_node_index);
695         s = format (s, "     enc4 %s (next %d)\n", n->name, ab->ah4_encrypt_next_index);
696         n = vlib_get_node (vm, ab->ah4_decrypt_node_index);
697         s = format (s, "     dec4 %s (next %d)\n", n->name, ab->ah4_decrypt_next_index);
698         n = vlib_get_node (vm, ab->ah6_encrypt_node_index);
699         s = format (s, "     enc6 %s (next %d)\n", n->name, ab->ah6_encrypt_next_index);
700         n = vlib_get_node (vm, ab->ah6_decrypt_node_index);
701         s = format (s, "     dec6 %s (next %d)\n", n->name, ab->ah6_decrypt_next_index);
702     }
703   }
704   vlib_cli_output (vm, "%v", s);
705   vec_set_len (s, 0);
706   vlib_cli_output (vm, "IPsec ESP backends available:");
707   s = format (s, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
708   ipsec_esp_backend_t *eb;
709   pool_foreach (eb, im->esp_backends) {
710     s = format (s, "%=25s %=25u %=10s\n", eb->name, eb - im->esp_backends,
711                 eb - im->esp_backends == im->esp_current_backend ? "yes"
712                                                                  : "no");
713     if (verbose) {
714         vlib_node_t *n;
715         n = vlib_get_node (vm, eb->esp4_encrypt_node_index);
716         s = format (s, "     enc4 %s (next %d)\n", n->name, eb->esp4_encrypt_next_index);
717         n = vlib_get_node (vm, eb->esp4_decrypt_node_index);
718         s = format (s, "     dec4 %s (next %d)\n", n->name, eb->esp4_decrypt_next_index);
719         n = vlib_get_node (vm, eb->esp6_encrypt_node_index);
720         s = format (s, "     enc6 %s (next %d)\n", n->name, eb->esp6_encrypt_next_index);
721         n = vlib_get_node (vm, eb->esp6_decrypt_node_index);
722         s = format (s, "     dec6 %s (next %d)\n", n->name, eb->esp6_decrypt_next_index);
723     }
724   }
725   vlib_cli_output (vm, "%v", s);
726
727   vec_free (s);
728   return 0;
729 }
730
731 VLIB_CLI_COMMAND (ipsec_show_backends_command, static) = {
732     .path = "show ipsec backends",
733     .short_help = "show ipsec backends",
734     .function = ipsec_show_backends_command_fn,
735 };
736
737 static clib_error_t *
738 ipsec_select_backend_command_fn (vlib_main_t * vm,
739                                  unformat_input_t * input,
740                                  vlib_cli_command_t * cmd)
741 {
742   unformat_input_t _line_input, *line_input = &_line_input;
743   ipsec_main_t *im = &ipsec_main;
744   clib_error_t *error;
745   u32 backend_index;
746
747   error = ipsec_rsc_in_use (im);
748
749   if (error)
750     return error;
751
752   /* Get a line of input. */
753   if (!unformat_user (input, unformat_line_input, line_input))
754     return 0;
755
756   if (unformat (line_input, "ah"))
757     {
758       if (unformat (line_input, "%u", &backend_index))
759         {
760           if (ipsec_select_ah_backend (im, backend_index) < 0)
761             {
762               return clib_error_return (0, "Invalid AH backend index `%u'",
763                                         backend_index);
764             }
765         }
766       else
767         {
768           return clib_error_return (0, "Invalid backend index `%U'",
769                                     format_unformat_error, line_input);
770         }
771     }
772   else if (unformat (line_input, "esp"))
773     {
774       if (unformat (line_input, "%u", &backend_index))
775         {
776           if (ipsec_select_esp_backend (im, backend_index) < 0)
777             {
778               return clib_error_return (0, "Invalid ESP backend index `%u'",
779                                         backend_index);
780             }
781         }
782       else
783         {
784           return clib_error_return (0, "Invalid backend index `%U'",
785                                     format_unformat_error, line_input);
786         }
787     }
788   else
789     {
790       return clib_error_return (0, "Unknown input `%U'",
791                                 format_unformat_error, line_input);
792     }
793
794   return 0;
795 }
796
797 VLIB_CLI_COMMAND (ipsec_select_backend_command, static) = {
798     .path = "ipsec select backend",
799     .short_help = "ipsec select backend <ah|esp> <backend index>",
800     .function = ipsec_select_backend_command_fn,
801 };
802
803
804 static clib_error_t *
805 clear_ipsec_counters_command_fn (vlib_main_t * vm,
806                                  unformat_input_t * input,
807                                  vlib_cli_command_t * cmd)
808 {
809   vlib_clear_combined_counters (&ipsec_spd_policy_counters);
810   vlib_clear_combined_counters (&ipsec_sa_counters);
811   for (int i = 0; i < IPSEC_SA_N_ERRORS; i++)
812     vlib_clear_simple_counters (&ipsec_sa_err_counters[i]);
813
814   return (NULL);
815 }
816
817 VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = {
818     .path = "clear ipsec counters",
819     .short_help = "clear ipsec counters",
820     .function = clear_ipsec_counters_command_fn,
821 };
822
823 static clib_error_t *
824 ipsec_tun_protect_cmd (vlib_main_t * vm,
825                        unformat_input_t * input, vlib_cli_command_t * cmd)
826 {
827   unformat_input_t _line_input, *line_input = &_line_input;
828   u32 sw_if_index, is_del, sa_in, sa_out, *sa_ins = NULL;
829   ip_address_t peer = { };
830   vnet_main_t *vnm;
831
832   is_del = 0;
833   sw_if_index = ~0;
834   vnm = vnet_get_main ();
835
836   if (!unformat_user (input, unformat_line_input, line_input))
837     return 0;
838
839   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
840     {
841       if (unformat (line_input, "del"))
842         is_del = 1;
843       else if (unformat (line_input, "add"))
844         is_del = 0;
845       else if (unformat (line_input, "sa-in %d", &sa_in))
846         vec_add1 (sa_ins, sa_in);
847       else if (unformat (line_input, "sa-out %d", &sa_out))
848         ;
849       else if (unformat (line_input, "%U",
850                          unformat_vnet_sw_interface, vnm, &sw_if_index))
851         ;
852       else if (unformat (line_input, "%U", unformat_ip_address, &peer))
853         ;
854       else
855         return (clib_error_return (0, "unknown input '%U'",
856                                    format_unformat_error, line_input));
857     }
858
859   if (!is_del)
860     ipsec_tun_protect_update (sw_if_index, &peer, sa_out, sa_ins);
861   else
862     ipsec_tun_protect_del (sw_if_index, &peer);
863
864   unformat_free (line_input);
865   return NULL;
866 }
867
868 /**
869  * Protect tunnel with IPSEC
870  */
871 VLIB_CLI_COMMAND (ipsec_tun_protect_cmd_node, static) =
872 {
873   .path = "ipsec tunnel protect",
874   .function = ipsec_tun_protect_cmd,
875   .short_help = "ipsec tunnel protect <interface> input-sa <SA> output-sa <SA> [add|del]",
876     // this is not MP safe
877 };
878
879
880 static clib_error_t *
881 ipsec_tun_protect_show (vlib_main_t * vm,
882                         unformat_input_t * input, vlib_cli_command_t * cmd)
883 {
884   ipsec_tun_protect_walk (ipsec_tun_protect_show_one, vm);
885
886   return NULL;
887 }
888
889 /**
890  * show IPSEC tunnel protection
891  */
892 VLIB_CLI_COMMAND (ipsec_tun_protect_show_node, static) =
893 {
894   .path = "show ipsec protect",
895   .function = ipsec_tun_protect_show,
896   .short_help =  "show ipsec protect",
897 };
898
899 static int
900 ipsec_tun_protect4_hash_show_one (clib_bihash_kv_8_16_t * kv, void *arg)
901 {
902   ipsec4_tunnel_kv_t *ikv = (ipsec4_tunnel_kv_t *) kv;
903   vlib_main_t *vm = arg;
904
905   vlib_cli_output (vm, " %U", format_ipsec4_tunnel_kv, ikv);
906
907   return (BIHASH_WALK_CONTINUE);
908 }
909
910 static int
911 ipsec_tun_protect6_hash_show_one (clib_bihash_kv_24_16_t * kv, void *arg)
912 {
913   ipsec6_tunnel_kv_t *ikv = (ipsec6_tunnel_kv_t *) kv;
914   vlib_main_t *vm = arg;
915
916   vlib_cli_output (vm, " %U", format_ipsec6_tunnel_kv, ikv);
917
918   return (BIHASH_WALK_CONTINUE);
919 }
920
921 static clib_error_t *
922 ipsec_tun_protect_hash_show (vlib_main_t * vm,
923                              unformat_input_t * input,
924                              vlib_cli_command_t * cmd)
925 {
926   ipsec_main_t *im = &ipsec_main;
927
928   {
929     vlib_cli_output (vm, "IPv4:");
930
931     clib_bihash_foreach_key_value_pair_8_16
932       (&im->tun4_protect_by_key, ipsec_tun_protect4_hash_show_one, vm);
933
934     vlib_cli_output (vm, "IPv6:");
935
936     clib_bihash_foreach_key_value_pair_24_16
937       (&im->tun6_protect_by_key, ipsec_tun_protect6_hash_show_one, vm);
938   }
939
940   return NULL;
941 }
942
943 /**
944  * show IPSEC tunnel protection hash tables
945  */
946 VLIB_CLI_COMMAND (ipsec_tun_protect_hash_show_node, static) =
947 {
948   .path = "show ipsec protect-hash",
949   .function = ipsec_tun_protect_hash_show,
950   .short_help =  "show ipsec protect-hash",
951 };
952
953 clib_error_t *
954 ipsec_cli_init (vlib_main_t * vm)
955 {
956   return 0;
957 }
958
959 VLIB_INIT_FUNCTION (ipsec_cli_init);
960
961 static clib_error_t *
962 set_async_mode_command_fn (vlib_main_t * vm, unformat_input_t * input,
963                            vlib_cli_command_t * cmd)
964 {
965   unformat_input_t _line_input, *line_input = &_line_input;
966   int async_enable = 0;
967
968   if (!unformat_user (input, unformat_line_input, line_input))
969     return 0;
970
971   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
972     {
973       if (unformat (line_input, "on"))
974         async_enable = 1;
975       else if (unformat (line_input, "off"))
976         async_enable = 0;
977       else
978         return (clib_error_return (0, "unknown input '%U'",
979                                    format_unformat_error, line_input));
980     }
981
982   ipsec_set_async_mode (async_enable);
983
984   unformat_free (line_input);
985   return (NULL);
986 }
987
988 VLIB_CLI_COMMAND (set_async_mode_command, static) = {
989     .path = "set ipsec async mode",
990     .short_help = "set ipsec async mode on|off",
991     .function = set_async_mode_command_fn,
992 };
993
994 /*
995  * fd.io coding-style-patch-verification: ON
996  *
997  * Local Variables:
998  * eval: (c-set-style "gnu")
999  * End:
1000  */