ipsec: cli bug fix
[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
24 #include <vnet/ipsec/ipsec.h>
25
26 static clib_error_t *
27 set_interface_spd_command_fn (vlib_main_t * vm,
28                               unformat_input_t * input,
29                               vlib_cli_command_t * cmd)
30 {
31   unformat_input_t _line_input, *line_input = &_line_input;
32   ipsec_main_t *im = &ipsec_main;
33   u32 sw_if_index = (u32) ~ 0;
34   u32 spd_id;
35   int is_add = 1;
36   clib_error_t *error = NULL;
37
38   if (!unformat_user (input, unformat_line_input, line_input))
39     return 0;
40
41   if (unformat
42       (line_input, "%U %u", unformat_vnet_sw_interface, im->vnet_main,
43        &sw_if_index, &spd_id))
44     ;
45   else if (unformat (line_input, "del"))
46     is_add = 0;
47   else
48     {
49       error = clib_error_return (0, "parse error: '%U'",
50                                  format_unformat_error, line_input);
51       goto done;
52     }
53
54   ipsec_set_interface_spd (vm, sw_if_index, spd_id, is_add);
55
56 done:
57   unformat_free (line_input);
58
59   return error;
60 }
61
62 /* *INDENT-OFF* */
63 VLIB_CLI_COMMAND (set_interface_spd_command, static) = {
64     .path = "set interface ipsec spd",
65     .short_help =
66     "set interface ipsec spd <int> <id>",
67     .function = set_interface_spd_command_fn,
68 };
69 /* *INDENT-ON* */
70
71 static clib_error_t *
72 ipsec_sa_add_del_command_fn (vlib_main_t * vm,
73                              unformat_input_t * input,
74                              vlib_cli_command_t * cmd)
75 {
76   unformat_input_t _line_input, *line_input = &_line_input;
77   ip46_address_t tun_src = { }, tun_dst =
78   {
79   };
80   ipsec_crypto_alg_t crypto_alg;
81   ipsec_integ_alg_t integ_alg;
82   ipsec_protocol_t proto;
83   ipsec_sa_flags_t flags;
84   clib_error_t *error;
85   ipsec_key_t ck, ik;
86   int is_add, rv;
87   u32 id, spi;
88
89   error = NULL;
90   is_add = 0;
91   flags = IPSEC_SA_FLAG_NONE;
92   proto = IPSEC_PROTOCOL_ESP;
93
94   if (!unformat_user (input, unformat_line_input, line_input))
95     return 0;
96
97   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
98     {
99       if (unformat (line_input, "add %u", &id))
100         is_add = 1;
101       else if (unformat (line_input, "del %u", &id))
102         is_add = 0;
103       else if (unformat (line_input, "spi %u", &spi))
104         ;
105       else if (unformat (line_input, "esp"))
106         proto = IPSEC_PROTOCOL_ESP;
107       else if (unformat (line_input, "ah"))
108         proto = IPSEC_PROTOCOL_AH;
109       else if (unformat (line_input, "crypto-key %U",
110                          unformat_ipsec_key, &ck))
111         ;
112       else if (unformat (line_input, "crypto-alg %U",
113                          unformat_ipsec_crypto_alg, &crypto_alg))
114         ;
115       else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik))
116         ;
117       else if (unformat (line_input, "integ-alg %U",
118                          unformat_ipsec_integ_alg, &integ_alg))
119         ;
120       else if (unformat (line_input, "tunnel-src %U",
121                          unformat_ip46_address, &tun_src, IP46_TYPE_ANY))
122         {
123           flags |= IPSEC_SA_FLAG_IS_TUNNEL;
124           if (!ip46_address_is_ip4 (&tun_src))
125             flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
126         }
127       else if (unformat (line_input, "tunnel-dst %U",
128                          unformat_ip46_address, &tun_dst, IP46_TYPE_ANY))
129         ;
130       else if (unformat (line_input, "udp-encap"))
131         flags |= IPSEC_SA_FLAG_UDP_ENCAP;
132       else
133         {
134           error = clib_error_return (0, "parse error: '%U'",
135                                      format_unformat_error, line_input);
136           goto done;
137         }
138     }
139
140   if (is_add)
141     rv = ipsec_sa_add (id, spi, proto, crypto_alg,
142                        &ck, integ_alg, &ik, flags,
143                        0, &tun_src, &tun_dst, NULL);
144   else
145     rv = ipsec_sa_del (id);
146
147   if (rv)
148     clib_error_return (0, "failed");
149
150 done:
151   unformat_free (line_input);
152
153   return error;
154 }
155
156 /* *INDENT-OFF* */
157 VLIB_CLI_COMMAND (ipsec_sa_add_del_command, static) = {
158     .path = "ipsec sa",
159     .short_help =
160     "ipsec sa [add|del]",
161     .function = ipsec_sa_add_del_command_fn,
162 };
163 /* *INDENT-ON* */
164
165 static clib_error_t *
166 ipsec_spd_add_del_command_fn (vlib_main_t * vm,
167                               unformat_input_t * input,
168                               vlib_cli_command_t * cmd)
169 {
170   unformat_input_t _line_input, *line_input = &_line_input;
171   u32 spd_id = ~0;
172   int is_add = ~0;
173   clib_error_t *error = NULL;
174
175   if (!unformat_user (input, unformat_line_input, line_input))
176     return 0;
177
178   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
179     {
180       if (unformat (line_input, "add"))
181         is_add = 1;
182       else if (unformat (line_input, "del"))
183         is_add = 0;
184       else if (unformat (line_input, "%u", &spd_id))
185         ;
186       else
187         {
188           error = clib_error_return (0, "parse error: '%U'",
189                                      format_unformat_error, line_input);
190           goto done;
191         }
192     }
193
194   if (spd_id == ~0)
195     {
196       error = clib_error_return (0, "please specify SPD ID");
197       goto done;
198     }
199
200   ipsec_add_del_spd (vm, spd_id, is_add);
201
202 done:
203   unformat_free (line_input);
204
205   return error;
206 }
207
208 /* *INDENT-OFF* */
209 VLIB_CLI_COMMAND (ipsec_spd_add_del_command, static) = {
210     .path = "ipsec spd",
211     .short_help =
212     "ipsec spd [add|del] <id>",
213     .function = ipsec_spd_add_del_command_fn,
214 };
215 /* *INDENT-ON* */
216
217
218 static clib_error_t *
219 ipsec_policy_add_del_command_fn (vlib_main_t * vm,
220                                  unformat_input_t * input,
221                                  vlib_cli_command_t * cmd)
222 {
223   unformat_input_t _line_input, *line_input = &_line_input;
224   ipsec_policy_t p;
225   int rv, is_add = 0;
226   u32 tmp, tmp2, stat_index;
227   clib_error_t *error = NULL;
228
229   clib_memset (&p, 0, sizeof (p));
230   p.lport.stop = p.rport.stop = ~0;
231   p.laddr.stop.ip4.as_u32 = p.raddr.stop.ip4.as_u32 = (u32) ~ 0;
232   p.laddr.stop.ip6.as_u64[0] = p.laddr.stop.ip6.as_u64[1] = (u64) ~ 0;
233   p.raddr.stop.ip6.as_u64[0] = p.raddr.stop.ip6.as_u64[1] = (u64) ~ 0;
234
235   if (!unformat_user (input, unformat_line_input, line_input))
236     return 0;
237
238   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
239     {
240       if (unformat (line_input, "add"))
241         is_add = 1;
242       else if (unformat (line_input, "del"))
243         is_add = 0;
244       else if (unformat (line_input, "spd %u", &p.id))
245         ;
246       else if (unformat (line_input, "inbound"))
247         p.is_outbound = 0;
248       else if (unformat (line_input, "outbound"))
249         p.is_outbound = 1;
250       else if (unformat (line_input, "priority %d", &p.priority))
251         ;
252       else if (unformat (line_input, "protocol %u", &tmp))
253         p.protocol = (u8) tmp;
254       else
255         if (unformat
256             (line_input, "action %U", unformat_ipsec_policy_action,
257              &p.policy))
258         {
259           if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
260             {
261               error = clib_error_return (0, "unsupported action: 'resolve'");
262               goto done;
263             }
264         }
265       else if (unformat (line_input, "sa %u", &p.sa_id))
266         ;
267       else if (unformat (line_input, "local-ip-range %U - %U",
268                          unformat_ip4_address, &p.laddr.start.ip4,
269                          unformat_ip4_address, &p.laddr.stop.ip4))
270         ;
271       else if (unformat (line_input, "remote-ip-range %U - %U",
272                          unformat_ip4_address, &p.raddr.start.ip4,
273                          unformat_ip4_address, &p.raddr.stop.ip4))
274         ;
275       else if (unformat (line_input, "local-ip-range %U - %U",
276                          unformat_ip6_address, &p.laddr.start.ip6,
277                          unformat_ip6_address, &p.laddr.stop.ip6))
278         {
279           p.is_ipv6 = 1;
280         }
281       else if (unformat (line_input, "remote-ip-range %U - %U",
282                          unformat_ip6_address, &p.raddr.start.ip6,
283                          unformat_ip6_address, &p.raddr.stop.ip6))
284         {
285           p.is_ipv6 = 1;
286         }
287       else if (unformat (line_input, "local-port-range %u - %u", &tmp, &tmp2))
288         {
289           p.lport.start = tmp;
290           p.lport.stop = tmp2;
291         }
292       else
293         if (unformat (line_input, "remote-port-range %u - %u", &tmp, &tmp2))
294         {
295           p.rport.start = tmp;
296           p.rport.stop = tmp2;
297         }
298       else
299         {
300           error = clib_error_return (0, "parse error: '%U'",
301                                      format_unformat_error, line_input);
302           goto done;
303         }
304     }
305
306   /* Check if SA is for IPv6/AH which is not supported. Return error if TRUE. */
307   if (p.sa_id)
308     {
309       uword *p1;
310       ipsec_main_t *im = &ipsec_main;
311       ipsec_sa_t *sa = 0;
312       p1 = hash_get (im->sa_index_by_sa_id, p.sa_id);
313       if (!p1)
314         {
315           error =
316             clib_error_return (0, "SA with index %u not found", p.sa_id);
317           goto done;
318         }
319       sa = pool_elt_at_index (im->sad, p1[0]);
320       if (sa && sa->protocol == IPSEC_PROTOCOL_AH && is_add && p.is_ipv6)
321         {
322           error = clib_error_return (0, "AH not supported for IPV6: '%U'",
323                                      format_unformat_error, line_input);
324           goto done;
325         }
326     }
327   rv = ipsec_add_del_policy (vm, &p, is_add, &stat_index);
328
329   if (!rv)
330     vlib_cli_output (vm, "policy-index:%d", stat_index);
331   else
332     vlib_cli_output (vm, "error:%d", rv);
333
334 done:
335   unformat_free (line_input);
336
337   return error;
338 }
339
340 /* *INDENT-OFF* */
341 VLIB_CLI_COMMAND (ipsec_policy_add_del_command, static) = {
342     .path = "ipsec policy",
343     .short_help =
344     "ipsec policy [add|del] spd <id> priority <n> ",
345     .function = ipsec_policy_add_del_command_fn,
346 };
347 /* *INDENT-ON* */
348
349 static clib_error_t *
350 set_ipsec_sa_key_command_fn (vlib_main_t * vm,
351                              unformat_input_t * input,
352                              vlib_cli_command_t * cmd)
353 {
354   unformat_input_t _line_input, *line_input = &_line_input;
355   clib_error_t *error = NULL;
356   ipsec_key_t ck, ik;
357   u32 id;
358
359   if (!unformat_user (input, unformat_line_input, line_input))
360     return 0;
361
362   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
363     {
364       if (unformat (line_input, "%u", &id))
365         ;
366       else
367         if (unformat (line_input, "crypto-key %U", unformat_ipsec_key, &ck))
368         ;
369       else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik))
370         ;
371       else
372         {
373           error = clib_error_return (0, "parse error: '%U'",
374                                      format_unformat_error, line_input);
375           goto done;
376         }
377     }
378
379   ipsec_set_sa_key (id, &ck, &ik);
380
381 done:
382   unformat_free (line_input);
383
384   return error;
385 }
386
387 /* *INDENT-OFF* */
388 VLIB_CLI_COMMAND (set_ipsec_sa_key_command, static) = {
389     .path = "set ipsec sa",
390     .short_help =
391     "set ipsec sa <id> crypto-key <key> integ-key <key>",
392     .function = set_ipsec_sa_key_command_fn,
393 };
394 /* *INDENT-ON* */
395
396 static clib_error_t *
397 show_ipsec_command_fn (vlib_main_t * vm,
398                        unformat_input_t * input, vlib_cli_command_t * cmd)
399 {
400   ipsec_main_t *im = &ipsec_main;
401   u32 spd_id, sw_if_index, sai;
402   vnet_hw_interface_t *hi;
403   ipsec_tunnel_if_t *t;
404   u8 *protocol = NULL;
405   u8 *policy = NULL;
406   u32 i;
407
408   /* *INDENT-OFF* */
409   pool_foreach_index (sai, im->sad, ({
410      vlib_cli_output(vm, "%U", format_ipsec_sa, sai);
411   }));
412   pool_foreach_index (i, im->spds, ({
413     vlib_cli_output(vm, "%U", format_ipsec_spd, i);
414   }));
415
416   vlib_cli_output (vm, "SPD Bindings:");
417
418   hash_foreach(sw_if_index, spd_id, im->spd_index_by_sw_if_index, ({
419     vlib_cli_output (vm, "  %d -> %U", spd_id,
420                      format_vnet_sw_if_index_name, im->vnet_main,
421                      sw_if_index);
422   }));
423   /* *INDENT-ON* */
424
425   vlib_cli_output (vm, "tunnel interfaces");
426   /* *INDENT-OFF* */
427   pool_foreach (t, im->tunnel_interfaces, ({
428     if (t->hw_if_index == ~0)
429       continue;
430     hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index);
431
432     vlib_cli_output(vm, "  %s", hi->name);
433
434     vlib_cli_output(vm, "  out-bound sa");
435     vlib_cli_output(vm, "   %U", format_ipsec_sa, t->output_sa_index);
436
437     vlib_cli_output(vm, "  in-bound sa");
438     vlib_cli_output(vm, "   %U", format_ipsec_sa, t->input_sa_index);
439   }));
440   vec_free(policy);
441   vec_free(protocol);
442   /* *INDENT-ON* */
443   return 0;
444 }
445
446 /* *INDENT-OFF* */
447 VLIB_CLI_COMMAND (show_ipsec_command, static) = {
448     .path = "show ipsec",
449     .short_help = "show ipsec [backends]",
450     .function = show_ipsec_command_fn,
451 };
452 /* *INDENT-ON* */
453
454 static clib_error_t *
455 ipsec_show_backends_command_fn (vlib_main_t * vm,
456                                 unformat_input_t * input,
457                                 vlib_cli_command_t * cmd)
458 {
459   ipsec_main_t *im = &ipsec_main;
460   u32 verbose = 0;
461
462   (void) unformat (input, "verbose %u", &verbose);
463
464   vlib_cli_output (vm, "IPsec AH backends available:");
465   u8 *s = format (NULL, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
466   ipsec_ah_backend_t *ab;
467   /* *INDENT-OFF* */
468   pool_foreach (ab, im->ah_backends, {
469     s = format (s, "%=25s %=25u %=10s\n", ab->name, ab - im->ah_backends,
470                 ab - im->ah_backends == im->ah_current_backend ? "yes" : "no");
471     if (verbose) {
472         vlib_node_t *n;
473         n = vlib_get_node (vm, ab->ah4_encrypt_node_index);
474         s = format (s, "     enc4 %s (next %d)\n", n->name, ab->ah4_encrypt_next_index);
475         n = vlib_get_node (vm, ab->ah4_decrypt_node_index);
476         s = format (s, "     dec4 %s (next %d)\n", n->name, ab->ah4_decrypt_next_index);
477         n = vlib_get_node (vm, ab->ah6_encrypt_node_index);
478         s = format (s, "     enc6 %s (next %d)\n", n->name, ab->ah6_encrypt_next_index);
479         n = vlib_get_node (vm, ab->ah6_decrypt_node_index);
480         s = format (s, "     dec6 %s (next %d)\n", n->name, ab->ah6_decrypt_next_index);
481     }
482   });
483   /* *INDENT-ON* */
484   vlib_cli_output (vm, "%v", s);
485   _vec_len (s) = 0;
486   vlib_cli_output (vm, "IPsec ESP backends available:");
487   s = format (s, "%=25s %=25s %=10s\n", "Name", "Index", "Active");
488   ipsec_esp_backend_t *eb;
489   /* *INDENT-OFF* */
490   pool_foreach (eb, im->esp_backends, {
491     s = format (s, "%=25s %=25u %=10s\n", eb->name, eb - im->esp_backends,
492                 eb - im->esp_backends == im->esp_current_backend ? "yes"
493                                                                  : "no");
494     if (verbose) {
495         vlib_node_t *n;
496         n = vlib_get_node (vm, eb->esp4_encrypt_node_index);
497         s = format (s, "     enc4 %s (next %d)\n", n->name, eb->esp4_encrypt_next_index);
498         n = vlib_get_node (vm, eb->esp4_decrypt_node_index);
499         s = format (s, "     dec4 %s (next %d)\n", n->name, eb->esp4_decrypt_next_index);
500         n = vlib_get_node (vm, eb->esp6_encrypt_node_index);
501         s = format (s, "     enc6 %s (next %d)\n", n->name, eb->esp6_encrypt_next_index);
502         n = vlib_get_node (vm, eb->esp6_decrypt_node_index);
503         s = format (s, "     dec6 %s (next %d)\n", n->name, eb->esp6_decrypt_next_index);
504     }
505   });
506   /* *INDENT-ON* */
507   vlib_cli_output (vm, "%v", s);
508
509   vec_free (s);
510   return 0;
511 }
512
513 /* *INDENT-OFF* */
514 VLIB_CLI_COMMAND (ipsec_show_backends_command, static) = {
515     .path = "show ipsec backends",
516     .short_help = "show ipsec backends",
517     .function = ipsec_show_backends_command_fn,
518 };
519 /* *INDENT-ON* */
520
521 static clib_error_t *
522 ipsec_select_backend_command_fn (vlib_main_t * vm,
523                                  unformat_input_t * input,
524                                  vlib_cli_command_t * cmd)
525 {
526   u32 backend_index;
527   ipsec_main_t *im = &ipsec_main;
528
529   if (pool_elts (im->sad) > 0)
530     {
531       return clib_error_return (0,
532                                 "Cannot change IPsec backend, while %u SA entries are configured",
533                                 pool_elts (im->sad));
534     }
535
536   unformat_input_t _line_input, *line_input = &_line_input;
537   /* Get a line of input. */
538   if (!unformat_user (input, unformat_line_input, line_input))
539     return 0;
540
541   if (unformat (line_input, "ah"))
542     {
543       if (unformat (line_input, "%u", &backend_index))
544         {
545           if (ipsec_select_ah_backend (im, backend_index) < 0)
546             {
547               return clib_error_return (0, "Invalid AH backend index `%u'",
548                                         backend_index);
549             }
550         }
551       else
552         {
553           return clib_error_return (0, "Invalid backend index `%U'",
554                                     format_unformat_error, line_input);
555         }
556     }
557   else if (unformat (line_input, "esp"))
558     {
559       if (unformat (line_input, "%u", &backend_index))
560         {
561           if (ipsec_select_esp_backend (im, backend_index) < 0)
562             {
563               return clib_error_return (0, "Invalid ESP backend index `%u'",
564                                         backend_index);
565             }
566         }
567       else
568         {
569           return clib_error_return (0, "Invalid backend index `%U'",
570                                     format_unformat_error, line_input);
571         }
572     }
573   else
574     {
575       return clib_error_return (0, "Unknown input `%U'",
576                                 format_unformat_error, line_input);
577     }
578
579   return 0;
580 }
581
582 /* *INDENT-OFF* */
583 VLIB_CLI_COMMAND (ipsec_select_backend_command, static) = {
584     .path = "ipsec select backend",
585     .short_help = "ipsec select backend <ah|esp> <backend index>",
586     .function = ipsec_select_backend_command_fn,
587 };
588
589 /* *INDENT-ON* */
590
591 static clib_error_t *
592 clear_ipsec_counters_command_fn (vlib_main_t * vm,
593                                  unformat_input_t * input,
594                                  vlib_cli_command_t * cmd)
595 {
596   vlib_clear_combined_counters (&ipsec_spd_policy_counters);
597
598   return (NULL);
599 }
600
601 /* *INDENT-OFF* */
602 VLIB_CLI_COMMAND (clear_ipsec_counters_command, static) = {
603     .path = "clear ipsec counters",
604     .short_help = "clear ipsec counters",
605     .function = clear_ipsec_counters_command_fn,
606 };
607 /* *INDENT-ON* */
608
609 static clib_error_t *
610 create_ipsec_tunnel_command_fn (vlib_main_t * vm,
611                                 unformat_input_t * input,
612                                 vlib_cli_command_t * cmd)
613 {
614   unformat_input_t _line_input, *line_input = &_line_input;
615   ipsec_add_del_tunnel_args_t a;
616   int rv;
617   u32 num_m_args = 0;
618   u8 ipv4_set = 0;
619   u8 ipv6_set = 0;
620   clib_error_t *error = NULL;
621
622   clib_memset (&a, 0, sizeof (a));
623   a.is_add = 1;
624
625   /* Get a line of input. */
626   if (!unformat_user (input, unformat_line_input, line_input))
627     return 0;
628
629   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
630     {
631       if (unformat
632           (line_input, "local-ip %U", unformat_ip46_address, &a.local_ip,
633            IP46_TYPE_ANY))
634         {
635           ip46_address_is_ip4 (&a.local_ip) ? (ipv4_set = 1) : (ipv6_set = 1);
636           num_m_args++;
637         }
638       else
639         if (unformat
640             (line_input, "remote-ip %U", unformat_ip46_address, &a.remote_ip,
641              IP46_TYPE_ANY))
642         {
643           ip46_address_is_ip4 (&a.remote_ip) ? (ipv4_set = 1) : (ipv6_set =
644                                                                  1);
645           num_m_args++;
646         }
647       else if (unformat (line_input, "local-spi %u", &a.local_spi))
648         num_m_args++;
649       else if (unformat (line_input, "remote-spi %u", &a.remote_spi))
650         num_m_args++;
651       else if (unformat (line_input, "instance %u", &a.show_instance))
652         a.renumber = 1;
653       else if (unformat (line_input, "udp-encap"))
654         a.udp_encap = 1;
655       else if (unformat (line_input, "use-esn"))
656         a.esn = 1;
657       else if (unformat (line_input, "use-anti-replay"))
658         a.anti_replay = 1;
659       else if (unformat (line_input, "tx-table %u", &a.tx_table_id))
660         ;
661       else if (unformat (line_input, "del"))
662         a.is_add = 0;
663       else
664         {
665           error = clib_error_return (0, "unknown input `%U'",
666                                      format_unformat_error, line_input);
667           goto done;
668         }
669     }
670
671   if (num_m_args < 4)
672     {
673       error = clib_error_return (0, "mandatory argument(s) missing");
674       goto done;
675     }
676
677   if (ipv6_set)
678     return clib_error_return (0, "currently only IPv4 supported");
679
680   if (ipv4_set && ipv6_set)
681     return clib_error_return (0, "both IPv4 and IPv6 addresses specified");
682
683   rv = ipsec_add_del_tunnel_if (&a);
684
685   switch (rv)
686     {
687     case 0:
688       break;
689     case VNET_API_ERROR_INVALID_VALUE:
690       if (a.is_add)
691         error = clib_error_return (0,
692                                    "IPSec tunnel interface already exists...");
693       else
694         error = clib_error_return (0, "IPSec tunnel interface not exists...");
695       goto done;
696     default:
697       error = clib_error_return (0, "ipsec_register_interface returned %d",
698                                  rv);
699       goto done;
700     }
701
702 done:
703   unformat_free (line_input);
704
705   return error;
706 }
707
708 /* *INDENT-OFF* */
709 VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = {
710   .path = "create ipsec tunnel",
711   .short_help = "create ipsec tunnel local-ip <addr> local-spi <spi> "
712       "remote-ip <addr> remote-spi <spi> [instance <inst_num>] [udp-encap] [use-esn] [use-anti-replay] "
713       "[tx-table <table-id>]",
714   .function = create_ipsec_tunnel_command_fn,
715 };
716 /* *INDENT-ON* */
717
718 static clib_error_t *
719 set_interface_key_command_fn (vlib_main_t * vm,
720                               unformat_input_t * input,
721                               vlib_cli_command_t * cmd)
722 {
723   unformat_input_t _line_input, *line_input = &_line_input;
724   ipsec_main_t *im = &ipsec_main;
725   ipsec_if_set_key_type_t type = IPSEC_IF_SET_KEY_TYPE_NONE;
726   u32 hw_if_index = (u32) ~ 0;
727   u32 alg;
728   u8 *key = 0;
729   clib_error_t *error = NULL;
730
731   if (!unformat_user (input, unformat_line_input, line_input))
732     return 0;
733
734   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
735     {
736       if (unformat (line_input, "%U",
737                     unformat_vnet_hw_interface, im->vnet_main, &hw_if_index))
738         ;
739       else
740         if (unformat
741             (line_input, "local crypto %U", unformat_ipsec_crypto_alg, &alg))
742         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO;
743       else
744         if (unformat
745             (line_input, "remote crypto %U", unformat_ipsec_crypto_alg, &alg))
746         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO;
747       else
748         if (unformat
749             (line_input, "local integ %U", unformat_ipsec_integ_alg, &alg))
750         type = IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG;
751       else
752         if (unformat
753             (line_input, "remote integ %U", unformat_ipsec_integ_alg, &alg))
754         type = IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG;
755       else if (unformat (line_input, "%U", unformat_hex_string, &key))
756         ;
757       else
758         {
759           error = clib_error_return (0, "parse error: '%U'",
760                                      format_unformat_error, line_input);
761           goto done;
762         }
763     }
764
765   if (type == IPSEC_IF_SET_KEY_TYPE_NONE)
766     {
767       error = clib_error_return (0, "unknown key type");
768       goto done;
769     }
770
771   if (alg > 0 && vec_len (key) == 0)
772     {
773       error = clib_error_return (0, "key is not specified");
774       goto done;
775     }
776
777   if (hw_if_index == (u32) ~ 0)
778     {
779       error = clib_error_return (0, "interface not specified");
780       goto done;
781     }
782
783   ipsec_set_interface_key (im->vnet_main, hw_if_index, type, alg, key);
784
785 done:
786   vec_free (key);
787   unformat_free (line_input);
788
789   return error;
790 }
791
792 /* *INDENT-OFF* */
793 VLIB_CLI_COMMAND (set_interface_key_command, static) = {
794     .path = "set interface ipsec key",
795     .short_help =
796     "set interface ipsec key <int> <local|remote> <crypto|integ> <key type> <key>",
797     .function = set_interface_key_command_fn,
798 };
799 /* *INDENT-ON* */
800
801 clib_error_t *
802 ipsec_cli_init (vlib_main_t * vm)
803 {
804   return 0;
805 }
806
807 VLIB_INIT_FUNCTION (ipsec_cli_init);
808
809
810 /*
811  * fd.io coding-style-patch-verification: ON
812  *
813  * Local Variables:
814  * eval: (c-set-style "gnu")
815  * End:
816  */