ipsec: huge anti-replay window support
[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   u32 sw_if_index;
128 } ipsec_dump_walk_ctx_t;
129
130 static walk_rc_t
131 send_ipsec_tunnel_protect_details (index_t itpi, void *arg)
132 {
133   ipsec_dump_walk_ctx_t *ctx = arg;
134   vl_api_ipsec_tunnel_protect_details_t *mp;
135   ipsec_tun_protect_t *itp;
136   u32 ii = 0;
137   ipsec_sa_t *sa;
138
139   itp = ipsec_tun_protect_get (itpi);
140
141   mp = vl_msg_api_alloc (sizeof (*mp) + (sizeof (u32) * itp->itp_n_sa_in));
142   clib_memset (mp, 0, sizeof (*mp));
143   mp->_vl_msg_id =
144     ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_TUNNEL_PROTECT_DETAILS);
145   mp->context = ctx->context;
146
147   mp->tun.sw_if_index = htonl (itp->itp_sw_if_index);
148   ip_address_encode2 (itp->itp_key, &mp->tun.nh);
149
150   sa = ipsec_sa_get (itp->itp_out_sa);
151   mp->tun.sa_out = htonl (sa->id);
152   mp->tun.n_sa_in = itp->itp_n_sa_in;
153   /* *INDENT-OFF* */
154   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
155   ({
156     mp->tun.sa_in[ii++] = htonl (sa->id);
157   }));
158   /* *INDENT-ON* */
159
160   vl_api_send_msg (ctx->reg, (u8 *) mp);
161
162   return (WALK_CONTINUE);
163 }
164
165 static void
166 vl_api_ipsec_tunnel_protect_dump_t_handler (vl_api_ipsec_tunnel_protect_dump_t
167                                             * mp)
168 {
169   vl_api_registration_t *reg;
170   u32 sw_if_index;
171
172   reg = vl_api_client_index_to_registration (mp->client_index);
173   if (!reg)
174     return;
175
176   ipsec_dump_walk_ctx_t ctx = {
177     .reg = reg,
178     .context = mp->context,
179   };
180
181   sw_if_index = ntohl (mp->sw_if_index);
182
183   if (~0 == sw_if_index)
184     {
185       ipsec_tun_protect_walk (send_ipsec_tunnel_protect_details, &ctx);
186     }
187   else
188     {
189       ipsec_tun_protect_walk_itf (sw_if_index,
190                                   send_ipsec_tunnel_protect_details, &ctx);
191     }
192 }
193
194 static int
195 ipsec_spd_action_decode (vl_api_ipsec_spd_action_t in,
196                          ipsec_policy_action_t * out)
197 {
198   in = clib_net_to_host_u32 (in);
199
200   switch (in)
201     {
202 #define _(v,f,s) case IPSEC_API_SPD_ACTION_##f: \
203       *out = IPSEC_POLICY_ACTION_##f;              \
204       return (0);
205       foreach_ipsec_policy_action
206 #undef _
207     }
208   return (VNET_API_ERROR_UNIMPLEMENTED);
209 }
210
211 static void vl_api_ipsec_spd_entry_add_del_t_handler
212   (vl_api_ipsec_spd_entry_add_del_t * mp)
213 {
214   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
215   vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
216   ip46_type_t itype;
217   u32 stat_index;
218   int rv;
219
220   stat_index = ~0;
221
222   ipsec_policy_t p;
223
224   clib_memset (&p, 0, sizeof (p));
225
226   p.id = ntohl (mp->entry.spd_id);
227   p.priority = ntohl (mp->entry.priority);
228
229   itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
230   ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
231   ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
232   ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
233
234   p.is_ipv6 = (itype == IP46_TYPE_IP6);
235
236   p.protocol =
237     mp->entry.protocol ? mp->entry.protocol : IPSEC_POLICY_PROTOCOL_ANY;
238   p.rport.start = ntohs (mp->entry.remote_port_start);
239   p.rport.stop = ntohs (mp->entry.remote_port_stop);
240   p.lport.start = ntohs (mp->entry.local_port_start);
241   p.lport.stop = ntohs (mp->entry.local_port_stop);
242
243   rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
244
245   if (rv)
246     goto out;
247
248   /* policy action resolve unsupported */
249   if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
250     {
251       clib_warning ("unsupported action: 'resolve'");
252       rv = VNET_API_ERROR_UNIMPLEMENTED;
253       goto out;
254     }
255   p.sa_id = ntohl (mp->entry.sa_id);
256   rv =
257     ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy,
258                           &p.type);
259   if (rv)
260     goto out;
261
262   rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
263   if (rv)
264     goto out;
265
266 out:
267   /* *INDENT-OFF* */
268   REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_REPLY,
269   ({
270     rmp->stat_index = ntohl(stat_index);
271   }));
272   /* *INDENT-ON* */
273 }
274
275 static void
276 vl_api_ipsec_spd_entry_add_del_v2_t_handler (
277   vl_api_ipsec_spd_entry_add_del_v2_t *mp)
278 {
279   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
280   vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
281   ip46_type_t itype;
282   u32 stat_index;
283   int rv;
284
285   stat_index = ~0;
286
287   ipsec_policy_t p;
288
289   clib_memset (&p, 0, sizeof (p));
290
291   p.id = ntohl (mp->entry.spd_id);
292   p.priority = ntohl (mp->entry.priority);
293
294   itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
295   ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
296   ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
297   ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
298
299   p.is_ipv6 = (itype == IP46_TYPE_IP6);
300
301   p.protocol = mp->entry.protocol;
302   p.rport.start = ntohs (mp->entry.remote_port_start);
303   p.rport.stop = ntohs (mp->entry.remote_port_stop);
304   p.lport.start = ntohs (mp->entry.local_port_start);
305   p.lport.stop = ntohs (mp->entry.local_port_stop);
306
307   rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
308
309   if (rv)
310     goto out;
311
312   /* policy action resolve unsupported */
313   if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
314     {
315       clib_warning ("unsupported action: 'resolve'");
316       rv = VNET_API_ERROR_UNIMPLEMENTED;
317       goto out;
318     }
319   p.sa_id = ntohl (mp->entry.sa_id);
320   rv =
321     ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy, &p.type);
322   if (rv)
323     goto out;
324
325   rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
326   if (rv)
327     goto out;
328
329 out:
330   REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_V2_REPLY,
331                 ({ rmp->stat_index = ntohl (stat_index); }));
332 }
333
334 static void vl_api_ipsec_sad_entry_add_del_t_handler
335   (vl_api_ipsec_sad_entry_add_del_t * mp)
336 {
337   vl_api_ipsec_sad_entry_add_del_reply_t *rmp;
338   ipsec_key_t crypto_key, integ_key;
339   ipsec_crypto_alg_t crypto_alg;
340   ipsec_integ_alg_t integ_alg;
341   ipsec_protocol_t proto;
342   ipsec_sa_flags_t flags;
343   u32 id, spi, sa_index = ~0;
344   tunnel_t tun = {
345     .t_flags = TUNNEL_FLAG_NONE,
346     .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE,
347     .t_dscp = 0,
348     .t_mode = TUNNEL_MODE_P2P,
349     .t_table_id = 0,
350     .t_hop_limit = 255,
351   };
352   int rv;
353
354   id = ntohl (mp->entry.sad_id);
355   if (!mp->is_add)
356     {
357       rv = ipsec_sa_unlock_id (id);
358       goto out;
359     }
360   spi = ntohl (mp->entry.spi);
361
362   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
363
364   if (rv)
365     goto out;
366
367   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
368
369   if (rv)
370     goto out;
371
372   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
373
374   if (rv)
375     goto out;
376
377   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
378   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
379
380   flags = ipsec_sa_flags_decode (mp->entry.flags);
381
382   ip_address_decode2 (&mp->entry.tunnel_src, &tun.t_src);
383   ip_address_decode2 (&mp->entry.tunnel_dst, &tun.t_dst);
384
385   rv = ipsec_sa_add_and_lock (
386     id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
387     mp->entry.salt, htons (mp->entry.udp_src_port),
388     htons (mp->entry.udp_dst_port), 0, &tun, &sa_index);
389
390 out:
391   /* *INDENT-OFF* */
392   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY,
393   {
394     rmp->stat_index = htonl (sa_index);
395   });
396   /* *INDENT-ON* */
397 }
398
399 static void vl_api_ipsec_sad_entry_add_del_v2_t_handler
400   (vl_api_ipsec_sad_entry_add_del_v2_t * mp)
401 {
402   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
403   vl_api_ipsec_sad_entry_add_del_v2_reply_t *rmp;
404   ipsec_key_t crypto_key, integ_key;
405   ipsec_crypto_alg_t crypto_alg;
406   ipsec_integ_alg_t integ_alg;
407   ipsec_protocol_t proto;
408   ipsec_sa_flags_t flags;
409   u32 id, spi, sa_index = ~0;
410   int rv;
411   tunnel_t tun = {
412     .t_flags = TUNNEL_FLAG_NONE,
413     .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE,
414     .t_dscp = 0,
415     .t_mode = TUNNEL_MODE_P2P,
416     .t_table_id = htonl (mp->entry.tx_table_id),
417     .t_hop_limit = 255,
418   };
419
420   id = ntohl (mp->entry.sad_id);
421   if (!mp->is_add)
422     {
423       rv = ipsec_sa_unlock_id (id);
424       goto out;
425     }
426
427   spi = ntohl (mp->entry.spi);
428
429   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
430
431   if (rv)
432     goto out;
433
434   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
435
436   if (rv)
437     goto out;
438
439   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
440
441   if (rv)
442     goto out;
443
444   rv = tunnel_encap_decap_flags_decode (mp->entry.tunnel_flags,
445                                         &tun.t_encap_decap_flags);
446
447   if (rv)
448     goto out;
449
450   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
451   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
452
453   flags = ipsec_sa_flags_decode (mp->entry.flags);
454   tun.t_dscp = ip_dscp_decode (mp->entry.dscp);
455
456   ip_address_decode2 (&mp->entry.tunnel_src, &tun.t_src);
457   ip_address_decode2 (&mp->entry.tunnel_dst, &tun.t_dst);
458
459   rv = ipsec_sa_add_and_lock (
460     id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
461     mp->entry.salt, htons (mp->entry.udp_src_port),
462     htons (mp->entry.udp_dst_port), 0, &tun, &sa_index);
463
464 out:
465   /* *INDENT-OFF* */
466   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_V2_REPLY,
467   {
468     rmp->stat_index = htonl (sa_index);
469   });
470   /* *INDENT-ON* */
471 }
472
473 static int
474 ipsec_sad_entry_add_v3 (const vl_api_ipsec_sad_entry_v3_t *entry,
475                         u32 *sa_index)
476 {
477   ipsec_key_t crypto_key, integ_key;
478   ipsec_crypto_alg_t crypto_alg;
479   ipsec_integ_alg_t integ_alg;
480   ipsec_protocol_t proto;
481   ipsec_sa_flags_t flags;
482   u32 id, spi;
483   tunnel_t tun = { 0 };
484   int rv;
485
486   id = ntohl (entry->sad_id);
487   spi = ntohl (entry->spi);
488
489   rv = ipsec_proto_decode (entry->protocol, &proto);
490
491   if (rv)
492     return (rv);
493
494   rv = ipsec_crypto_algo_decode (entry->crypto_algorithm, &crypto_alg);
495
496   if (rv)
497     return (rv);
498
499   rv = ipsec_integ_algo_decode (entry->integrity_algorithm, &integ_alg);
500
501   if (rv)
502     return (rv);
503
504   flags = ipsec_sa_flags_decode (entry->flags);
505
506   if (flags & IPSEC_SA_FLAG_IS_TUNNEL)
507     {
508       rv = tunnel_decode (&entry->tunnel, &tun);
509
510       if (rv)
511         return (rv);
512     }
513
514   ipsec_key_decode (&entry->crypto_key, &crypto_key);
515   ipsec_key_decode (&entry->integrity_key, &integ_key);
516
517   return ipsec_sa_add_and_lock (
518     id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
519     entry->salt, htons (entry->udp_src_port), htons (entry->udp_dst_port), 0,
520     &tun, sa_index);
521 }
522
523 static void
524 vl_api_ipsec_sad_entry_add_del_v3_t_handler (
525   vl_api_ipsec_sad_entry_add_del_v3_t *mp)
526 {
527   vl_api_ipsec_sad_entry_add_del_v3_reply_t *rmp;
528   u32 id, sa_index = ~0;
529   int rv;
530
531   id = ntohl (mp->entry.sad_id);
532
533   if (!mp->is_add)
534     {
535       rv = ipsec_sa_unlock_id (id);
536     }
537   else
538     {
539       rv = ipsec_sad_entry_add_v3 (&mp->entry, &sa_index);
540     }
541
542   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_V3_REPLY,
543                 { rmp->stat_index = htonl (sa_index); });
544 }
545
546 static int
547 ipsec_sad_entry_add_v4 (const vl_api_ipsec_sad_entry_v4_t *entry,
548                         u32 *sa_index)
549 {
550   ipsec_key_t crypto_key, integ_key;
551   ipsec_crypto_alg_t crypto_alg;
552   ipsec_integ_alg_t integ_alg;
553   ipsec_protocol_t proto;
554   ipsec_sa_flags_t flags;
555   u32 id, spi;
556   tunnel_t tun = { 0 };
557   int rv;
558
559   id = ntohl (entry->sad_id);
560   spi = ntohl (entry->spi);
561
562   rv = ipsec_proto_decode (entry->protocol, &proto);
563
564   if (rv)
565     return rv;
566
567   rv = ipsec_crypto_algo_decode (entry->crypto_algorithm, &crypto_alg);
568
569   if (rv)
570     return rv;
571
572   rv = ipsec_integ_algo_decode (entry->integrity_algorithm, &integ_alg);
573
574   if (rv)
575     return rv;
576
577   flags = ipsec_sa_flags_decode (entry->flags);
578
579   if (flags & IPSEC_SA_FLAG_IS_TUNNEL)
580     {
581       rv = tunnel_decode (&entry->tunnel, &tun);
582
583       if (rv)
584         return rv;
585     }
586
587   ipsec_key_decode (&entry->crypto_key, &crypto_key);
588   ipsec_key_decode (&entry->integrity_key, &integ_key);
589
590   return ipsec_sa_add_and_lock (
591     id, spi, proto, crypto_alg, &crypto_key, integ_alg, &integ_key, flags,
592     entry->salt, htons (entry->udp_src_port), htons (entry->udp_dst_port),
593     ntohl (entry->anti_replay_window_size), &tun, sa_index);
594 }
595
596 static void
597 vl_api_ipsec_sad_entry_del_t_handler (vl_api_ipsec_sad_entry_del_t *mp)
598 {
599   vl_api_ipsec_sad_entry_del_reply_t *rmp;
600   int rv;
601
602   rv = ipsec_sa_unlock_id (ntohl (mp->id));
603
604   REPLY_MACRO (VL_API_IPSEC_SAD_ENTRY_DEL_REPLY);
605 }
606
607 static void
608 vl_api_ipsec_sad_entry_add_t_handler (vl_api_ipsec_sad_entry_add_t *mp)
609 {
610   vl_api_ipsec_sad_entry_add_reply_t *rmp;
611   u32 sa_index = ~0;
612   int rv;
613
614   rv = ipsec_sad_entry_add_v3 (&mp->entry, &sa_index);
615
616   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_REPLY,
617                 { rmp->stat_index = htonl (sa_index); });
618 }
619
620 static void
621 vl_api_ipsec_sad_entry_add_v2_t_handler (vl_api_ipsec_sad_entry_add_v2_t *mp)
622 {
623   vl_api_ipsec_sad_entry_add_reply_t *rmp;
624   u32 sa_index = ~0;
625   int rv;
626
627   rv = ipsec_sad_entry_add_v4 (&mp->entry, &sa_index);
628
629   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_V2_REPLY,
630                 { rmp->stat_index = htonl (sa_index); });
631 }
632
633 static void
634 vl_api_ipsec_sad_entry_update_t_handler (vl_api_ipsec_sad_entry_update_t *mp)
635 {
636   vl_api_ipsec_sad_entry_update_reply_t *rmp;
637   u32 id;
638   tunnel_t tun = { 0 };
639   int rv;
640
641   id = ntohl (mp->sad_id);
642
643   if (mp->is_tun)
644     {
645       rv = tunnel_decode (&mp->tunnel, &tun);
646
647       if (rv)
648         goto out;
649     }
650
651   rv = ipsec_sa_update (id, htons (mp->udp_src_port), htons (mp->udp_dst_port),
652                         &tun, mp->is_tun);
653
654 out:
655   REPLY_MACRO (VL_API_IPSEC_SAD_ENTRY_UPDATE_REPLY);
656 }
657
658 static void
659 vl_api_ipsec_sad_bind_t_handler (vl_api_ipsec_sad_bind_t *mp)
660 {
661   vl_api_ipsec_sad_bind_reply_t *rmp;
662   u32 sa_id;
663   u32 worker;
664   int rv;
665
666   sa_id = ntohl (mp->sa_id);
667   worker = ntohl (mp->worker);
668
669   rv = ipsec_sa_bind (sa_id, worker, true /* bind */);
670
671   REPLY_MACRO (VL_API_IPSEC_SAD_BIND_REPLY);
672 }
673
674 static void
675 vl_api_ipsec_sad_unbind_t_handler (vl_api_ipsec_sad_unbind_t *mp)
676 {
677   vl_api_ipsec_sad_unbind_reply_t *rmp;
678   u32 sa_id;
679   int rv;
680
681   sa_id = ntohl (mp->sa_id);
682
683   rv = ipsec_sa_bind (sa_id, ~0, false /* bind */);
684
685   REPLY_MACRO (VL_API_IPSEC_SAD_UNBIND_REPLY);
686 }
687
688 static void
689 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
690                          u32 context)
691 {
692   vl_api_ipsec_spds_details_t *mp;
693   u32 n_policies = 0;
694
695   mp = vl_msg_api_alloc (sizeof (*mp));
696   clib_memset (mp, 0, sizeof (*mp));
697   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SPDS_DETAILS);
698   mp->context = context;
699
700   mp->spd_id = htonl (spd->id);
701 #define _(s, n) n_policies += vec_len (spd->policies[IPSEC_SPD_POLICY_##s]);
702   foreach_ipsec_spd_policy_type
703 #undef _
704     mp->npolicies = htonl (n_policies);
705
706   vl_api_send_msg (reg, (u8 *) mp);
707 }
708
709 static void
710 vl_api_ipsec_spds_dump_t_handler (vl_api_ipsec_spds_dump_t * mp)
711 {
712   vl_api_registration_t *reg;
713   ipsec_main_t *im = &ipsec_main;
714   ipsec_spd_t *spd;
715
716   reg = vl_api_client_index_to_registration (mp->client_index);
717   if (!reg)
718     return;
719
720   pool_foreach (spd, im->spds)  {
721     send_ipsec_spds_details (spd, reg, mp->context);
722   }
723 }
724
725 vl_api_ipsec_spd_action_t
726 ipsec_spd_action_encode (ipsec_policy_action_t in)
727 {
728   vl_api_ipsec_spd_action_t out = IPSEC_API_SPD_ACTION_BYPASS;
729
730   switch (in)
731     {
732 #define _(v,f,s) case IPSEC_POLICY_ACTION_##f: \
733       out = IPSEC_API_SPD_ACTION_##f;          \
734       break;
735       foreach_ipsec_policy_action
736 #undef _
737     }
738   return (clib_host_to_net_u32 (out));
739 }
740
741 static void
742 send_ipsec_spd_details (ipsec_policy_t * p, vl_api_registration_t * reg,
743                         u32 context)
744 {
745   vl_api_ipsec_spd_details_t *mp;
746
747   mp = vl_msg_api_alloc (sizeof (*mp));
748   clib_memset (mp, 0, sizeof (*mp));
749   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SPD_DETAILS);
750   mp->context = context;
751
752   mp->entry.spd_id = htonl (p->id);
753   mp->entry.priority = htonl (p->priority);
754   mp->entry.is_outbound = ((p->type == IPSEC_SPD_POLICY_IP6_OUTBOUND) ||
755                            (p->type == IPSEC_SPD_POLICY_IP4_OUTBOUND));
756
757   ip_address_encode (&p->laddr.start, IP46_TYPE_ANY,
758                      &mp->entry.local_address_start);
759   ip_address_encode (&p->laddr.stop, IP46_TYPE_ANY,
760                      &mp->entry.local_address_stop);
761   ip_address_encode (&p->raddr.start, IP46_TYPE_ANY,
762                      &mp->entry.remote_address_start);
763   ip_address_encode (&p->raddr.stop, IP46_TYPE_ANY,
764                      &mp->entry.remote_address_stop);
765   mp->entry.local_port_start = htons (p->lport.start);
766   mp->entry.local_port_stop = htons (p->lport.stop);
767   mp->entry.remote_port_start = htons (p->rport.start);
768   mp->entry.remote_port_stop = htons (p->rport.stop);
769   mp->entry.protocol = p->protocol;
770   mp->entry.policy = ipsec_spd_action_encode (p->policy);
771   mp->entry.sa_id = htonl (p->sa_id);
772
773   vl_api_send_msg (reg, (u8 *) mp);
774 }
775
776 static void
777 vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp)
778 {
779   vl_api_registration_t *reg;
780   ipsec_main_t *im = &ipsec_main;
781   ipsec_spd_policy_type_t ptype;
782   ipsec_policy_t *policy;
783   ipsec_spd_t *spd;
784   uword *p;
785   u32 spd_index, *ii;
786
787   reg = vl_api_client_index_to_registration (mp->client_index);
788   if (!reg)
789     return;
790
791   p = hash_get (im->spd_index_by_spd_id, ntohl (mp->spd_id));
792   if (!p)
793     return;
794
795   spd_index = p[0];
796   spd = pool_elt_at_index (im->spds, spd_index);
797
798   FOR_EACH_IPSEC_SPD_POLICY_TYPE(ptype) {
799     vec_foreach(ii, spd->policies[ptype])
800       {
801         policy = pool_elt_at_index(im->policies, *ii);
802
803         if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == policy->sa_id)
804           send_ipsec_spd_details (policy, reg, mp->context);
805       }
806   }
807 }
808
809 static void
810 send_ipsec_spd_interface_details (vl_api_registration_t * reg, u32 spd_index,
811                                   u32 sw_if_index, u32 context)
812 {
813   vl_api_ipsec_spd_interface_details_t *mp;
814
815   mp = vl_msg_api_alloc (sizeof (*mp));
816   clib_memset (mp, 0, sizeof (*mp));
817   mp->_vl_msg_id =
818     ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SPD_INTERFACE_DETAILS);
819   mp->context = context;
820
821   mp->spd_index = htonl (spd_index);
822   mp->sw_if_index = htonl (sw_if_index);
823
824   vl_api_send_msg (reg, (u8 *) mp);
825 }
826
827 static void
828 vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t *
829                                            mp)
830 {
831   ipsec_main_t *im = &ipsec_main;
832   vl_api_registration_t *reg;
833   u32 k, v, spd_index;
834
835   reg = vl_api_client_index_to_registration (mp->client_index);
836   if (!reg)
837     return;
838
839   if (mp->spd_index_valid)
840     {
841       spd_index = ntohl (mp->spd_index);
842       /* *INDENT-OFF* */
843       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
844         if (v == spd_index)
845           send_ipsec_spd_interface_details(reg, v, k, mp->context);
846       }));
847       /* *INDENT-ON* */
848     }
849   else
850     {
851       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
852         send_ipsec_spd_interface_details(reg, v, k, mp->context);
853       }));
854     }
855 }
856
857 static void
858 vl_api_ipsec_itf_create_t_handler (vl_api_ipsec_itf_create_t * mp)
859 {
860   vl_api_ipsec_itf_create_reply_t *rmp;
861   tunnel_mode_t mode;
862   u32 sw_if_index = ~0;
863   int rv;
864
865   rv = tunnel_mode_decode (mp->itf.mode, &mode);
866
867   if (!rv)
868     rv = ipsec_itf_create (ntohl (mp->itf.user_instance), mode, &sw_if_index);
869
870   /* *INDENT-OFF* */
871   REPLY_MACRO2 (VL_API_IPSEC_ITF_CREATE_REPLY,
872   ({
873     rmp->sw_if_index = htonl (sw_if_index);
874   }));
875   /* *INDENT-ON* */
876 }
877
878 static void
879 vl_api_ipsec_itf_delete_t_handler (vl_api_ipsec_itf_delete_t * mp)
880 {
881   vl_api_ipsec_itf_delete_reply_t *rmp;
882   int rv;
883
884   rv = ipsec_itf_delete (ntohl (mp->sw_if_index));
885
886   REPLY_MACRO (VL_API_IPSEC_ITF_DELETE_REPLY);
887 }
888
889 static walk_rc_t
890 send_ipsec_itf_details (ipsec_itf_t *itf, void *arg)
891 {
892   ipsec_dump_walk_ctx_t *ctx = arg;
893   vl_api_ipsec_itf_details_t *mp;
894
895   if (~0 != ctx->sw_if_index && ctx->sw_if_index != itf->ii_sw_if_index)
896     return (WALK_CONTINUE);
897
898   mp = vl_msg_api_alloc (sizeof (*mp));
899   clib_memset (mp, 0, sizeof (*mp));
900   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_ITF_DETAILS);
901   mp->context = ctx->context;
902
903   mp->itf.mode = tunnel_mode_encode (itf->ii_mode);
904   mp->itf.user_instance = htonl (itf->ii_user_instance);
905   mp->itf.sw_if_index = htonl (itf->ii_sw_if_index);
906   vl_api_send_msg (ctx->reg, (u8 *) mp);
907
908   return (WALK_CONTINUE);
909 }
910
911 static void
912 vl_api_ipsec_itf_dump_t_handler (vl_api_ipsec_itf_dump_t * mp)
913 {
914   vl_api_registration_t *reg;
915
916   reg = vl_api_client_index_to_registration (mp->client_index);
917   if (!reg)
918     return;
919
920   ipsec_dump_walk_ctx_t ctx = {
921     .reg = reg,
922     .context = mp->context,
923     .sw_if_index = ntohl (mp->sw_if_index),
924   };
925
926   ipsec_itf_walk (send_ipsec_itf_details, &ctx);
927 }
928
929 typedef struct ipsec_sa_dump_match_ctx_t_
930 {
931   index_t sai;
932   u32 sw_if_index;
933 } ipsec_sa_dump_match_ctx_t;
934
935 static walk_rc_t
936 ipsec_sa_dump_match_sa (index_t itpi, void *arg)
937 {
938   ipsec_sa_dump_match_ctx_t *ctx = arg;
939   ipsec_tun_protect_t *itp;
940   index_t sai;
941
942   itp = ipsec_tun_protect_get (itpi);
943
944   if (itp->itp_out_sa == ctx->sai)
945     {
946       ctx->sw_if_index = itp->itp_sw_if_index;
947       return (WALK_STOP);
948     }
949
950   FOR_EACH_IPSEC_PROTECT_INPUT_SAI (itp, sai,
951   ({
952     if (sai == ctx->sai)
953       {
954         ctx->sw_if_index = itp->itp_sw_if_index;
955         return (WALK_STOP);
956       }
957   }));
958
959   return (WALK_CONTINUE);
960 }
961
962 static walk_rc_t
963 send_ipsec_sa_details (ipsec_sa_t * sa, void *arg)
964 {
965   ipsec_dump_walk_ctx_t *ctx = arg;
966   vl_api_ipsec_sa_details_t *mp;
967
968   mp = vl_msg_api_alloc (sizeof (*mp));
969   clib_memset (mp, 0, sizeof (*mp));
970   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_DETAILS);
971   mp->context = ctx->context;
972
973   mp->entry.sad_id = htonl (sa->id);
974   mp->entry.spi = htonl (sa->spi);
975   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
976   mp->entry.tx_table_id = htonl (sa->tunnel.t_table_id);
977
978   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
979   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
980
981   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
982   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
983
984   mp->entry.flags = ipsec_sad_flags_encode (sa);
985   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
986
987   if (ipsec_sa_is_set_IS_PROTECT (sa))
988     {
989       ipsec_sa_dump_match_ctx_t ctx = {
990         .sai = sa - ipsec_sa_pool,
991         .sw_if_index = ~0,
992       };
993       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
994
995       mp->sw_if_index = htonl (ctx.sw_if_index);
996     }
997   else
998     mp->sw_if_index = ~0;
999
1000   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1001     {
1002       ip_address_encode2 (&sa->tunnel.t_src, &mp->entry.tunnel_src);
1003       ip_address_encode2 (&sa->tunnel.t_dst, &mp->entry.tunnel_dst);
1004     }
1005   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1006     {
1007       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1008       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1009     }
1010
1011   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1012   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
1013   if (ipsec_sa_is_set_USE_ESN (sa))
1014     {
1015       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1016       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1017     }
1018   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1019     {
1020       mp->replay_window =
1021         clib_host_to_net_u64 (ipsec_sa_anti_replay_get_64b_window (sa));
1022     }
1023
1024   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1025
1026   vl_api_send_msg (ctx->reg, (u8 *) mp);
1027
1028   return (WALK_CONTINUE);
1029 }
1030
1031 static void
1032 vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp)
1033 {
1034   vl_api_registration_t *reg;
1035
1036   reg = vl_api_client_index_to_registration (mp->client_index);
1037   if (!reg)
1038     return;
1039
1040   ipsec_dump_walk_ctx_t ctx = {
1041     .reg = reg,
1042     .context = mp->context,
1043   };
1044
1045   ipsec_sa_walk (send_ipsec_sa_details, &ctx);
1046 }
1047
1048 static walk_rc_t
1049 send_ipsec_sa_v2_details (ipsec_sa_t * sa, void *arg)
1050 {
1051   ipsec_dump_walk_ctx_t *ctx = arg;
1052   vl_api_ipsec_sa_v2_details_t *mp;
1053
1054   mp = vl_msg_api_alloc (sizeof (*mp));
1055   clib_memset (mp, 0, sizeof (*mp));
1056   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V2_DETAILS);
1057   mp->context = ctx->context;
1058
1059   mp->entry.sad_id = htonl (sa->id);
1060   mp->entry.spi = htonl (sa->spi);
1061   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
1062   mp->entry.tx_table_id = htonl (sa->tunnel.t_table_id);
1063
1064   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
1065   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
1066
1067   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
1068   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
1069
1070   mp->entry.flags = ipsec_sad_flags_encode (sa);
1071   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
1072
1073   if (ipsec_sa_is_set_IS_PROTECT (sa))
1074     {
1075       ipsec_sa_dump_match_ctx_t ctx = {
1076         .sai = sa - ipsec_sa_pool,
1077         .sw_if_index = ~0,
1078       };
1079       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
1080
1081       mp->sw_if_index = htonl (ctx.sw_if_index);
1082     }
1083   else
1084     mp->sw_if_index = ~0;
1085
1086   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1087     {
1088       ip_address_encode2 (&sa->tunnel.t_src, &mp->entry.tunnel_src);
1089       ip_address_encode2 (&sa->tunnel.t_dst, &mp->entry.tunnel_dst);
1090     }
1091   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1092     {
1093       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1094       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1095     }
1096
1097   mp->entry.tunnel_flags =
1098     tunnel_encap_decap_flags_encode (sa->tunnel.t_encap_decap_flags);
1099   mp->entry.dscp = ip_dscp_encode (sa->tunnel.t_dscp);
1100
1101   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1102   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
1103   if (ipsec_sa_is_set_USE_ESN (sa))
1104     {
1105       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1106       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1107     }
1108   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1109     {
1110       mp->replay_window =
1111         clib_host_to_net_u64 (ipsec_sa_anti_replay_get_64b_window (sa));
1112     }
1113
1114   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1115
1116   vl_api_send_msg (ctx->reg, (u8 *) mp);
1117
1118   return (WALK_CONTINUE);
1119 }
1120
1121 static void
1122 vl_api_ipsec_sa_v2_dump_t_handler (vl_api_ipsec_sa_v2_dump_t *mp)
1123 {
1124   vl_api_registration_t *reg;
1125
1126   reg = vl_api_client_index_to_registration (mp->client_index);
1127   if (!reg)
1128     return;
1129
1130   ipsec_dump_walk_ctx_t ctx = {
1131     .reg = reg,
1132     .context = mp->context,
1133   };
1134
1135   ipsec_sa_walk (send_ipsec_sa_v2_details, &ctx);
1136 }
1137
1138 static walk_rc_t
1139 send_ipsec_sa_v3_details (ipsec_sa_t *sa, void *arg)
1140 {
1141   ipsec_dump_walk_ctx_t *ctx = arg;
1142   vl_api_ipsec_sa_v3_details_t *mp;
1143
1144   mp = vl_msg_api_alloc (sizeof (*mp));
1145   clib_memset (mp, 0, sizeof (*mp));
1146   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V3_DETAILS);
1147   mp->context = ctx->context;
1148
1149   mp->entry.sad_id = htonl (sa->id);
1150   mp->entry.spi = htonl (sa->spi);
1151   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
1152
1153   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
1154   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
1155
1156   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
1157   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
1158
1159   mp->entry.flags = ipsec_sad_flags_encode (sa);
1160   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
1161
1162   if (ipsec_sa_is_set_IS_PROTECT (sa))
1163     {
1164       ipsec_sa_dump_match_ctx_t ctx = {
1165         .sai = sa - ipsec_sa_pool,
1166         .sw_if_index = ~0,
1167       };
1168       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
1169
1170       mp->sw_if_index = htonl (ctx.sw_if_index);
1171     }
1172   else
1173     mp->sw_if_index = ~0;
1174
1175   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1176     tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
1177
1178   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1179     {
1180       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1181       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1182     }
1183
1184   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1185   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
1186   if (ipsec_sa_is_set_USE_ESN (sa))
1187     {
1188       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1189       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1190     }
1191   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1192     {
1193       mp->replay_window =
1194         clib_host_to_net_u64 (ipsec_sa_anti_replay_get_64b_window (sa));
1195     }
1196
1197   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1198
1199   vl_api_send_msg (ctx->reg, (u8 *) mp);
1200
1201   return (WALK_CONTINUE);
1202 }
1203
1204 static void
1205 vl_api_ipsec_sa_v3_dump_t_handler (vl_api_ipsec_sa_v3_dump_t *mp)
1206 {
1207   vl_api_registration_t *reg;
1208
1209   reg = vl_api_client_index_to_registration (mp->client_index);
1210   if (!reg)
1211     return;
1212
1213   ipsec_dump_walk_ctx_t ctx = {
1214     .reg = reg,
1215     .context = mp->context,
1216   };
1217
1218   ipsec_sa_walk (send_ipsec_sa_v3_details, &ctx);
1219 }
1220
1221 static walk_rc_t
1222 send_ipsec_sa_v4_details (ipsec_sa_t *sa, void *arg)
1223 {
1224   ipsec_dump_walk_ctx_t *ctx = arg;
1225   vl_api_ipsec_sa_v4_details_t *mp;
1226
1227   mp = vl_msg_api_alloc (sizeof (*mp));
1228   clib_memset (mp, 0, sizeof (*mp));
1229   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V4_DETAILS);
1230   mp->context = ctx->context;
1231
1232   mp->entry.sad_id = htonl (sa->id);
1233   mp->entry.spi = htonl (sa->spi);
1234   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
1235
1236   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
1237   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
1238
1239   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
1240   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
1241
1242   mp->entry.flags = ipsec_sad_flags_encode (sa);
1243   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
1244
1245   if (ipsec_sa_is_set_IS_PROTECT (sa))
1246     {
1247       ipsec_sa_dump_match_ctx_t ctx = {
1248         .sai = sa - ipsec_sa_pool,
1249         .sw_if_index = ~0,
1250       };
1251       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
1252
1253       mp->sw_if_index = htonl (ctx.sw_if_index);
1254     }
1255   else
1256     mp->sw_if_index = ~0;
1257
1258   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1259     tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
1260
1261   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1262     {
1263       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1264       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1265     }
1266
1267   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1268   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
1269   if (ipsec_sa_is_set_USE_ESN (sa))
1270     {
1271       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1272       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1273     }
1274   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1275     {
1276       mp->replay_window =
1277         clib_host_to_net_u64 (ipsec_sa_anti_replay_get_64b_window (sa));
1278     }
1279
1280   mp->thread_index = clib_host_to_net_u32 (sa->thread_index);
1281   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1282
1283   vl_api_send_msg (ctx->reg, (u8 *) mp);
1284
1285   return (WALK_CONTINUE);
1286 }
1287
1288 static void
1289 vl_api_ipsec_sa_v4_dump_t_handler (vl_api_ipsec_sa_v4_dump_t *mp)
1290 {
1291   vl_api_registration_t *reg;
1292
1293   reg = vl_api_client_index_to_registration (mp->client_index);
1294   if (!reg)
1295     return;
1296
1297   ipsec_dump_walk_ctx_t ctx = {
1298     .reg = reg,
1299     .context = mp->context,
1300   };
1301
1302   ipsec_sa_walk (send_ipsec_sa_v4_details, &ctx);
1303 }
1304
1305 static walk_rc_t
1306 send_ipsec_sa_v5_details (ipsec_sa_t *sa, void *arg)
1307 {
1308   ipsec_dump_walk_ctx_t *ctx = arg;
1309   vl_api_ipsec_sa_v5_details_t *mp;
1310
1311   mp = vl_msg_api_alloc (sizeof (*mp));
1312   clib_memset (mp, 0, sizeof (*mp));
1313   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V5_DETAILS);
1314   mp->context = ctx->context;
1315
1316   mp->entry.sad_id = htonl (sa->id);
1317   mp->entry.spi = htonl (sa->spi);
1318   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
1319
1320   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
1321   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
1322
1323   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
1324   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
1325
1326   mp->entry.flags = ipsec_sad_flags_encode (sa);
1327   mp->entry.salt = clib_host_to_net_u32 (sa->salt);
1328
1329   if (ipsec_sa_is_set_IS_PROTECT (sa))
1330     {
1331       ipsec_sa_dump_match_ctx_t ctx = {
1332         .sai = sa - ipsec_sa_pool,
1333         .sw_if_index = ~0,
1334       };
1335       ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
1336
1337       mp->sw_if_index = htonl (ctx.sw_if_index);
1338     }
1339   else
1340     mp->sw_if_index = ~0;
1341
1342   if (ipsec_sa_is_set_IS_TUNNEL (sa))
1343     tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
1344
1345   if (ipsec_sa_is_set_UDP_ENCAP (sa))
1346     {
1347       mp->entry.udp_src_port = sa->udp_hdr.src_port;
1348       mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
1349     }
1350
1351   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
1352   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
1353   if (ipsec_sa_is_set_USE_ESN (sa))
1354     {
1355       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1356       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
1357     }
1358   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
1359     {
1360       mp->replay_window =
1361         clib_host_to_net_u64 (ipsec_sa_anti_replay_get_64b_window (sa));
1362
1363       mp->entry.anti_replay_window_size =
1364         clib_host_to_net_u32 (IPSEC_SA_ANTI_REPLAY_WINDOW_SIZE (sa));
1365     }
1366
1367   mp->thread_index = clib_host_to_net_u32 (sa->thread_index);
1368   mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
1369
1370   vl_api_send_msg (ctx->reg, (u8 *) mp);
1371
1372   return (WALK_CONTINUE);
1373 }
1374
1375 static void
1376 vl_api_ipsec_sa_v5_dump_t_handler (vl_api_ipsec_sa_v5_dump_t *mp)
1377 {
1378   vl_api_registration_t *reg;
1379
1380   reg = vl_api_client_index_to_registration (mp->client_index);
1381   if (!reg)
1382     return;
1383
1384   ipsec_dump_walk_ctx_t ctx = {
1385     .reg = reg,
1386     .context = mp->context,
1387   };
1388
1389   ipsec_sa_walk (send_ipsec_sa_v5_details, &ctx);
1390 }
1391
1392 static void
1393 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t *mp)
1394 {
1395   vl_api_registration_t *rp;
1396   ipsec_main_t *im = &ipsec_main;
1397   u32 context = mp->context;
1398
1399   rp = vl_api_client_index_to_registration (mp->client_index);
1400
1401   if (rp == 0)
1402     {
1403       clib_warning ("Client %d AWOL", mp->client_index);
1404       return;
1405     }
1406
1407   ipsec_ah_backend_t *ab;
1408   ipsec_esp_backend_t *eb;
1409   /* *INDENT-OFF* */
1410   pool_foreach (ab, im->ah_backends) {
1411     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
1412     clib_memset (mp, 0, sizeof (*mp));
1413     mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_BACKEND_DETAILS);
1414     mp->context = context;
1415     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
1416               ab->name);
1417     mp->protocol = ntohl (IPSEC_API_PROTO_AH);
1418     mp->index = ab - im->ah_backends;
1419     mp->active = mp->index == im->ah_current_backend ? 1 : 0;
1420     vl_api_send_msg (rp, (u8 *)mp);
1421   }
1422   pool_foreach (eb, im->esp_backends) {
1423     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
1424     clib_memset (mp, 0, sizeof (*mp));
1425     mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_BACKEND_DETAILS);
1426     mp->context = context;
1427     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
1428               eb->name);
1429     mp->protocol = ntohl (IPSEC_API_PROTO_ESP);
1430     mp->index = eb - im->esp_backends;
1431     mp->active = mp->index == im->esp_current_backend ? 1 : 0;
1432     vl_api_send_msg (rp, (u8 *)mp);
1433   }
1434   /* *INDENT-ON* */
1435 }
1436
1437 static void
1438 vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
1439 {
1440   ipsec_main_t *im = &ipsec_main;
1441   vl_api_ipsec_select_backend_reply_t *rmp;
1442   ipsec_protocol_t protocol;
1443   int rv = 0;
1444   if (pool_elts (ipsec_sa_pool) > 0)
1445     {
1446       rv = VNET_API_ERROR_INSTANCE_IN_USE;
1447       goto done;
1448     }
1449
1450   rv = ipsec_proto_decode (mp->protocol, &protocol);
1451
1452   if (rv)
1453     goto done;
1454
1455   switch (protocol)
1456     {
1457     case IPSEC_PROTOCOL_ESP:
1458       rv = ipsec_select_esp_backend (im, mp->index);
1459       break;
1460     case IPSEC_PROTOCOL_AH:
1461       rv = ipsec_select_ah_backend (im, mp->index);
1462       break;
1463     default:
1464       rv = VNET_API_ERROR_INVALID_PROTOCOL;
1465       break;
1466     }
1467 done:
1468   REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
1469 }
1470
1471 static void
1472 vl_api_ipsec_set_async_mode_t_handler (vl_api_ipsec_set_async_mode_t * mp)
1473 {
1474   vl_api_ipsec_set_async_mode_reply_t *rmp;
1475   int rv = 0;
1476
1477   ipsec_set_async_mode (mp->async_enable);
1478
1479   REPLY_MACRO (VL_API_IPSEC_SET_ASYNC_MODE_REPLY);
1480 }
1481
1482 #include <vnet/ipsec/ipsec.api.c>
1483 static clib_error_t *
1484 ipsec_api_hookup (vlib_main_t * vm)
1485 {
1486   /*
1487    * Set up the (msg_name, crc, message-id) table
1488    */
1489   REPLY_MSG_ID_BASE = setup_message_id_table ();
1490
1491   return 0;
1492 }
1493
1494 VLIB_API_INIT_FUNCTION (ipsec_api_hookup);
1495
1496 /*
1497  * fd.io coding-style-patch-verification: ON
1498  *
1499  * Local Variables:
1500  * eval: (c-set-style "gnu")
1501  * End:
1502  */