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