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