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