ipsec: Revert "IPSEC: remove byte swap operations in DP during SPD classify"
[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 (id, spi, proto,
517                        crypto_alg, &crypto_key,
518                        integ_alg, &integ_key, flags,
519                        0, mp->entry.salt, &tun_src, &tun_dst, &sa_index);
520   else
521     rv = ipsec_sa_del (id);
522
523 #else
524   rv = VNET_API_ERROR_UNIMPLEMENTED;
525 #endif
526
527 out:
528   /* *INDENT-OFF* */
529   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY,
530   {
531     rmp->stat_index = htonl (sa_index);
532   });
533   /* *INDENT-ON* */
534 }
535
536 static void
537 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
538                          u32 context)
539 {
540   vl_api_ipsec_spds_details_t *mp;
541   u32 n_policies = 0;
542
543   mp = vl_msg_api_alloc (sizeof (*mp));
544   clib_memset (mp, 0, sizeof (*mp));
545   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPDS_DETAILS);
546   mp->context = context;
547
548   mp->spd_id = htonl (spd->id);
549 #define _(s, n) n_policies += vec_len (spd->policies[IPSEC_SPD_POLICY_##s]);
550   foreach_ipsec_spd_policy_type
551 #undef _
552     mp->npolicies = htonl (n_policies);
553
554   vl_api_send_msg (reg, (u8 *) mp);
555 }
556
557 static void
558 vl_api_ipsec_spds_dump_t_handler (vl_api_ipsec_spds_dump_t * mp)
559 {
560   vl_api_registration_t *reg;
561   ipsec_main_t *im = &ipsec_main;
562   ipsec_spd_t *spd;
563 #if WITH_LIBSSL > 0
564   reg = vl_api_client_index_to_registration (mp->client_index);
565   if (!reg)
566     return;
567
568   /* *INDENT-OFF* */
569   pool_foreach (spd, im->spds, ({
570     send_ipsec_spds_details (spd, reg, mp->context);
571   }));
572   /* *INDENT-ON* */
573 #else
574   clib_warning ("unimplemented");
575 #endif
576 }
577
578 vl_api_ipsec_spd_action_t
579 ipsec_spd_action_encode (ipsec_policy_action_t in)
580 {
581   vl_api_ipsec_spd_action_t out = IPSEC_API_SPD_ACTION_BYPASS;
582
583   switch (in)
584     {
585 #define _(v,f,s) case IPSEC_POLICY_ACTION_##f: \
586       out = IPSEC_API_SPD_ACTION_##f;          \
587       break;
588       foreach_ipsec_policy_action
589 #undef _
590     }
591   return (clib_host_to_net_u32 (out));
592 }
593
594 static void
595 send_ipsec_spd_details (ipsec_policy_t * p, vl_api_registration_t * reg,
596                         u32 context)
597 {
598   vl_api_ipsec_spd_details_t *mp;
599
600   mp = vl_msg_api_alloc (sizeof (*mp));
601   clib_memset (mp, 0, sizeof (*mp));
602   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_DETAILS);
603   mp->context = context;
604
605   mp->entry.spd_id = htonl (p->id);
606   mp->entry.priority = htonl (p->priority);
607   mp->entry.is_outbound = ((p->type == IPSEC_SPD_POLICY_IP6_OUTBOUND) ||
608                            (p->type == IPSEC_SPD_POLICY_IP4_OUTBOUND));
609
610   ip_address_encode (&p->laddr.start, IP46_TYPE_ANY,
611                      &mp->entry.local_address_start);
612   ip_address_encode (&p->laddr.stop, IP46_TYPE_ANY,
613                      &mp->entry.local_address_stop);
614   ip_address_encode (&p->raddr.start, IP46_TYPE_ANY,
615                      &mp->entry.remote_address_start);
616   ip_address_encode (&p->raddr.stop, IP46_TYPE_ANY,
617                      &mp->entry.remote_address_stop);
618   mp->entry.local_port_start = htons (p->lport.start);
619   mp->entry.local_port_stop = htons (p->lport.stop);
620   mp->entry.remote_port_start = htons (p->rport.start);
621   mp->entry.remote_port_stop = htons (p->rport.stop);
622   mp->entry.protocol = p->protocol;
623   mp->entry.policy = ipsec_spd_action_encode (p->policy);
624   mp->entry.sa_id = htonl (p->sa_id);
625
626   vl_api_send_msg (reg, (u8 *) mp);
627 }
628
629 static void
630 vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp)
631 {
632   vl_api_registration_t *reg;
633   ipsec_main_t *im = &ipsec_main;
634   ipsec_spd_policy_type_t ptype;
635   ipsec_policy_t *policy;
636   ipsec_spd_t *spd;
637   uword *p;
638   u32 spd_index, *ii;
639 #if WITH_LIBSSL > 0
640   reg = vl_api_client_index_to_registration (mp->client_index);
641   if (!reg)
642     return;
643
644   p = hash_get (im->spd_index_by_spd_id, ntohl (mp->spd_id));
645   if (!p)
646     return;
647
648   spd_index = p[0];
649   spd = pool_elt_at_index (im->spds, spd_index);
650
651   /* *INDENT-OFF* */
652   FOR_EACH_IPSEC_SPD_POLICY_TYPE(ptype) {
653     vec_foreach(ii, spd->policies[ptype])
654       {
655         policy = pool_elt_at_index(im->policies, *ii);
656
657         if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == policy->sa_id)
658           send_ipsec_spd_details (policy, reg, mp->context);
659       }
660   }
661   /* *INDENT-ON* */
662 #else
663   clib_warning ("unimplemented");
664 #endif
665 }
666
667 static void
668 send_ipsec_spd_interface_details (vl_api_registration_t * reg, u32 spd_index,
669                                   u32 sw_if_index, u32 context)
670 {
671   vl_api_ipsec_spd_interface_details_t *mp;
672
673   mp = vl_msg_api_alloc (sizeof (*mp));
674   clib_memset (mp, 0, sizeof (*mp));
675   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_INTERFACE_DETAILS);
676   mp->context = context;
677
678   mp->spd_index = htonl (spd_index);
679   mp->sw_if_index = htonl (sw_if_index);
680
681   vl_api_send_msg (reg, (u8 *) mp);
682 }
683
684 static void
685 vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t *
686                                            mp)
687 {
688   ipsec_main_t *im = &ipsec_main;
689   vl_api_registration_t *reg;
690   u32 k, v, spd_index;
691
692 #if WITH_LIBSSL > 0
693   reg = vl_api_client_index_to_registration (mp->client_index);
694   if (!reg)
695     return;
696
697   if (mp->spd_index_valid)
698     {
699       spd_index = ntohl (mp->spd_index);
700       /* *INDENT-OFF* */
701       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
702         if (v == spd_index)
703           send_ipsec_spd_interface_details(reg, v, k, mp->context);
704       }));
705       /* *INDENT-ON* */
706     }
707   else
708     {
709       /* *INDENT-OFF* */
710       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
711         send_ipsec_spd_interface_details(reg, v, k, mp->context);
712       }));
713       /* *INDENT-ON* */
714     }
715
716 #else
717   clib_warning ("unimplemented");
718 #endif
719 }
720
721 static void
722 vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
723                                           mp)
724 {
725   vl_api_ipsec_tunnel_if_add_del_reply_t *rmp;
726   ipsec_main_t *im = &ipsec_main;
727   vnet_main_t *vnm = im->vnet_main;
728   u32 sw_if_index = ~0;
729   ip46_type_t itype;
730   int rv;
731
732 #if WITH_LIBSSL > 0
733   ipsec_add_del_tunnel_args_t tun;
734
735   clib_memset (&tun, 0, sizeof (ipsec_add_del_tunnel_args_t));
736
737   tun.is_add = mp->is_add;
738   tun.esn = mp->esn;
739   tun.anti_replay = mp->anti_replay;
740   tun.local_spi = ntohl (mp->local_spi);
741   tun.remote_spi = ntohl (mp->remote_spi);
742   tun.crypto_alg = mp->crypto_alg;
743   tun.local_crypto_key_len = mp->local_crypto_key_len;
744   tun.remote_crypto_key_len = mp->remote_crypto_key_len;
745   tun.integ_alg = mp->integ_alg;
746   tun.local_integ_key_len = mp->local_integ_key_len;
747   tun.remote_integ_key_len = mp->remote_integ_key_len;
748   tun.udp_encap = mp->udp_encap;
749   tun.tx_table_id = ntohl (mp->tx_table_id);
750   tun.salt = mp->salt;
751   itype = ip_address_decode (&mp->local_ip, &tun.local_ip);
752   itype = ip_address_decode (&mp->remote_ip, &tun.remote_ip);
753   tun.is_ip6 = (IP46_TYPE_IP6 == itype);
754   memcpy (&tun.local_crypto_key, &mp->local_crypto_key,
755           mp->local_crypto_key_len);
756   memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key,
757           mp->remote_crypto_key_len);
758   memcpy (&tun.local_integ_key, &mp->local_integ_key,
759           mp->local_integ_key_len);
760   memcpy (&tun.remote_integ_key, &mp->remote_integ_key,
761           mp->remote_integ_key_len);
762   tun.renumber = mp->renumber;
763   tun.show_instance = ntohl (mp->show_instance);
764
765   rv = ipsec_add_del_tunnel_if_internal (vnm, &tun, &sw_if_index);
766
767 #else
768   rv = VNET_API_ERROR_UNIMPLEMENTED;
769 #endif
770
771   /* *INDENT-OFF* */
772   REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY,
773   ({
774     rmp->sw_if_index = htonl (sw_if_index);
775   }));
776   /* *INDENT-ON* */
777 }
778
779 static void
780 send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg,
781                        u32 context, u32 sw_if_index)
782 {
783   vl_api_ipsec_sa_details_t *mp;
784
785   mp = vl_msg_api_alloc (sizeof (*mp));
786   clib_memset (mp, 0, sizeof (*mp));
787   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS);
788   mp->context = context;
789
790   mp->entry.sad_id = htonl (sa->id);
791   mp->entry.spi = htonl (sa->spi);
792   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
793   mp->entry.tx_table_id =
794     htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4));
795
796   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
797   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
798
799   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
800   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
801
802   mp->entry.flags = ipsec_sad_flags_encode (sa);
803
804   if (ipsec_sa_is_set_IS_TUNNEL (sa))
805     {
806       ip_address_encode (&sa->tunnel_src_addr, IP46_TYPE_ANY,
807                          &mp->entry.tunnel_src);
808       ip_address_encode (&sa->tunnel_dst_addr, IP46_TYPE_ANY,
809                          &mp->entry.tunnel_dst);
810     }
811
812   mp->sw_if_index = htonl (sw_if_index);
813   mp->salt = clib_host_to_net_u32 (sa->salt);
814   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
815   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
816   if (ipsec_sa_is_set_USE_ESN (sa))
817     {
818       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
819       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
820     }
821   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
822     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
823
824   vl_api_send_msg (reg, (u8 *) mp);
825 }
826
827
828 static void
829 vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp)
830 {
831   vl_api_registration_t *reg;
832   ipsec_main_t *im = &ipsec_main;
833   vnet_main_t *vnm = im->vnet_main;
834   ipsec_sa_t *sa;
835   ipsec_tunnel_if_t *t;
836   u32 *sa_index_to_tun_if_index = 0;
837
838 #if WITH_LIBSSL > 0
839   reg = vl_api_client_index_to_registration (mp->client_index);
840   if (!reg || pool_elts (im->sad) == 0)
841     return;
842
843   vec_validate_init_empty (sa_index_to_tun_if_index, vec_len (im->sad) - 1,
844                            ~0);
845
846   /* *INDENT-OFF* */
847   pool_foreach (t, im->tunnel_interfaces,
848   ({
849     vnet_hw_interface_t *hi;
850     u32 sw_if_index = ~0;
851
852     hi = vnet_get_hw_interface (vnm, t->hw_if_index);
853     sw_if_index = hi->sw_if_index;
854     sa_index_to_tun_if_index[t->input_sa_index] = sw_if_index;
855     sa_index_to_tun_if_index[t->output_sa_index] = sw_if_index;
856   }));
857
858   pool_foreach (sa, im->sad,
859   ({
860     if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == sa->id)
861       send_ipsec_sa_details (sa, reg, mp->context,
862                              sa_index_to_tun_if_index[sa - im->sad]);
863   }));
864   /* *INDENT-ON* */
865
866   vec_free (sa_index_to_tun_if_index);
867 #else
868   clib_warning ("unimplemented");
869 #endif
870 }
871
872 static void
873 vl_api_ipsec_tunnel_if_set_sa_t_handler (vl_api_ipsec_tunnel_if_set_sa_t * mp)
874 {
875   vl_api_ipsec_tunnel_if_set_sa_reply_t *rmp;
876   ipsec_main_t *im = &ipsec_main;
877   vnet_main_t *vnm = im->vnet_main;
878   vnet_sw_interface_t *sw;
879   int rv;
880
881 #if WITH_LIBSSL > 0
882   sw = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
883
884   rv = ipsec_set_interface_sa (vnm, sw->hw_if_index, ntohl (mp->sa_id),
885                                mp->is_outbound);
886 #else
887   clib_warning ("unimplemented");
888 #endif
889
890   REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY);
891 }
892
893 static void
894 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
895 {
896   vl_api_registration_t *rp;
897   ipsec_main_t *im = &ipsec_main;
898   u32 context = mp->context;
899
900   rp = vl_api_client_index_to_registration (mp->client_index);
901
902   if (rp == 0)
903     {
904       clib_warning ("Client %d AWOL", mp->client_index);
905       return;
906     }
907
908   ipsec_ah_backend_t *ab;
909   ipsec_esp_backend_t *eb;
910   /* *INDENT-OFF* */
911   pool_foreach (ab, im->ah_backends, {
912     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
913     clib_memset (mp, 0, sizeof (*mp));
914     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
915     mp->context = context;
916     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
917               ab->name);
918     mp->protocol = ntohl (IPSEC_API_PROTO_AH);
919     mp->index = ab - im->ah_backends;
920     mp->active = mp->index == im->ah_current_backend ? 1 : 0;
921     vl_api_send_msg (rp, (u8 *)mp);
922   });
923   pool_foreach (eb, im->esp_backends, {
924     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
925     clib_memset (mp, 0, sizeof (*mp));
926     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
927     mp->context = context;
928     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
929               eb->name);
930     mp->protocol = ntohl (IPSEC_API_PROTO_ESP);
931     mp->index = eb - im->esp_backends;
932     mp->active = mp->index == im->esp_current_backend ? 1 : 0;
933     vl_api_send_msg (rp, (u8 *)mp);
934   });
935   /* *INDENT-ON* */
936 }
937
938 static void
939 vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
940 {
941   ipsec_main_t *im = &ipsec_main;
942   vl_api_ipsec_select_backend_reply_t *rmp;
943   ipsec_protocol_t protocol;
944   int rv = 0;
945   if (pool_elts (im->sad) > 0)
946     {
947       rv = VNET_API_ERROR_INSTANCE_IN_USE;
948       goto done;
949     }
950
951   rv = ipsec_proto_decode (mp->protocol, &protocol);
952
953   if (rv)
954     goto done;
955
956 #if WITH_LIBSSL > 0
957   switch (protocol)
958     {
959     case IPSEC_PROTOCOL_ESP:
960       rv = ipsec_select_esp_backend (im, mp->index);
961       break;
962     case IPSEC_PROTOCOL_AH:
963       rv = ipsec_select_ah_backend (im, mp->index);
964       break;
965     default:
966       rv = VNET_API_ERROR_INVALID_PROTOCOL;
967       break;
968     }
969 #else
970   clib_warning ("unimplemented");       /* FIXME */
971 #endif
972 done:
973   REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
974 }
975
976 /*
977  * ipsec_api_hookup
978  * Add vpe's API message handlers to the table.
979  * vlib has already mapped shared memory and
980  * added the client registration handlers.
981  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
982  */
983 #define vl_msg_name_crc_list
984 #include <vnet/vnet_all_api_h.h>
985 #undef vl_msg_name_crc_list
986
987 static void
988 setup_message_id_table (api_main_t * am)
989 {
990 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
991   foreach_vl_msg_name_crc_ipsec;
992 #undef _
993 }
994
995 static clib_error_t *
996 ipsec_api_hookup (vlib_main_t * vm)
997 {
998   api_main_t *am = &api_main;
999
1000 #define _(N,n)                                                  \
1001     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1002                            vl_api_##n##_t_handler,              \
1003                            vl_noop_handler,                     \
1004                            vl_api_##n##_t_endian,               \
1005                            vl_api_##n##_t_print,                \
1006                            sizeof(vl_api_##n##_t), 1);
1007   foreach_vpe_api_msg;
1008 #undef _
1009
1010   /*
1011    * Adding and deleting SAs is MP safe since when they are added/delete
1012    * no traffic is using them
1013    */
1014   am->is_mp_safe[VL_API_IPSEC_SAD_ENTRY_ADD_DEL] = 1;
1015   am->is_mp_safe[VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY] = 1;
1016
1017   /*
1018    * Set up the (msg_name, crc, message-id) table
1019    */
1020   setup_message_id_table (am);
1021
1022   return 0;
1023 }
1024
1025 VLIB_API_INIT_FUNCTION (ipsec_api_hookup);
1026
1027 /*
1028  * fd.io coding-style-patch-verification: ON
1029  *
1030  * Local Variables:
1031  * eval: (c-set-style "gnu")
1032  * End:
1033  */