ipsec: add ipsec set async mode api
[vpp.git] / src / vnet / ipsec / ipsec_api.c
1 /*
2  *------------------------------------------------------------------
3  * ipsec_api.c - ipsec api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/ip/ip.h>
26 #include <vnet/ip/ip_types_api.h>
27 #include <vnet/ipsec/ipsec_types_api.h>
28 #include <vnet/tunnel/tunnel_types_api.h>
29 #include <vnet/fib/fib.h>
30 #include <vnet/ipip/ipip.h>
31
32 #include <vnet/vnet_msg_enum.h>
33
34 #if WITH_LIBSSL > 0
35 #include <vnet/ipsec/ipsec.h>
36 #include <vnet/ipsec/ipsec_tun.h>
37 #include <vnet/ipsec/ipsec_itf.h>
38 #endif /* IPSEC */
39
40 #define vl_typedefs             /* define message structures */
41 #include <vnet/vnet_all_api_h.h>
42 #undef vl_typedefs
43
44 #define vl_endianfun            /* define message structures */
45 #include <vnet/vnet_all_api_h.h>
46 #undef vl_endianfun
47
48 /* instantiate all the print functions we know about */
49 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
50 #define vl_printfun
51 #include <vnet/vnet_all_api_h.h>
52 #undef vl_printfun
53
54 #include <vlibapi/api_helper_macros.h>
55
56 #define foreach_vpe_api_msg                                     \
57 _(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                         \
58 _(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)     \
59 _(IPSEC_SPD_ENTRY_ADD_DEL, ipsec_spd_entry_add_del)             \
60 _(IPSEC_SAD_ENTRY_ADD_DEL, ipsec_sad_entry_add_del)             \
61 _(IPSEC_SA_DUMP, ipsec_sa_dump)                                 \
62 _(IPSEC_SPDS_DUMP, ipsec_spds_dump)                             \
63 _(IPSEC_SPD_DUMP, ipsec_spd_dump)                               \
64 _(IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump)           \
65 _(IPSEC_ITF_CREATE, ipsec_itf_create)                           \
66 _(IPSEC_ITF_DELETE, ipsec_itf_delete)                           \
67 _(IPSEC_ITF_DUMP, ipsec_itf_dump)                               \
68 _(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del)             \
69 _(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa)               \
70 _(IPSEC_SELECT_BACKEND, ipsec_select_backend)                   \
71 _(IPSEC_BACKEND_DUMP, ipsec_backend_dump)                       \
72 _(IPSEC_TUNNEL_PROTECT_UPDATE, ipsec_tunnel_protect_update)     \
73 _(IPSEC_TUNNEL_PROTECT_DEL, ipsec_tunnel_protect_del)           \
74 _(IPSEC_TUNNEL_PROTECT_DUMP, ipsec_tunnel_protect_dump)         \
75 _(IPSEC_SET_ASYNC_MODE, ipsec_set_async_mode)
76
77 static void
78 vl_api_ipsec_spd_add_del_t_handler (vl_api_ipsec_spd_add_del_t * mp)
79 {
80 #if WITH_LIBSSL == 0
81   clib_warning ("unimplemented");
82 #else
83
84   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
85   vl_api_ipsec_spd_add_del_reply_t *rmp;
86   int rv;
87
88   rv = ipsec_add_del_spd (vm, ntohl (mp->spd_id), mp->is_add);
89
90   REPLY_MACRO (VL_API_IPSEC_SPD_ADD_DEL_REPLY);
91 #endif
92 }
93
94 static void vl_api_ipsec_interface_add_del_spd_t_handler
95   (vl_api_ipsec_interface_add_del_spd_t * mp)
96 {
97   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
98   vl_api_ipsec_interface_add_del_spd_reply_t *rmp;
99   int rv;
100   u32 sw_if_index __attribute__ ((unused));
101   u32 spd_id __attribute__ ((unused));
102
103   sw_if_index = ntohl (mp->sw_if_index);
104   spd_id = ntohl (mp->spd_id);
105
106   VALIDATE_SW_IF_INDEX (mp);
107
108 #if WITH_LIBSSL > 0
109   rv = ipsec_set_interface_spd (vm, sw_if_index, spd_id, mp->is_add);
110 #else
111   rv = VNET_API_ERROR_UNIMPLEMENTED;
112 #endif
113
114   BAD_SW_IF_INDEX_LABEL;
115
116   REPLY_MACRO (VL_API_IPSEC_INTERFACE_ADD_DEL_SPD_REPLY);
117 }
118
119 static void vl_api_ipsec_tunnel_protect_update_t_handler
120   (vl_api_ipsec_tunnel_protect_update_t * mp)
121 {
122   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
123   vl_api_ipsec_tunnel_protect_update_reply_t *rmp;
124   u32 sw_if_index, ii, *sa_ins = NULL;
125   ip_address_t nh;
126   int rv;
127
128   sw_if_index = ntohl (mp->tunnel.sw_if_index);
129
130   VALIDATE_SW_IF_INDEX (&(mp->tunnel));
131
132 #if WITH_LIBSSL > 0
133
134   for (ii = 0; ii < mp->tunnel.n_sa_in; ii++)
135     vec_add1 (sa_ins, ntohl (mp->tunnel.sa_in[ii]));
136
137   ip_address_decode2 (&mp->tunnel.nh, &nh);
138
139   rv = ipsec_tun_protect_update (sw_if_index, &nh,
140                                  ntohl (mp->tunnel.sa_out), sa_ins);
141 #else
142   rv = VNET_API_ERROR_UNIMPLEMENTED;
143 #endif
144
145   BAD_SW_IF_INDEX_LABEL;
146
147   REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_UPDATE_REPLY);
148 }
149
150 static void vl_api_ipsec_tunnel_protect_del_t_handler
151   (vl_api_ipsec_tunnel_protect_del_t * mp)
152 {
153   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
154   vl_api_ipsec_tunnel_protect_del_reply_t *rmp;
155   ip_address_t nh;
156   u32 sw_if_index;
157   int rv;
158
159   sw_if_index = ntohl (mp->sw_if_index);
160
161   VALIDATE_SW_IF_INDEX (mp);
162
163 #if WITH_LIBSSL > 0
164   ip_address_decode2 (&mp->nh, &nh);
165   rv = ipsec_tun_protect_del (sw_if_index, &nh);
166 #else
167   rv = VNET_API_ERROR_UNIMPLEMENTED;
168 #endif
169
170   BAD_SW_IF_INDEX_LABEL;
171
172   REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_DEL_REPLY);
173 }
174
175 typedef struct ipsec_dump_walk_ctx_t_
176 {
177   vl_api_registration_t *reg;
178   u32 context;
179 } ipsec_dump_walk_ctx_t;
180
181 static walk_rc_t
182 send_ipsec_tunnel_protect_details (index_t itpi, void *arg)
183 {
184   ipsec_dump_walk_ctx_t *ctx = arg;
185   vl_api_ipsec_tunnel_protect_details_t *mp;
186   ipsec_tun_protect_t *itp;
187   u32 ii = 0;
188   ipsec_sa_t *sa;
189
190   itp = ipsec_tun_protect_get (itpi);
191
192   mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (u32) * itp->itp_n_sa_in));
193   clib_memset (mp, 0, sizeof (*mp));
194   mp->_vl_msg_id = ntohs (VL_API_IPSEC_TUNNEL_PROTECT_DETAILS);
195   mp->context = ctx->context;
196
197   mp->tun.sw_if_index = htonl (itp->itp_sw_if_index);
198   ip_address_encode2 (itp->itp_key, &mp->tun.nh);
199
200   sa = ipsec_sa_get (itp->itp_out_sa);
201   mp->tun.sa_out = htonl (sa->id);
202   mp->tun.n_sa_in = itp->itp_n_sa_in;
203   /* *INDENT-OFF* */
204   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
205   ({
206     mp->tun.sa_in[ii++] = htonl (sa->id);
207   }));
208   /* *INDENT-ON* */
209
210   vl_api_send_msg (ctx->reg, (u8 *) mp);
211
212   return (WALK_CONTINUE);
213 }
214
215 static void
216 vl_api_ipsec_tunnel_protect_dump_t_handler (vl_api_ipsec_tunnel_protect_dump_t
217                                             * mp)
218 {
219   vl_api_registration_t *reg;
220   u32 sw_if_index;
221
222 #if WITH_LIBSSL > 0
223   reg = vl_api_client_index_to_registration (mp->client_index);
224   if (!reg)
225     return;
226
227   ipsec_dump_walk_ctx_t ctx = {
228     .reg = reg,
229     .context = mp->context,
230   };
231
232   sw_if_index = ntohl (mp->sw_if_index);
233
234   if (~0 == sw_if_index)
235     {
236       ipsec_tun_protect_walk (send_ipsec_tunnel_protect_details, &ctx);
237     }
238   else
239     {
240       ipsec_tun_protect_walk_itf (sw_if_index,
241                                   send_ipsec_tunnel_protect_details, &ctx);
242     }
243 #else
244   clib_warning ("unimplemented");
245 #endif
246 }
247
248 static int
249 ipsec_spd_action_decode (vl_api_ipsec_spd_action_t in,
250                          ipsec_policy_action_t * out)
251 {
252   in = clib_net_to_host_u32 (in);
253
254   switch (in)
255     {
256 #define _(v,f,s) case IPSEC_API_SPD_ACTION_##f: \
257       *out = IPSEC_POLICY_ACTION_##f;              \
258       return (0);
259       foreach_ipsec_policy_action
260 #undef _
261     }
262   return (VNET_API_ERROR_UNIMPLEMENTED);
263 }
264
265 static void vl_api_ipsec_spd_entry_add_del_t_handler
266   (vl_api_ipsec_spd_entry_add_del_t * mp)
267 {
268   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
269   vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
270   ip46_type_t itype;
271   u32 stat_index;
272   int rv;
273
274   stat_index = ~0;
275
276 #if WITH_LIBSSL > 0
277   ipsec_policy_t p;
278
279   clib_memset (&p, 0, sizeof (p));
280
281   p.id = ntohl (mp->entry.spd_id);
282   p.priority = ntohl (mp->entry.priority);
283
284   itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
285   ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
286   ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
287   ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
288
289   p.is_ipv6 = (itype == IP46_TYPE_IP6);
290
291   p.protocol = mp->entry.protocol;
292   p.rport.start = ntohs (mp->entry.remote_port_start);
293   p.rport.stop = ntohs (mp->entry.remote_port_stop);
294   p.lport.start = ntohs (mp->entry.local_port_start);
295   p.lport.stop = ntohs (mp->entry.local_port_stop);
296
297   rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
298
299   if (rv)
300     goto out;
301
302   /* policy action resolve unsupported */
303   if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
304     {
305       clib_warning ("unsupported action: 'resolve'");
306       rv = VNET_API_ERROR_UNIMPLEMENTED;
307       goto out;
308     }
309   p.sa_id = ntohl (mp->entry.sa_id);
310   rv =
311     ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy,
312                           &p.type);
313   if (rv)
314     goto out;
315
316   rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
317   if (rv)
318     goto out;
319
320 #else
321   rv = VNET_API_ERROR_UNIMPLEMENTED;
322   goto out;
323 #endif
324
325 out:
326   /* *INDENT-OFF* */
327   REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_REPLY,
328   ({
329     rmp->stat_index = ntohl(stat_index);
330   }));
331   /* *INDENT-ON* */
332 }
333
334 static void vl_api_ipsec_sad_entry_add_del_t_handler
335   (vl_api_ipsec_sad_entry_add_del_t * mp)
336 {
337   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
338   vl_api_ipsec_sad_entry_add_del_reply_t *rmp;
339   ip46_address_t tun_src = { }, tun_dst =
340   {
341   };
342   ipsec_key_t crypto_key, integ_key;
343   ipsec_crypto_alg_t crypto_alg;
344   ipsec_integ_alg_t integ_alg;
345   ipsec_protocol_t proto;
346   ipsec_sa_flags_t flags;
347   u32 id, spi, sa_index = ~0;
348   int rv;
349
350 #if WITH_LIBSSL > 0
351
352   id = ntohl (mp->entry.sad_id);
353   spi = ntohl (mp->entry.spi);
354
355   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
356
357   if (rv)
358     goto out;
359
360   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
361
362   if (rv)
363     goto out;
364
365   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
366
367   if (rv)
368     goto out;
369
370   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
371   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
372
373   flags = ipsec_sa_flags_decode (mp->entry.flags);
374
375   ip_address_decode (&mp->entry.tunnel_src, &tun_src);
376   ip_address_decode (&mp->entry.tunnel_dst, &tun_dst);
377
378   if (mp->is_add)
379     rv = ipsec_sa_add_and_lock (id, spi, proto,
380                                 crypto_alg, &crypto_key,
381                                 integ_alg, &integ_key, flags,
382                                 0, mp->entry.salt, &tun_src, &tun_dst,
383                                 &sa_index, htons (mp->entry.udp_src_port),
384                                 htons (mp->entry.udp_dst_port));
385   else
386     rv = ipsec_sa_unlock_id (id);
387
388 #else
389   rv = VNET_API_ERROR_UNIMPLEMENTED;
390 #endif
391
392 out:
393   /* *INDENT-OFF* */
394   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY,
395   {
396     rmp->stat_index = htonl (sa_index);
397   });
398   /* *INDENT-ON* */
399 }
400
401 static void
402 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
403                          u32 context)
404 {
405   vl_api_ipsec_spds_details_t *mp;
406   u32 n_policies = 0;
407
408   mp = vl_msg_api_alloc (sizeof (*mp));
409   clib_memset (mp, 0, sizeof (*mp));
410   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPDS_DETAILS);
411   mp->context = context;
412
413   mp->spd_id = htonl (spd->id);
414 #define _(s, n) n_policies += vec_len (spd->policies[IPSEC_SPD_POLICY_##s]);
415   foreach_ipsec_spd_policy_type
416 #undef _
417     mp->npolicies = htonl (n_policies);
418
419   vl_api_send_msg (reg, (u8 *) mp);
420 }
421
422 static void
423 vl_api_ipsec_spds_dump_t_handler (vl_api_ipsec_spds_dump_t * mp)
424 {
425   vl_api_registration_t *reg;
426   ipsec_main_t *im = &ipsec_main;
427   ipsec_spd_t *spd;
428 #if WITH_LIBSSL > 0
429   reg = vl_api_client_index_to_registration (mp->client_index);
430   if (!reg)
431     return;
432
433   /* *INDENT-OFF* */
434   pool_foreach (spd, im->spds, ({
435     send_ipsec_spds_details (spd, reg, mp->context);
436   }));
437   /* *INDENT-ON* */
438 #else
439   clib_warning ("unimplemented");
440 #endif
441 }
442
443 vl_api_ipsec_spd_action_t
444 ipsec_spd_action_encode (ipsec_policy_action_t in)
445 {
446   vl_api_ipsec_spd_action_t out = IPSEC_API_SPD_ACTION_BYPASS;
447
448   switch (in)
449     {
450 #define _(v,f,s) case IPSEC_POLICY_ACTION_##f: \
451       out = IPSEC_API_SPD_ACTION_##f;          \
452       break;
453       foreach_ipsec_policy_action
454 #undef _
455     }
456   return (clib_host_to_net_u32 (out));
457 }
458
459 static void
460 send_ipsec_spd_details (ipsec_policy_t * p, vl_api_registration_t * reg,
461                         u32 context)
462 {
463   vl_api_ipsec_spd_details_t *mp;
464
465   mp = vl_msg_api_alloc (sizeof (*mp));
466   clib_memset (mp, 0, sizeof (*mp));
467   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_DETAILS);
468   mp->context = context;
469
470   mp->entry.spd_id = htonl (p->id);
471   mp->entry.priority = htonl (p->priority);
472   mp->entry.is_outbound = ((p->type == IPSEC_SPD_POLICY_IP6_OUTBOUND) ||
473                            (p->type == IPSEC_SPD_POLICY_IP4_OUTBOUND));
474
475   ip_address_encode (&p->laddr.start, IP46_TYPE_ANY,
476                      &mp->entry.local_address_start);
477   ip_address_encode (&p->laddr.stop, IP46_TYPE_ANY,
478                      &mp->entry.local_address_stop);
479   ip_address_encode (&p->raddr.start, IP46_TYPE_ANY,
480                      &mp->entry.remote_address_start);
481   ip_address_encode (&p->raddr.stop, IP46_TYPE_ANY,
482                      &mp->entry.remote_address_stop);
483   mp->entry.local_port_start = htons (p->lport.start);
484   mp->entry.local_port_stop = htons (p->lport.stop);
485   mp->entry.remote_port_start = htons (p->rport.start);
486   mp->entry.remote_port_stop = htons (p->rport.stop);
487   mp->entry.protocol = p->protocol;
488   mp->entry.policy = ipsec_spd_action_encode (p->policy);
489   mp->entry.sa_id = htonl (p->sa_id);
490
491   vl_api_send_msg (reg, (u8 *) mp);
492 }
493
494 static void
495 vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp)
496 {
497   vl_api_registration_t *reg;
498   ipsec_main_t *im = &ipsec_main;
499   ipsec_spd_policy_type_t ptype;
500   ipsec_policy_t *policy;
501   ipsec_spd_t *spd;
502   uword *p;
503   u32 spd_index, *ii;
504 #if WITH_LIBSSL > 0
505   reg = vl_api_client_index_to_registration (mp->client_index);
506   if (!reg)
507     return;
508
509   p = hash_get (im->spd_index_by_spd_id, ntohl (mp->spd_id));
510   if (!p)
511     return;
512
513   spd_index = p[0];
514   spd = pool_elt_at_index (im->spds, spd_index);
515
516   /* *INDENT-OFF* */
517   FOR_EACH_IPSEC_SPD_POLICY_TYPE(ptype) {
518     vec_foreach(ii, spd->policies[ptype])
519       {
520         policy = pool_elt_at_index(im->policies, *ii);
521
522         if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == policy->sa_id)
523           send_ipsec_spd_details (policy, reg, mp->context);
524       }
525   }
526   /* *INDENT-ON* */
527 #else
528   clib_warning ("unimplemented");
529 #endif
530 }
531
532 static void
533 send_ipsec_spd_interface_details (vl_api_registration_t * reg, u32 spd_index,
534                                   u32 sw_if_index, u32 context)
535 {
536   vl_api_ipsec_spd_interface_details_t *mp;
537
538   mp = vl_msg_api_alloc (sizeof (*mp));
539   clib_memset (mp, 0, sizeof (*mp));
540   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_INTERFACE_DETAILS);
541   mp->context = context;
542
543   mp->spd_index = htonl (spd_index);
544   mp->sw_if_index = htonl (sw_if_index);
545
546   vl_api_send_msg (reg, (u8 *) mp);
547 }
548
549 static void
550 vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t *
551                                            mp)
552 {
553   ipsec_main_t *im = &ipsec_main;
554   vl_api_registration_t *reg;
555   u32 k, v, spd_index;
556
557 #if WITH_LIBSSL > 0
558   reg = vl_api_client_index_to_registration (mp->client_index);
559   if (!reg)
560     return;
561
562   if (mp->spd_index_valid)
563     {
564       spd_index = ntohl (mp->spd_index);
565       /* *INDENT-OFF* */
566       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
567         if (v == spd_index)
568           send_ipsec_spd_interface_details(reg, v, k, mp->context);
569       }));
570       /* *INDENT-ON* */
571     }
572   else
573     {
574       /* *INDENT-OFF* */
575       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
576         send_ipsec_spd_interface_details(reg, v, k, mp->context);
577       }));
578       /* *INDENT-ON* */
579     }
580
581 #else
582   clib_warning ("unimplemented");
583 #endif
584 }
585
586 static u32
587 ipsec_tun_mk_input_sa_id (u32 ti)
588 {
589   return (0x80000000 | ti);
590 }
591
592 static u32
593 ipsec_tun_mk_output_sa_id (u32 ti)
594 {
595   return (0xc0000000 | ti);
596 }
597
598 static void
599 vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
600                                           mp)
601 {
602   vl_api_ipsec_tunnel_if_add_del_reply_t *rmp;
603   u32 sw_if_index = ~0;
604   int rv;
605
606 #if WITH_LIBSSL > 0
607   ip46_address_t local_ip = ip46_address_initializer;
608   ip46_address_t remote_ip = ip46_address_initializer;
609   ipsec_key_t crypto_key, integ_key;
610   ipsec_sa_flags_t flags;
611   ip46_type_t local_ip_type, remote_ip_type;
612   ipip_transport_t transport;
613   u32 fib_index;
614
615   local_ip_type = ip_address_decode (&mp->local_ip, &local_ip);
616   remote_ip_type = ip_address_decode (&mp->remote_ip, &remote_ip);
617   transport = (IP46_TYPE_IP6 == local_ip_type ?
618                IPIP_TRANSPORT_IP6 : IPIP_TRANSPORT_IP4);
619
620   if (local_ip_type != remote_ip_type)
621     {
622       rv = VNET_API_ERROR_INVALID_VALUE;
623       goto done;
624     }
625
626   flags = IPSEC_SA_FLAG_NONE;
627
628   if (mp->udp_encap)
629     flags |= IPSEC_SA_FLAG_UDP_ENCAP;
630   if (mp->esn)
631     flags |= IPSEC_SA_FLAG_USE_ESN;
632   if (mp->anti_replay)
633     flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
634
635   ipsec_mk_key (&crypto_key, mp->remote_crypto_key,
636                 mp->remote_crypto_key_len);
637   ipsec_mk_key (&integ_key, mp->remote_integ_key, mp->remote_integ_key_len);
638   ipsec_mk_key (&crypto_key, mp->local_crypto_key, mp->local_crypto_key_len);
639   ipsec_mk_key (&integ_key, mp->local_integ_key, mp->local_integ_key_len);
640
641   fib_index =
642     fib_table_find (fib_proto_from_ip46 (local_ip_type),
643                     ntohl (mp->tx_table_id));
644
645   if (~0 == fib_index)
646     {
647       rv = VNET_API_ERROR_NO_SUCH_FIB;
648       goto done;
649     }
650
651   if (mp->is_add)
652     {
653       // remote = input, local = output
654       /* create an ip-ip tunnel, then the two SA, then bind them */
655       rv = ipip_add_tunnel (transport,
656                             (mp->renumber ? ntohl (mp->show_instance) : ~0),
657                             &local_ip,
658                             &remote_ip, fib_index,
659                             TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0,
660                             TUNNEL_MODE_P2P, &sw_if_index);
661
662       if (rv)
663         goto done;
664
665       rv = ipsec_sa_add_and_lock (ipsec_tun_mk_input_sa_id (sw_if_index),
666                                   ntohl (mp->remote_spi),
667                                   IPSEC_PROTOCOL_ESP,
668                                   mp->crypto_alg,
669                                   &crypto_key,
670                                   mp->integ_alg,
671                                   &integ_key,
672                                   (flags | IPSEC_SA_FLAG_IS_INBOUND),
673                                   ntohl (mp->tx_table_id),
674                                   mp->salt, &remote_ip, &local_ip, NULL,
675                                   IPSEC_UDP_PORT_NONE, IPSEC_UDP_PORT_NONE);
676
677       if (rv)
678         goto done;
679
680       rv = ipsec_sa_add_and_lock (ipsec_tun_mk_output_sa_id (sw_if_index),
681                                   ntohl (mp->local_spi),
682                                   IPSEC_PROTOCOL_ESP,
683                                   mp->crypto_alg,
684                                   &crypto_key,
685                                   mp->integ_alg,
686                                   &integ_key,
687                                   flags,
688                                   ntohl (mp->tx_table_id),
689                                   mp->salt, &local_ip, &remote_ip, NULL,
690                                   IPSEC_UDP_PORT_NONE, IPSEC_UDP_PORT_NONE);
691
692       if (rv)
693         goto done;
694
695       rv = ipsec_tun_protect_update_one (sw_if_index, NULL,
696                                          ipsec_tun_mk_output_sa_id
697                                          (sw_if_index),
698                                          ipsec_tun_mk_input_sa_id
699                                          (sw_if_index));
700       if (rv)
701         goto done;
702
703       /* the SAs are locked as a result of being used for proection,
704        * they cannot be removed from the API, since they cannot be refered
705        * to by the API. unlock them now, so that if the tunnel is rekeyed
706        * they-ll disapper
707        */
708       ipsec_sa_unlock_id (ipsec_tun_mk_input_sa_id (sw_if_index));
709       ipsec_sa_unlock_id (ipsec_tun_mk_output_sa_id (sw_if_index));
710     }
711   else
712     {
713       /* *INDENT-OFF* */
714       ipip_tunnel_key_t key = {
715         .transport = transport,
716         .fib_index = fib_index,
717         .src = local_ip,
718         .dst = remote_ip
719       };
720       /* *INDENT-ON* */
721
722       ipip_tunnel_t *t = ipip_tunnel_db_find (&key);
723
724       if (NULL != t)
725         {
726           rv = ipsec_tun_protect_del (t->sw_if_index, NULL);
727           ipip_del_tunnel (t->sw_if_index);
728         }
729       else
730         rv = VNET_API_ERROR_NO_SUCH_ENTRY;
731     }
732
733 #else
734   rv = VNET_API_ERROR_UNIMPLEMENTED;
735 #endif
736 done:
737   /* *INDENT-OFF* */
738   REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY,
739   ({
740     rmp->sw_if_index = htonl (sw_if_index);
741   }));
742   /* *INDENT-ON* */
743 }
744
745 static void
746 vl_api_ipsec_itf_create_t_handler (vl_api_ipsec_itf_create_t * mp)
747 {
748   vl_api_ipsec_itf_create_reply_t *rmp;
749   tunnel_mode_t mode;
750   u32 sw_if_index = ~0;
751   int rv;
752
753   rv = tunnel_mode_decode (mp->itf.mode, &mode);
754
755   if (!rv)
756     rv = ipsec_itf_create (ntohl (mp->itf.user_instance), mode, &sw_if_index);
757
758   /* *INDENT-OFF* */
759   REPLY_MACRO2 (VL_API_IPSEC_ITF_CREATE_REPLY,
760   ({
761     rmp->sw_if_index = htonl (sw_if_index);
762   }));
763   /* *INDENT-ON* */
764 }
765
766 static void
767 vl_api_ipsec_itf_delete_t_handler (vl_api_ipsec_itf_delete_t * mp)
768 {
769   vl_api_ipsec_itf_delete_reply_t *rmp;
770   int rv;
771
772   rv = ipsec_itf_delete (ntohl (mp->sw_if_index));
773
774   REPLY_MACRO (VL_API_IPSEC_ITF_DELETE_REPLY);
775 }
776
777 static void
778 vl_api_ipsec_itf_dump_t_handler (vl_api_ipsec_itf_dump_t * mp)
779 {
780 }
781
782 typedef struct ipsec_sa_dump_match_ctx_t_
783 {
784   index_t sai;
785   u32 sw_if_index;
786 } ipsec_sa_dump_match_ctx_t;
787
788 static walk_rc_t
789 ipsec_sa_dump_match_sa (index_t itpi, void *arg)
790 {
791   ipsec_sa_dump_match_ctx_t *ctx = arg;
792   ipsec_tun_protect_t *itp;
793   index_t sai;
794
795   itp = ipsec_tun_protect_get (itpi);
796
797   if (itp->itp_out_sa == ctx->sai)
798     {
799       ctx->sw_if_index = itp->itp_sw_if_index;
800       return (WALK_STOP);
801     }
802   /* *INDENT-OFF* */
803   FOR_EACH_IPSEC_PROTECT_INPUT_SAI (itp, sai,
804   ({
805     if (sai == ctx->sai)
806       {
807         ctx->sw_if_index = itp->itp_sw_if_index;
808         return (WALK_STOP);
809       }
810   }));
811   /* *INDENT-OFF* */
812
813   return (WALK_CONTINUE);
814 }
815
816 static walk_rc_t
817 send_ipsec_sa_details (ipsec_sa_t * sa, void *arg)
818 {
819   ipsec_dump_walk_ctx_t *ctx = arg;
820   vl_api_ipsec_sa_details_t *mp;
821   ipsec_main_t *im = &ipsec_main;
822
823   mp = vl_msg_api_alloc (sizeof (*mp));
824   clib_memset (mp, 0, sizeof (*mp));
825   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS);
826   mp->context = ctx->context;
827
828   mp->entry.sad_id = htonl (sa->id);
829   mp->entry.spi = htonl (sa->spi);
830   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
831   mp->entry.tx_table_id =
832     htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4));
833
834   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
835   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
836
837   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
838   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
839
840   mp->entry.flags = ipsec_sad_flags_encode (sa);
841   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
842
843   if (ipsec_sa_is_set_IS_PROTECT (sa))
844     {
845       ipsec_sa_dump_match_ctx_t ctx = {
846         .sai = sa - im->sad,
847         .sw_if_index = ~0,
848       };
849       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
850
851       mp->sw_if_index = htonl (ctx.sw_if_index);
852     }
853   else
854     mp->sw_if_index = ~0;
855
856   if (ipsec_sa_is_set_IS_TUNNEL (sa))
857     {
858       ip_address_encode (&sa->tunnel_src_addr, IP46_TYPE_ANY,
859                          &mp->entry.tunnel_src);
860       ip_address_encode (&sa->tunnel_dst_addr, IP46_TYPE_ANY,
861                          &mp->entry.tunnel_dst);
862     }
863   if (ipsec_sa_is_set_UDP_ENCAP (sa))
864     {
865       mp->entry.udp_src_port = sa->udp_hdr.src_port;
866       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
867     }
868
869   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
870   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
871   if (ipsec_sa_is_set_USE_ESN (sa))
872     {
873       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
874       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
875     }
876   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
877     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
878
879   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
880
881   vl_api_send_msg (ctx->reg, (u8 *) mp);
882
883   return (WALK_CONTINUE);
884 }
885
886 static void
887 vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp)
888 {
889   vl_api_registration_t *reg;
890
891 #if WITH_LIBSSL > 0
892   reg = vl_api_client_index_to_registration (mp->client_index);
893   if (!reg)
894     return;
895
896   ipsec_dump_walk_ctx_t ctx = {
897     .reg = reg,
898     .context = mp->context,
899   };
900
901   ipsec_sa_walk (send_ipsec_sa_details, &ctx);
902
903 #else
904   clib_warning ("unimplemented");
905 #endif
906 }
907
908 static void
909 vl_api_ipsec_tunnel_if_set_sa_t_handler (vl_api_ipsec_tunnel_if_set_sa_t * mp)
910 {
911   vl_api_ipsec_tunnel_if_set_sa_reply_t *rmp;
912   int rv;
913
914 #if WITH_LIBSSL > 0
915   VALIDATE_SW_IF_INDEX(mp);
916
917   if (mp->is_outbound)
918     rv = ipsec_tun_protect_update_out (ntohl (mp->sw_if_index), NULL,
919                                        ntohl (mp->sa_id));
920   else
921     rv = ipsec_tun_protect_update_in (ntohl (mp->sw_if_index), NULL,
922                                        ntohl (mp->sa_id));
923
924 #else
925   clib_warning ("unimplemented");
926 #endif
927
928   BAD_SW_IF_INDEX_LABEL;
929
930   REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY);
931 }
932
933 static void
934 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
935 {
936   vl_api_registration_t *rp;
937   ipsec_main_t *im = &ipsec_main;
938   u32 context = mp->context;
939
940   rp = vl_api_client_index_to_registration (mp->client_index);
941
942   if (rp == 0)
943     {
944       clib_warning ("Client %d AWOL", mp->client_index);
945       return;
946     }
947
948   ipsec_ah_backend_t *ab;
949   ipsec_esp_backend_t *eb;
950   /* *INDENT-OFF* */
951   pool_foreach (ab, im->ah_backends, {
952     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
953     clib_memset (mp, 0, sizeof (*mp));
954     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
955     mp->context = context;
956     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
957               ab->name);
958     mp->protocol = ntohl (IPSEC_API_PROTO_AH);
959     mp->index = ab - im->ah_backends;
960     mp->active = mp->index == im->ah_current_backend ? 1 : 0;
961     vl_api_send_msg (rp, (u8 *)mp);
962   });
963   pool_foreach (eb, im->esp_backends, {
964     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
965     clib_memset (mp, 0, sizeof (*mp));
966     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
967     mp->context = context;
968     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
969               eb->name);
970     mp->protocol = ntohl (IPSEC_API_PROTO_ESP);
971     mp->index = eb - im->esp_backends;
972     mp->active = mp->index == im->esp_current_backend ? 1 : 0;
973     vl_api_send_msg (rp, (u8 *)mp);
974   });
975   /* *INDENT-ON* */
976 }
977
978 static void
979 vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
980 {
981   ipsec_main_t *im = &ipsec_main;
982   vl_api_ipsec_select_backend_reply_t *rmp;
983   ipsec_protocol_t protocol;
984   int rv = 0;
985   if (pool_elts (im->sad) > 0)
986     {
987       rv = VNET_API_ERROR_INSTANCE_IN_USE;
988       goto done;
989     }
990
991   rv = ipsec_proto_decode (mp->protocol, &protocol);
992
993   if (rv)
994     goto done;
995
996 #if WITH_LIBSSL > 0
997   switch (protocol)
998     {
999     case IPSEC_PROTOCOL_ESP:
1000       rv = ipsec_select_esp_backend (im, mp->index);
1001       break;
1002     case IPSEC_PROTOCOL_AH:
1003       rv = ipsec_select_ah_backend (im, mp->index);
1004       break;
1005     default:
1006       rv = VNET_API_ERROR_INVALID_PROTOCOL;
1007       break;
1008     }
1009 #else
1010   clib_warning ("unimplemented");       /* FIXME */
1011 #endif
1012 done:
1013   REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
1014 }
1015
1016 static void
1017 vl_api_ipsec_set_async_mode_t_handler (vl_api_ipsec_set_async_mode_t * mp)
1018 {
1019   vl_api_ipsec_set_async_mode_reply_t *rmp;
1020   int rv = 0;
1021
1022   vnet_crypto_request_async_mode (mp->async_enable);
1023   ipsec_set_async_mode (mp->async_enable);
1024
1025   REPLY_MACRO (VL_API_IPSEC_SET_ASYNC_MODE_REPLY);
1026 }
1027
1028 /*
1029  * ipsec_api_hookup
1030  * Add vpe's API message handlers to the table.
1031  * vlib has already mapped shared memory and
1032  * added the client registration handlers.
1033  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
1034  */
1035 #define vl_msg_name_crc_list
1036 #include <vnet/vnet_all_api_h.h>
1037 #undef vl_msg_name_crc_list
1038
1039 static void
1040 setup_message_id_table (api_main_t * am)
1041 {
1042 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1043   foreach_vl_msg_name_crc_ipsec;
1044 #undef _
1045 }
1046
1047 static clib_error_t *
1048 ipsec_api_hookup (vlib_main_t * vm)
1049 {
1050   api_main_t *am = vlibapi_get_main ();
1051
1052 #define _(N,n)                                                  \
1053     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1054                            vl_api_##n##_t_handler,              \
1055                            vl_noop_handler,                     \
1056                            vl_api_##n##_t_endian,               \
1057                            vl_api_##n##_t_print,                \
1058                            sizeof(vl_api_##n##_t), 1);
1059   foreach_vpe_api_msg;
1060 #undef _
1061
1062   /*
1063    * Set up the (msg_name, crc, message-id) table
1064    */
1065   setup_message_id_table (am);
1066
1067   return 0;
1068 }
1069
1070 VLIB_API_INIT_FUNCTION (ipsec_api_hookup);
1071
1072 /*
1073  * fd.io coding-style-patch-verification: ON
1074  *
1075  * Local Variables:
1076  * eval: (c-set-style "gnu")
1077  * End:
1078  */