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