ipsec: Support async mode per-SA
[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 #include <vnet/tunnel/tunnel_types_api.h>
32
33 #include <vnet/vnet_msg_enum.h>
34
35 #if WITH_LIBSSL > 0
36 #include <vnet/ipsec/ipsec.h>
37 #include <vnet/ipsec/ipsec_tun.h>
38 #include <vnet/ipsec/ipsec_itf.h>
39 #endif /* IPSEC */
40
41 #define vl_typedefs             /* define message structures */
42 #include <vnet/vnet_all_api_h.h>
43 #undef vl_typedefs
44
45 #define vl_endianfun            /* define message structures */
46 #include <vnet/vnet_all_api_h.h>
47 #undef vl_endianfun
48
49 /* instantiate all the print functions we know about */
50 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
51 #define vl_printfun
52 #include <vnet/vnet_all_api_h.h>
53 #undef vl_printfun
54
55 #include <vlibapi/api_helper_macros.h>
56
57 #define foreach_vpe_api_msg                                                   \
58   _ (IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                                    \
59   _ (IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)                \
60   _ (IPSEC_SPD_ENTRY_ADD_DEL, ipsec_spd_entry_add_del)                        \
61   _ (IPSEC_SAD_ENTRY_ADD_DEL, ipsec_sad_entry_add_del)                        \
62   _ (IPSEC_SAD_ENTRY_ADD_DEL_V2, ipsec_sad_entry_add_del_v2)                  \
63   _ (IPSEC_SAD_ENTRY_ADD_DEL_V3, ipsec_sad_entry_add_del_v3)                  \
64   _ (IPSEC_SA_DUMP, ipsec_sa_dump)                                            \
65   _ (IPSEC_SA_V2_DUMP, ipsec_sa_v2_dump)                                      \
66   _ (IPSEC_SA_V3_DUMP, ipsec_sa_v3_dump)                                      \
67   _ (IPSEC_SPDS_DUMP, ipsec_spds_dump)                                        \
68   _ (IPSEC_SPD_DUMP, ipsec_spd_dump)                                          \
69   _ (IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump)                      \
70   _ (IPSEC_ITF_CREATE, ipsec_itf_create)                                      \
71   _ (IPSEC_ITF_DELETE, ipsec_itf_delete)                                      \
72   _ (IPSEC_ITF_DUMP, ipsec_itf_dump)                                          \
73   _ (IPSEC_SELECT_BACKEND, ipsec_select_backend)                              \
74   _ (IPSEC_BACKEND_DUMP, ipsec_backend_dump)                                  \
75   _ (IPSEC_TUNNEL_PROTECT_UPDATE, ipsec_tunnel_protect_update)                \
76   _ (IPSEC_TUNNEL_PROTECT_DEL, ipsec_tunnel_protect_del)                      \
77   _ (IPSEC_TUNNEL_PROTECT_DUMP, ipsec_tunnel_protect_dump)                    \
78   _ (IPSEC_SET_ASYNC_MODE, ipsec_set_async_mode)
79
80 static void
81 vl_api_ipsec_spd_add_del_t_handler (vl_api_ipsec_spd_add_del_t * mp)
82 {
83 #if WITH_LIBSSL == 0
84   clib_warning ("unimplemented");
85 #else
86
87   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
88   vl_api_ipsec_spd_add_del_reply_t *rmp;
89   int rv;
90
91   rv = ipsec_add_del_spd (vm, ntohl (mp->spd_id), mp->is_add);
92
93   REPLY_MACRO (VL_API_IPSEC_SPD_ADD_DEL_REPLY);
94 #endif
95 }
96
97 static void vl_api_ipsec_interface_add_del_spd_t_handler
98   (vl_api_ipsec_interface_add_del_spd_t * mp)
99 {
100   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
101   vl_api_ipsec_interface_add_del_spd_reply_t *rmp;
102   int rv;
103   u32 sw_if_index __attribute__ ((unused));
104   u32 spd_id __attribute__ ((unused));
105
106   sw_if_index = ntohl (mp->sw_if_index);
107   spd_id = ntohl (mp->spd_id);
108
109   VALIDATE_SW_IF_INDEX (mp);
110
111 #if WITH_LIBSSL > 0
112   rv = ipsec_set_interface_spd (vm, sw_if_index, spd_id, mp->is_add);
113 #else
114   rv = VNET_API_ERROR_UNIMPLEMENTED;
115 #endif
116
117   BAD_SW_IF_INDEX_LABEL;
118
119   REPLY_MACRO (VL_API_IPSEC_INTERFACE_ADD_DEL_SPD_REPLY);
120 }
121
122 static void vl_api_ipsec_tunnel_protect_update_t_handler
123   (vl_api_ipsec_tunnel_protect_update_t * mp)
124 {
125   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
126   vl_api_ipsec_tunnel_protect_update_reply_t *rmp;
127   u32 sw_if_index, ii, *sa_ins = NULL;
128   ip_address_t nh;
129   int rv;
130
131   sw_if_index = ntohl (mp->tunnel.sw_if_index);
132
133   VALIDATE_SW_IF_INDEX (&(mp->tunnel));
134
135 #if WITH_LIBSSL > 0
136
137   for (ii = 0; ii < mp->tunnel.n_sa_in; ii++)
138     vec_add1 (sa_ins, ntohl (mp->tunnel.sa_in[ii]));
139
140   ip_address_decode2 (&mp->tunnel.nh, &nh);
141
142   rv = ipsec_tun_protect_update (sw_if_index, &nh,
143                                  ntohl (mp->tunnel.sa_out), sa_ins);
144 #else
145   rv = VNET_API_ERROR_UNIMPLEMENTED;
146 #endif
147
148   BAD_SW_IF_INDEX_LABEL;
149
150   REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_UPDATE_REPLY);
151 }
152
153 static void vl_api_ipsec_tunnel_protect_del_t_handler
154   (vl_api_ipsec_tunnel_protect_del_t * mp)
155 {
156   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
157   vl_api_ipsec_tunnel_protect_del_reply_t *rmp;
158   ip_address_t nh;
159   u32 sw_if_index;
160   int rv;
161
162   sw_if_index = ntohl (mp->sw_if_index);
163
164   VALIDATE_SW_IF_INDEX (mp);
165
166 #if WITH_LIBSSL > 0
167   ip_address_decode2 (&mp->nh, &nh);
168   rv = ipsec_tun_protect_del (sw_if_index, &nh);
169 #else
170   rv = VNET_API_ERROR_UNIMPLEMENTED;
171 #endif
172
173   BAD_SW_IF_INDEX_LABEL;
174
175   REPLY_MACRO (VL_API_IPSEC_TUNNEL_PROTECT_DEL_REPLY);
176 }
177
178 typedef struct ipsec_dump_walk_ctx_t_
179 {
180   vl_api_registration_t *reg;
181   u32 context;
182 } ipsec_dump_walk_ctx_t;
183
184 static walk_rc_t
185 send_ipsec_tunnel_protect_details (index_t itpi, void *arg)
186 {
187   ipsec_dump_walk_ctx_t *ctx = arg;
188   vl_api_ipsec_tunnel_protect_details_t *mp;
189   ipsec_tun_protect_t *itp;
190   u32 ii = 0;
191   ipsec_sa_t *sa;
192
193   itp = ipsec_tun_protect_get (itpi);
194
195   mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (u32) * itp->itp_n_sa_in));
196   clib_memset (mp, 0, sizeof (*mp));
197   mp->_vl_msg_id = ntohs (VL_API_IPSEC_TUNNEL_PROTECT_DETAILS);
198   mp->context = ctx->context;
199
200   mp->tun.sw_if_index = htonl (itp->itp_sw_if_index);
201   ip_address_encode2 (itp->itp_key, &mp->tun.nh);
202
203   sa = ipsec_sa_get (itp->itp_out_sa);
204   mp->tun.sa_out = htonl (sa->id);
205   mp->tun.n_sa_in = itp->itp_n_sa_in;
206   /* *INDENT-OFF* */
207   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
208   ({
209     mp->tun.sa_in[ii++] = htonl (sa->id);
210   }));
211   /* *INDENT-ON* */
212
213   vl_api_send_msg (ctx->reg, (u8 *) mp);
214
215   return (WALK_CONTINUE);
216 }
217
218 static void
219 vl_api_ipsec_tunnel_protect_dump_t_handler (vl_api_ipsec_tunnel_protect_dump_t
220                                             * mp)
221 {
222   vl_api_registration_t *reg;
223   u32 sw_if_index;
224
225 #if WITH_LIBSSL > 0
226   reg = vl_api_client_index_to_registration (mp->client_index);
227   if (!reg)
228     return;
229
230   ipsec_dump_walk_ctx_t ctx = {
231     .reg = reg,
232     .context = mp->context,
233   };
234
235   sw_if_index = ntohl (mp->sw_if_index);
236
237   if (~0 == sw_if_index)
238     {
239       ipsec_tun_protect_walk (send_ipsec_tunnel_protect_details, &ctx);
240     }
241   else
242     {
243       ipsec_tun_protect_walk_itf (sw_if_index,
244                                   send_ipsec_tunnel_protect_details, &ctx);
245     }
246 #else
247   clib_warning ("unimplemented");
248 #endif
249 }
250
251 static int
252 ipsec_spd_action_decode (vl_api_ipsec_spd_action_t in,
253                          ipsec_policy_action_t * out)
254 {
255   in = clib_net_to_host_u32 (in);
256
257   switch (in)
258     {
259 #define _(v,f,s) case IPSEC_API_SPD_ACTION_##f: \
260       *out = IPSEC_POLICY_ACTION_##f;              \
261       return (0);
262       foreach_ipsec_policy_action
263 #undef _
264     }
265   return (VNET_API_ERROR_UNIMPLEMENTED);
266 }
267
268 static void vl_api_ipsec_spd_entry_add_del_t_handler
269   (vl_api_ipsec_spd_entry_add_del_t * mp)
270 {
271   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
272   vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
273   ip46_type_t itype;
274   u32 stat_index;
275   int rv;
276
277   stat_index = ~0;
278
279 #if WITH_LIBSSL > 0
280   ipsec_policy_t p;
281
282   clib_memset (&p, 0, sizeof (p));
283
284   p.id = ntohl (mp->entry.spd_id);
285   p.priority = ntohl (mp->entry.priority);
286
287   itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
288   ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
289   ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
290   ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
291
292   p.is_ipv6 = (itype == IP46_TYPE_IP6);
293
294   p.protocol = mp->entry.protocol;
295   p.rport.start = ntohs (mp->entry.remote_port_start);
296   p.rport.stop = ntohs (mp->entry.remote_port_stop);
297   p.lport.start = ntohs (mp->entry.local_port_start);
298   p.lport.stop = ntohs (mp->entry.local_port_stop);
299
300   rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
301
302   if (rv)
303     goto out;
304
305   /* policy action resolve unsupported */
306   if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
307     {
308       clib_warning ("unsupported action: 'resolve'");
309       rv = VNET_API_ERROR_UNIMPLEMENTED;
310       goto out;
311     }
312   p.sa_id = ntohl (mp->entry.sa_id);
313   rv =
314     ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy,
315                           &p.type);
316   if (rv)
317     goto out;
318
319   rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
320   if (rv)
321     goto out;
322
323 #else
324   rv = VNET_API_ERROR_UNIMPLEMENTED;
325   goto out;
326 #endif
327
328 out:
329   /* *INDENT-OFF* */
330   REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_REPLY,
331   ({
332     rmp->stat_index = ntohl(stat_index);
333   }));
334   /* *INDENT-ON* */
335 }
336
337 static void vl_api_ipsec_sad_entry_add_del_t_handler
338   (vl_api_ipsec_sad_entry_add_del_t * mp)
339 {
340   vl_api_ipsec_sad_entry_add_del_reply_t *rmp;
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   tunnel_t tun = {
348     .t_flags = TUNNEL_FLAG_NONE,
349     .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE,
350     .t_dscp = 0,
351     .t_mode = TUNNEL_MODE_P2P,
352     .t_table_id = 0,
353     .t_hop_limit = 255,
354   };
355   int rv;
356
357 #if WITH_LIBSSL > 0
358
359   id = ntohl (mp->entry.sad_id);
360   spi = ntohl (mp->entry.spi);
361
362   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
363
364   if (rv)
365     goto out;
366
367   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
368
369   if (rv)
370     goto out;
371
372   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
373
374   if (rv)
375     goto out;
376
377   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
378   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
379
380   flags = ipsec_sa_flags_decode (mp->entry.flags);
381
382   ip_address_decode2 (&mp->entry.tunnel_src, &tun.t_src);
383   ip_address_decode2 (&mp->entry.tunnel_dst, &tun.t_dst);
384
385   if (mp->is_add)
386     rv = ipsec_sa_add_and_lock (
387       id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
388       mp->entry.salt, htons (mp->entry.udp_src_port),
389       htons (mp->entry.udp_dst_port), &tun, &sa_index);
390   else
391     rv = ipsec_sa_unlock_id (id);
392
393 #else
394   rv = VNET_API_ERROR_UNIMPLEMENTED;
395 #endif
396
397 out:
398   /* *INDENT-OFF* */
399   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY,
400   {
401     rmp->stat_index = htonl (sa_index);
402   });
403   /* *INDENT-ON* */
404 }
405
406 static void vl_api_ipsec_sad_entry_add_del_v2_t_handler
407   (vl_api_ipsec_sad_entry_add_del_v2_t * mp)
408 {
409   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
410   vl_api_ipsec_sad_entry_add_del_v2_reply_t *rmp;
411   ipsec_key_t crypto_key, integ_key;
412   ipsec_crypto_alg_t crypto_alg;
413   ipsec_integ_alg_t integ_alg;
414   ipsec_protocol_t proto;
415   ipsec_sa_flags_t flags;
416   u32 id, spi, sa_index = ~0;
417   int rv;
418   tunnel_t tun = {
419     .t_flags = TUNNEL_FLAG_NONE,
420     .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE,
421     .t_dscp = 0,
422     .t_mode = TUNNEL_MODE_P2P,
423     .t_table_id = htonl (mp->entry.tx_table_id),
424     .t_hop_limit = 255,
425   };
426
427 #if WITH_LIBSSL > 0
428
429   id = ntohl (mp->entry.sad_id);
430   spi = ntohl (mp->entry.spi);
431
432   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
433
434   if (rv)
435     goto out;
436
437   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
438
439   if (rv)
440     goto out;
441
442   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
443
444   if (rv)
445     goto out;
446
447   rv = tunnel_encap_decap_flags_decode (mp->entry.tunnel_flags,
448                                         &tun.t_encap_decap_flags);
449
450   if (rv)
451     goto out;
452
453   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
454   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
455
456   flags = ipsec_sa_flags_decode (mp->entry.flags);
457   tun.t_dscp = ip_dscp_decode (mp->entry.dscp);
458
459   ip_address_decode2 (&mp->entry.tunnel_src, &tun.t_src);
460   ip_address_decode2 (&mp->entry.tunnel_dst, &tun.t_dst);
461
462   if (mp->is_add)
463     rv = ipsec_sa_add_and_lock (
464       id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
465       mp->entry.salt, htons (mp->entry.udp_src_port),
466       htons (mp->entry.udp_dst_port), &tun, &sa_index);
467   else
468     rv = ipsec_sa_unlock_id (id);
469
470 #else
471   rv = VNET_API_ERROR_UNIMPLEMENTED;
472 #endif
473
474 out:
475   /* *INDENT-OFF* */
476   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_V2_REPLY,
477   {
478     rmp->stat_index = htonl (sa_index);
479   });
480   /* *INDENT-ON* */
481 }
482
483 static void
484 vl_api_ipsec_sad_entry_add_del_v3_t_handler (
485   vl_api_ipsec_sad_entry_add_del_v3_t *mp)
486 {
487   vl_api_ipsec_sad_entry_add_del_v3_reply_t *rmp;
488   ipsec_key_t crypto_key, integ_key;
489   ipsec_crypto_alg_t crypto_alg;
490   ipsec_integ_alg_t integ_alg;
491   ipsec_protocol_t proto;
492   ipsec_sa_flags_t flags;
493   u32 id, spi, sa_index = ~0;
494   tunnel_t tun;
495   int rv;
496
497 #if WITH_LIBSSL > 0
498
499   id = ntohl (mp->entry.sad_id);
500   spi = ntohl (mp->entry.spi);
501
502   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
503
504   if (rv)
505     goto out;
506
507   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
508
509   if (rv)
510     goto out;
511
512   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
513
514   if (rv)
515     goto out;
516
517   flags = ipsec_sa_flags_decode (mp->entry.flags);
518
519   if (flags & IPSEC_SA_FLAG_IS_TUNNEL)
520     {
521       rv = tunnel_decode (&mp->entry.tunnel, &tun);
522
523       if (rv)
524         goto out;
525     }
526
527   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
528   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
529
530   if (mp->is_add)
531     rv = ipsec_sa_add_and_lock (
532       id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
533       mp->entry.salt, htons (mp->entry.udp_src_port),
534       htons (mp->entry.udp_dst_port), &tun, &sa_index);
535   else
536     rv = ipsec_sa_unlock_id (id);
537
538 #else
539   rv = VNET_API_ERROR_UNIMPLEMENTED;
540 #endif
541
542 out:
543   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_V3_REPLY,
544                 { rmp->stat_index = htonl (sa_index); });
545 }
546
547 static void
548 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
549                          u32 context)
550 {
551   vl_api_ipsec_spds_details_t *mp;
552   u32 n_policies = 0;
553
554   mp = vl_msg_api_alloc (sizeof (*mp));
555   clib_memset (mp, 0, sizeof (*mp));
556   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPDS_DETAILS);
557   mp->context = context;
558
559   mp->spd_id = htonl (spd->id);
560 #define _(s, n) n_policies += vec_len (spd->policies[IPSEC_SPD_POLICY_##s]);
561   foreach_ipsec_spd_policy_type
562 #undef _
563     mp->npolicies = htonl (n_policies);
564
565   vl_api_send_msg (reg, (u8 *) mp);
566 }
567
568 static void
569 vl_api_ipsec_spds_dump_t_handler (vl_api_ipsec_spds_dump_t * mp)
570 {
571   vl_api_registration_t *reg;
572   ipsec_main_t *im = &ipsec_main;
573   ipsec_spd_t *spd;
574 #if WITH_LIBSSL > 0
575   reg = vl_api_client_index_to_registration (mp->client_index);
576   if (!reg)
577     return;
578
579   /* *INDENT-OFF* */
580   pool_foreach (spd, im->spds)  {
581     send_ipsec_spds_details (spd, reg, mp->context);
582   }
583   /* *INDENT-ON* */
584 #else
585   clib_warning ("unimplemented");
586 #endif
587 }
588
589 vl_api_ipsec_spd_action_t
590 ipsec_spd_action_encode (ipsec_policy_action_t in)
591 {
592   vl_api_ipsec_spd_action_t out = IPSEC_API_SPD_ACTION_BYPASS;
593
594   switch (in)
595     {
596 #define _(v,f,s) case IPSEC_POLICY_ACTION_##f: \
597       out = IPSEC_API_SPD_ACTION_##f;          \
598       break;
599       foreach_ipsec_policy_action
600 #undef _
601     }
602   return (clib_host_to_net_u32 (out));
603 }
604
605 static void
606 send_ipsec_spd_details (ipsec_policy_t * p, vl_api_registration_t * reg,
607                         u32 context)
608 {
609   vl_api_ipsec_spd_details_t *mp;
610
611   mp = vl_msg_api_alloc (sizeof (*mp));
612   clib_memset (mp, 0, sizeof (*mp));
613   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_DETAILS);
614   mp->context = context;
615
616   mp->entry.spd_id = htonl (p->id);
617   mp->entry.priority = htonl (p->priority);
618   mp->entry.is_outbound = ((p->type == IPSEC_SPD_POLICY_IP6_OUTBOUND) ||
619                            (p->type == IPSEC_SPD_POLICY_IP4_OUTBOUND));
620
621   ip_address_encode (&p->laddr.start, IP46_TYPE_ANY,
622                      &mp->entry.local_address_start);
623   ip_address_encode (&p->laddr.stop, IP46_TYPE_ANY,
624                      &mp->entry.local_address_stop);
625   ip_address_encode (&p->raddr.start, IP46_TYPE_ANY,
626                      &mp->entry.remote_address_start);
627   ip_address_encode (&p->raddr.stop, IP46_TYPE_ANY,
628                      &mp->entry.remote_address_stop);
629   mp->entry.local_port_start = htons (p->lport.start);
630   mp->entry.local_port_stop = htons (p->lport.stop);
631   mp->entry.remote_port_start = htons (p->rport.start);
632   mp->entry.remote_port_stop = htons (p->rport.stop);
633   mp->entry.protocol = p->protocol;
634   mp->entry.policy = ipsec_spd_action_encode (p->policy);
635   mp->entry.sa_id = htonl (p->sa_id);
636
637   vl_api_send_msg (reg, (u8 *) mp);
638 }
639
640 static void
641 vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp)
642 {
643   vl_api_registration_t *reg;
644   ipsec_main_t *im = &ipsec_main;
645   ipsec_spd_policy_type_t ptype;
646   ipsec_policy_t *policy;
647   ipsec_spd_t *spd;
648   uword *p;
649   u32 spd_index, *ii;
650 #if WITH_LIBSSL > 0
651   reg = vl_api_client_index_to_registration (mp->client_index);
652   if (!reg)
653     return;
654
655   p = hash_get (im->spd_index_by_spd_id, ntohl (mp->spd_id));
656   if (!p)
657     return;
658
659   spd_index = p[0];
660   spd = pool_elt_at_index (im->spds, spd_index);
661
662   /* *INDENT-OFF* */
663   FOR_EACH_IPSEC_SPD_POLICY_TYPE(ptype) {
664     vec_foreach(ii, spd->policies[ptype])
665       {
666         policy = pool_elt_at_index(im->policies, *ii);
667
668         if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == policy->sa_id)
669           send_ipsec_spd_details (policy, reg, mp->context);
670       }
671   }
672   /* *INDENT-ON* */
673 #else
674   clib_warning ("unimplemented");
675 #endif
676 }
677
678 static void
679 send_ipsec_spd_interface_details (vl_api_registration_t * reg, u32 spd_index,
680                                   u32 sw_if_index, u32 context)
681 {
682   vl_api_ipsec_spd_interface_details_t *mp;
683
684   mp = vl_msg_api_alloc (sizeof (*mp));
685   clib_memset (mp, 0, sizeof (*mp));
686   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_INTERFACE_DETAILS);
687   mp->context = context;
688
689   mp->spd_index = htonl (spd_index);
690   mp->sw_if_index = htonl (sw_if_index);
691
692   vl_api_send_msg (reg, (u8 *) mp);
693 }
694
695 static void
696 vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t *
697                                            mp)
698 {
699   ipsec_main_t *im = &ipsec_main;
700   vl_api_registration_t *reg;
701   u32 k, v, spd_index;
702
703 #if WITH_LIBSSL > 0
704   reg = vl_api_client_index_to_registration (mp->client_index);
705   if (!reg)
706     return;
707
708   if (mp->spd_index_valid)
709     {
710       spd_index = ntohl (mp->spd_index);
711       /* *INDENT-OFF* */
712       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
713         if (v == spd_index)
714           send_ipsec_spd_interface_details(reg, v, k, mp->context);
715       }));
716       /* *INDENT-ON* */
717     }
718   else
719     {
720       /* *INDENT-OFF* */
721       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
722         send_ipsec_spd_interface_details(reg, v, k, mp->context);
723       }));
724       /* *INDENT-ON* */
725     }
726
727 #else
728   clib_warning ("unimplemented");
729 #endif
730 }
731
732 static void
733 vl_api_ipsec_itf_create_t_handler (vl_api_ipsec_itf_create_t * mp)
734 {
735   vl_api_ipsec_itf_create_reply_t *rmp;
736   tunnel_mode_t mode;
737   u32 sw_if_index = ~0;
738   int rv;
739
740   rv = tunnel_mode_decode (mp->itf.mode, &mode);
741
742   if (!rv)
743     rv = ipsec_itf_create (ntohl (mp->itf.user_instance), mode, &sw_if_index);
744
745   /* *INDENT-OFF* */
746   REPLY_MACRO2 (VL_API_IPSEC_ITF_CREATE_REPLY,
747   ({
748     rmp->sw_if_index = htonl (sw_if_index);
749   }));
750   /* *INDENT-ON* */
751 }
752
753 static void
754 vl_api_ipsec_itf_delete_t_handler (vl_api_ipsec_itf_delete_t * mp)
755 {
756   vl_api_ipsec_itf_delete_reply_t *rmp;
757   int rv;
758
759   rv = ipsec_itf_delete (ntohl (mp->sw_if_index));
760
761   REPLY_MACRO (VL_API_IPSEC_ITF_DELETE_REPLY);
762 }
763
764 static void
765 vl_api_ipsec_itf_dump_t_handler (vl_api_ipsec_itf_dump_t * mp)
766 {
767 }
768
769 typedef struct ipsec_sa_dump_match_ctx_t_
770 {
771   index_t sai;
772   u32 sw_if_index;
773 } ipsec_sa_dump_match_ctx_t;
774
775 static walk_rc_t
776 ipsec_sa_dump_match_sa (index_t itpi, void *arg)
777 {
778   ipsec_sa_dump_match_ctx_t *ctx = arg;
779   ipsec_tun_protect_t *itp;
780   index_t sai;
781
782   itp = ipsec_tun_protect_get (itpi);
783
784   if (itp->itp_out_sa == ctx->sai)
785     {
786       ctx->sw_if_index = itp->itp_sw_if_index;
787       return (WALK_STOP);
788     }
789   /* *INDENT-OFF* */
790   FOR_EACH_IPSEC_PROTECT_INPUT_SAI (itp, sai,
791   ({
792     if (sai == ctx->sai)
793       {
794         ctx->sw_if_index = itp->itp_sw_if_index;
795         return (WALK_STOP);
796       }
797   }));
798   /* *INDENT-OFF* */
799
800   return (WALK_CONTINUE);
801 }
802
803 static walk_rc_t
804 send_ipsec_sa_details (ipsec_sa_t * sa, void *arg)
805 {
806   ipsec_dump_walk_ctx_t *ctx = arg;
807   vl_api_ipsec_sa_details_t *mp;
808
809   mp = vl_msg_api_alloc (sizeof (*mp));
810   clib_memset (mp, 0, sizeof (*mp));
811   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS);
812   mp->context = ctx->context;
813
814   mp->entry.sad_id = htonl (sa->id);
815   mp->entry.spi = htonl (sa->spi);
816   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
817   mp->entry.tx_table_id = htonl (sa->tunnel.t_table_id);
818
819   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
820   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
821
822   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
823   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
824
825   mp->entry.flags = ipsec_sad_flags_encode (sa);
826   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
827
828   if (ipsec_sa_is_set_IS_PROTECT (sa))
829     {
830       ipsec_sa_dump_match_ctx_t ctx = {
831         .sai = sa - ipsec_sa_pool,
832         .sw_if_index = ~0,
833       };
834       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
835
836       mp->sw_if_index = htonl (ctx.sw_if_index);
837     }
838   else
839     mp->sw_if_index = ~0;
840
841   if (ipsec_sa_is_set_IS_TUNNEL (sa))
842     {
843       ip_address_encode2 (&sa->tunnel.t_src, &mp->entry.tunnel_src);
844       ip_address_encode2 (&sa->tunnel.t_dst, &mp->entry.tunnel_dst);
845     }
846   if (ipsec_sa_is_set_UDP_ENCAP (sa))
847     {
848       mp->entry.udp_src_port = sa->udp_hdr.src_port;
849       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
850     }
851
852   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
853   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
854   if (ipsec_sa_is_set_USE_ESN (sa))
855     {
856       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
857       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
858     }
859   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
860     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
861
862   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
863
864   vl_api_send_msg (ctx->reg, (u8 *) mp);
865
866   return (WALK_CONTINUE);
867 }
868
869 static void
870 vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp)
871 {
872   vl_api_registration_t *reg;
873
874 #if WITH_LIBSSL > 0
875   reg = vl_api_client_index_to_registration (mp->client_index);
876   if (!reg)
877     return;
878
879   ipsec_dump_walk_ctx_t ctx = {
880     .reg = reg,
881     .context = mp->context,
882   };
883
884   ipsec_sa_walk (send_ipsec_sa_details, &ctx);
885
886 #else
887   clib_warning ("unimplemented");
888 #endif
889 }
890
891 static walk_rc_t
892 send_ipsec_sa_v2_details (ipsec_sa_t * sa, void *arg)
893 {
894   ipsec_dump_walk_ctx_t *ctx = arg;
895   vl_api_ipsec_sa_v2_details_t *mp;
896
897   mp = vl_msg_api_alloc (sizeof (*mp));
898   clib_memset (mp, 0, sizeof (*mp));
899   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_V2_DETAILS);
900   mp->context = ctx->context;
901
902   mp->entry.sad_id = htonl (sa->id);
903   mp->entry.spi = htonl (sa->spi);
904   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
905   mp->entry.tx_table_id = htonl (sa->tunnel.t_table_id);
906
907   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
908   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
909
910   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
911   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
912
913   mp->entry.flags = ipsec_sad_flags_encode (sa);
914   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
915
916   if (ipsec_sa_is_set_IS_PROTECT (sa))
917     {
918       ipsec_sa_dump_match_ctx_t ctx = {
919         .sai = sa - ipsec_sa_pool,
920         .sw_if_index = ~0,
921       };
922       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
923
924       mp->sw_if_index = htonl (ctx.sw_if_index);
925     }
926   else
927     mp->sw_if_index = ~0;
928
929   if (ipsec_sa_is_set_IS_TUNNEL (sa))
930     {
931       ip_address_encode2 (&sa->tunnel.t_src, &mp->entry.tunnel_src);
932       ip_address_encode2 (&sa->tunnel.t_dst, &mp->entry.tunnel_dst);
933     }
934   if (ipsec_sa_is_set_UDP_ENCAP (sa))
935     {
936       mp->entry.udp_src_port = sa->udp_hdr.src_port;
937       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
938     }
939
940   mp->entry.tunnel_flags =
941     tunnel_encap_decap_flags_encode (sa->tunnel.t_encap_decap_flags);
942   mp->entry.dscp = ip_dscp_encode (sa->tunnel.t_dscp);
943
944   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
945   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
946   if (ipsec_sa_is_set_USE_ESN (sa))
947     {
948       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
949       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
950     }
951   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
952     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
953
954   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
955
956   vl_api_send_msg (ctx->reg, (u8 *) mp);
957
958   return (WALK_CONTINUE);
959 }
960
961 static void
962 vl_api_ipsec_sa_v2_dump_t_handler (vl_api_ipsec_sa_v2_dump_t *mp)
963 {
964   vl_api_registration_t *reg;
965
966 #if WITH_LIBSSL > 0
967   reg = vl_api_client_index_to_registration (mp->client_index);
968   if (!reg)
969     return;
970
971   ipsec_dump_walk_ctx_t ctx = {
972     .reg = reg,
973     .context = mp->context,
974   };
975
976   ipsec_sa_walk (send_ipsec_sa_v2_details, &ctx);
977
978 #else
979   clib_warning ("unimplemented");
980 #endif
981 }
982
983 static walk_rc_t
984 send_ipsec_sa_v3_details (ipsec_sa_t *sa, void *arg)
985 {
986   ipsec_dump_walk_ctx_t *ctx = arg;
987   vl_api_ipsec_sa_v3_details_t *mp;
988
989   mp = vl_msg_api_alloc (sizeof (*mp));
990   clib_memset (mp, 0, sizeof (*mp));
991   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_V3_DETAILS);
992   mp->context = ctx->context;
993
994   mp->entry.sad_id = htonl (sa->id);
995   mp->entry.spi = htonl (sa->spi);
996   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
997
998   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
999   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
1000
1001   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
1002   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
1003
1004   mp->entry.flags = ipsec_sad_flags_encode (sa);
1005   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
1006
1007   if (ipsec_sa_is_set_IS_PROTECT (sa))
1008     {
1009       ipsec_sa_dump_match_ctx_t ctx = {
1010         .sai = sa - ipsec_sa_pool,
1011         .sw_if_index = ~0,
1012       };
1013       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
1014
1015       mp->sw_if_index = htonl (ctx.sw_if_index);
1016     }
1017   else
1018     mp->sw_if_index = ~0;
1019
1020   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1021     tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
1022
1023   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1024     {
1025       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1026       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1027     }
1028
1029   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1030   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
1031   if (ipsec_sa_is_set_USE_ESN (sa))
1032     {
1033       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1034       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
1035     }
1036   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1037     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
1038
1039   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1040
1041   vl_api_send_msg (ctx->reg, (u8 *) mp);
1042
1043   return (WALK_CONTINUE);
1044 }
1045
1046 static void
1047 vl_api_ipsec_sa_v3_dump_t_handler (vl_api_ipsec_sa_v3_dump_t *mp)
1048 {
1049   vl_api_registration_t *reg;
1050
1051 #if WITH_LIBSSL > 0
1052   reg = vl_api_client_index_to_registration (mp->client_index);
1053   if (!reg)
1054     return;
1055
1056   ipsec_dump_walk_ctx_t ctx = {
1057     .reg = reg,
1058     .context = mp->context,
1059   };
1060
1061   ipsec_sa_walk (send_ipsec_sa_v3_details, &ctx);
1062
1063 #else
1064   clib_warning ("unimplemented");
1065 #endif
1066 }
1067
1068 static void
1069 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
1070 {
1071   vl_api_registration_t *rp;
1072   ipsec_main_t *im = &ipsec_main;
1073   u32 context = mp->context;
1074
1075   rp = vl_api_client_index_to_registration (mp->client_index);
1076
1077   if (rp == 0)
1078     {
1079       clib_warning ("Client %d AWOL", mp->client_index);
1080       return;
1081     }
1082
1083   ipsec_ah_backend_t *ab;
1084   ipsec_esp_backend_t *eb;
1085   /* *INDENT-OFF* */
1086   pool_foreach (ab, im->ah_backends) {
1087     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
1088     clib_memset (mp, 0, sizeof (*mp));
1089     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
1090     mp->context = context;
1091     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
1092               ab->name);
1093     mp->protocol = ntohl (IPSEC_API_PROTO_AH);
1094     mp->index = ab - im->ah_backends;
1095     mp->active = mp->index == im->ah_current_backend ? 1 : 0;
1096     vl_api_send_msg (rp, (u8 *)mp);
1097   }
1098   pool_foreach (eb, im->esp_backends) {
1099     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
1100     clib_memset (mp, 0, sizeof (*mp));
1101     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
1102     mp->context = context;
1103     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
1104               eb->name);
1105     mp->protocol = ntohl (IPSEC_API_PROTO_ESP);
1106     mp->index = eb - im->esp_backends;
1107     mp->active = mp->index == im->esp_current_backend ? 1 : 0;
1108     vl_api_send_msg (rp, (u8 *)mp);
1109   }
1110   /* *INDENT-ON* */
1111 }
1112
1113 static void
1114 vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
1115 {
1116   ipsec_main_t *im = &ipsec_main;
1117   vl_api_ipsec_select_backend_reply_t *rmp;
1118   ipsec_protocol_t protocol;
1119   int rv = 0;
1120   if (pool_elts (ipsec_sa_pool) > 0)
1121     {
1122       rv = VNET_API_ERROR_INSTANCE_IN_USE;
1123       goto done;
1124     }
1125
1126   rv = ipsec_proto_decode (mp->protocol, &protocol);
1127
1128   if (rv)
1129     goto done;
1130
1131 #if WITH_LIBSSL > 0
1132   switch (protocol)
1133     {
1134     case IPSEC_PROTOCOL_ESP:
1135       rv = ipsec_select_esp_backend (im, mp->index);
1136       break;
1137     case IPSEC_PROTOCOL_AH:
1138       rv = ipsec_select_ah_backend (im, mp->index);
1139       break;
1140     default:
1141       rv = VNET_API_ERROR_INVALID_PROTOCOL;
1142       break;
1143     }
1144 #else
1145   clib_warning ("unimplemented");       /* FIXME */
1146 #endif
1147 done:
1148   REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
1149 }
1150
1151 static void
1152 vl_api_ipsec_set_async_mode_t_handler (vl_api_ipsec_set_async_mode_t * mp)
1153 {
1154   vl_api_ipsec_set_async_mode_reply_t *rmp;
1155   int rv = 0;
1156
1157   ipsec_set_async_mode (mp->async_enable);
1158
1159   REPLY_MACRO (VL_API_IPSEC_SET_ASYNC_MODE_REPLY);
1160 }
1161
1162 /*
1163  * ipsec_api_hookup
1164  * Add vpe's API message handlers to the table.
1165  * vlib has already mapped shared memory and
1166  * added the client registration handlers.
1167  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
1168  */
1169 #define vl_msg_name_crc_list
1170 #include <vnet/vnet_all_api_h.h>
1171 #undef vl_msg_name_crc_list
1172
1173 static void
1174 setup_message_id_table (api_main_t * am)
1175 {
1176 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1177   foreach_vl_msg_name_crc_ipsec;
1178 #undef _
1179 }
1180
1181 static clib_error_t *
1182 ipsec_api_hookup (vlib_main_t * vm)
1183 {
1184   api_main_t *am = vlibapi_get_main ();
1185
1186 #define _(N,n)                                                  \
1187     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1188                            vl_api_##n##_t_handler,              \
1189                            vl_noop_handler,                     \
1190                            vl_api_##n##_t_endian,               \
1191                            vl_api_##n##_t_print,                \
1192                            sizeof(vl_api_##n##_t), 1);
1193   foreach_vpe_api_msg;
1194 #undef _
1195
1196   /*
1197    * Set up the (msg_name, crc, message-id) table
1198    */
1199   setup_message_id_table (am);
1200
1201   return 0;
1202 }
1203
1204 VLIB_API_INIT_FUNCTION (ipsec_api_hookup);
1205
1206 /*
1207  * fd.io coding-style-patch-verification: ON
1208  *
1209  * Local Variables:
1210  * eval: (c-set-style "gnu")
1211  * End:
1212  */