ipsec: perf improvement of ipsec4_input_node using flow cache
[vpp.git] / src / vnet / ipsec / ipsec.c
1 /*
2  * ipsec.c : IPSEC module functions
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/interface.h>
22 #include <vnet/udp/udp_local.h>
23
24 #include <vnet/ipsec/ipsec.h>
25 #include <vnet/ipsec/esp.h>
26 #include <vnet/ipsec/ah.h>
27 #include <vnet/ipsec/ipsec_tun.h>
28 #include <vnet/ipsec/ipsec_itf.h>
29
30 /* Flow cache is sized for 1 million flows with a load factor of .25.
31  */
32 #define IPSEC4_OUT_SPD_DEFAULT_HASH_NUM_BUCKETS (1 << 22)
33
34 /* Flow cache is sized for 1 million flows with a load factor of .25.
35  */
36 #define IPSEC4_SPD_DEFAULT_HASH_NUM_BUCKETS (1 << 22)
37
38 ipsec_main_t ipsec_main;
39 esp_async_post_next_t esp_encrypt_async_next;
40 esp_async_post_next_t esp_decrypt_async_next;
41
42 static clib_error_t *
43 ipsec_check_ah_support (ipsec_sa_t * sa)
44 {
45   ipsec_main_t *im = &ipsec_main;
46
47   if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
48     return clib_error_return (0, "unsupported none integ-alg");
49
50   if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
51     return clib_error_return (0, "No crypto engine support for %U",
52                               format_ipsec_integ_alg, sa->integ_alg);
53
54   return 0;
55 }
56
57 static clib_error_t *
58 ipsec_check_esp_support (ipsec_sa_t * sa)
59 {
60   ipsec_main_t *im = &ipsec_main;
61
62   if (IPSEC_INTEG_ALG_NONE != sa->integ_alg)
63     {
64       if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
65         return clib_error_return (0, "No crypto engine support for %U",
66                                   format_ipsec_integ_alg, sa->integ_alg);
67     }
68   if (IPSEC_CRYPTO_ALG_NONE != sa->crypto_alg)
69     {
70       if (!vnet_crypto_is_set_handler (im->crypto_algs[sa->crypto_alg].alg))
71         return clib_error_return (0, "No crypto engine support for %U",
72                                   format_ipsec_crypto_alg, sa->crypto_alg);
73     }
74
75   return (0);
76 }
77
78 clib_error_t *
79 ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index, u8 is_add)
80 {
81   ipsec_ah_backend_t *ah =
82     pool_elt_at_index (im->ah_backends, im->ah_current_backend);
83   if (ah->add_del_sa_sess_cb)
84     {
85       clib_error_t *err = ah->add_del_sa_sess_cb (sa_index, is_add);
86       if (err)
87         return err;
88     }
89   ipsec_esp_backend_t *esp =
90     pool_elt_at_index (im->esp_backends, im->esp_current_backend);
91   if (esp->add_del_sa_sess_cb)
92     {
93       clib_error_t *err = esp->add_del_sa_sess_cb (sa_index, is_add);
94       if (err)
95         return err;
96     }
97   return 0;
98 }
99
100 clib_error_t *
101 ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa)
102 {
103   clib_error_t *error = 0;
104
105   if (PREDICT_FALSE (sa->protocol == IPSEC_PROTOCOL_AH))
106     {
107       ipsec_ah_backend_t *ah =
108         pool_elt_at_index (im->ah_backends, im->ah_current_backend);
109       ASSERT (ah->check_support_cb);
110       error = ah->check_support_cb (sa);
111     }
112   else
113     {
114       ipsec_esp_backend_t *esp =
115         pool_elt_at_index (im->esp_backends, im->esp_current_backend);
116       ASSERT (esp->check_support_cb);
117       error = esp->check_support_cb (sa);
118     }
119   return error;
120 }
121
122
123 static void
124 ipsec_add_node (vlib_main_t * vm, const char *node_name,
125                 const char *prev_node_name, u32 * out_node_index,
126                 u32 * out_next_index)
127 {
128   vlib_node_t *prev_node, *node;
129   prev_node = vlib_get_node_by_name (vm, (u8 *) prev_node_name);
130   ASSERT (prev_node);
131   node = vlib_get_node_by_name (vm, (u8 *) node_name);
132   ASSERT (node);
133   *out_node_index = node->index;
134   *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index);
135 }
136
137 void
138 ipsec_unregister_udp_port (u16 port)
139 {
140   ipsec_main_t *im = &ipsec_main;
141   u32 n_regs;
142   uword *p;
143
144   p = hash_get (im->udp_port_registrations, port);
145
146   ASSERT (p);
147
148   n_regs = p[0];
149
150   if (0 == --n_regs)
151     {
152       udp_unregister_dst_port (vlib_get_main (), port, 1);
153       hash_unset (im->udp_port_registrations, port);
154     }
155   else
156     {
157       hash_unset (im->udp_port_registrations, port);
158       hash_set (im->udp_port_registrations, port, n_regs);
159     }
160 }
161
162 void
163 ipsec_register_udp_port (u16 port)
164 {
165   ipsec_main_t *im = &ipsec_main;
166   u32 n_regs;
167   uword *p;
168
169   p = hash_get (im->udp_port_registrations, port);
170
171   n_regs = (p ? p[0] : 0);
172
173   if (0 == n_regs++)
174     udp_register_dst_port (vlib_get_main (), port,
175                            ipsec4_tun_input_node.index, 1);
176
177   hash_unset (im->udp_port_registrations, port);
178   hash_set (im->udp_port_registrations, port, n_regs);
179 }
180
181 u32
182 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
183                            const char *name,
184                            const char *ah4_encrypt_node_name,
185                            const char *ah4_decrypt_node_name,
186                            const char *ah6_encrypt_node_name,
187                            const char *ah6_decrypt_node_name,
188                            check_support_cb_t ah_check_support_cb,
189                            add_del_sa_sess_cb_t ah_add_del_sa_sess_cb)
190 {
191   ipsec_ah_backend_t *b;
192   pool_get (im->ah_backends, b);
193   b->name = format (0, "%s%c", name, 0);
194
195   ipsec_add_node (vm, ah4_encrypt_node_name, "ipsec4-output-feature",
196                   &b->ah4_encrypt_node_index, &b->ah4_encrypt_next_index);
197   ipsec_add_node (vm, ah4_decrypt_node_name, "ipsec4-input-feature",
198                   &b->ah4_decrypt_node_index, &b->ah4_decrypt_next_index);
199   ipsec_add_node (vm, ah6_encrypt_node_name, "ipsec6-output-feature",
200                   &b->ah6_encrypt_node_index, &b->ah6_encrypt_next_index);
201   ipsec_add_node (vm, ah6_decrypt_node_name, "ipsec6-input-feature",
202                   &b->ah6_decrypt_node_index, &b->ah6_decrypt_next_index);
203
204   b->check_support_cb = ah_check_support_cb;
205   b->add_del_sa_sess_cb = ah_add_del_sa_sess_cb;
206   return b - im->ah_backends;
207 }
208
209 u32
210 ipsec_register_esp_backend (
211   vlib_main_t *vm, ipsec_main_t *im, const char *name,
212   const char *esp4_encrypt_node_name, const char *esp4_encrypt_node_tun_name,
213   const char *esp4_decrypt_node_name, const char *esp4_decrypt_tun_node_name,
214   const char *esp6_encrypt_node_name, const char *esp6_encrypt_node_tun_name,
215   const char *esp6_decrypt_node_name, const char *esp6_decrypt_tun_node_name,
216   const char *esp_mpls_encrypt_node_tun_name,
217   check_support_cb_t esp_check_support_cb,
218   add_del_sa_sess_cb_t esp_add_del_sa_sess_cb,
219   enable_disable_cb_t enable_disable_cb)
220 {
221   ipsec_esp_backend_t *b;
222
223   pool_get (im->esp_backends, b);
224   b->name = format (0, "%s%c", name, 0);
225
226   ipsec_add_node (vm, esp4_encrypt_node_name, "ipsec4-output-feature",
227                   &b->esp4_encrypt_node_index, &b->esp4_encrypt_next_index);
228   ipsec_add_node (vm, esp4_decrypt_node_name, "ipsec4-input-feature",
229                   &b->esp4_decrypt_node_index, &b->esp4_decrypt_next_index);
230   ipsec_add_node (vm, esp6_encrypt_node_name, "ipsec6-output-feature",
231                   &b->esp6_encrypt_node_index, &b->esp6_encrypt_next_index);
232   ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input-feature",
233                   &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
234   ipsec_add_node (vm, esp4_decrypt_tun_node_name, "ipsec4-tun-input",
235                   &b->esp4_decrypt_tun_node_index,
236                   &b->esp4_decrypt_tun_next_index);
237   ipsec_add_node (vm, esp6_decrypt_tun_node_name, "ipsec6-tun-input",
238                   &b->esp6_decrypt_tun_node_index,
239                   &b->esp6_decrypt_tun_next_index);
240
241   b->esp6_encrypt_tun_node_index =
242     vlib_get_node_by_name (vm, (u8 *) esp6_encrypt_node_tun_name)->index;
243   b->esp_mpls_encrypt_tun_node_index =
244     vlib_get_node_by_name (vm, (u8 *) esp_mpls_encrypt_node_tun_name)->index;
245   b->esp4_encrypt_tun_node_index =
246     vlib_get_node_by_name (vm, (u8 *) esp4_encrypt_node_tun_name)->index;
247
248   b->check_support_cb = esp_check_support_cb;
249   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
250   b->enable_disable_cb = enable_disable_cb;
251
252   return b - im->esp_backends;
253 }
254
255 clib_error_t *
256 ipsec_rsc_in_use (ipsec_main_t * im)
257 {
258   /* return an error is crypto resource are in use */
259   if (pool_elts (ipsec_sa_pool) > 0)
260     return clib_error_return (0, "%d SA entries configured",
261                               pool_elts (ipsec_sa_pool));
262   if (ipsec_itf_count () > 0)
263     return clib_error_return (0, "%d IPSec interface configured",
264                               ipsec_itf_count ());
265
266   return (NULL);
267 }
268
269 int
270 ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
271 {
272   if (ipsec_rsc_in_use (im))
273     return VNET_API_ERROR_RSRC_IN_USE;
274
275   if (pool_is_free_index (im->ah_backends, backend_idx))
276     return VNET_API_ERROR_INVALID_VALUE;
277
278   ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
279   im->ah_current_backend = backend_idx;
280   im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
281   im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
282   im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
283   im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
284   im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
285   im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
286   im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
287   im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
288
289   return 0;
290 }
291
292 int
293 ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
294 {
295   if (ipsec_rsc_in_use (im))
296     return VNET_API_ERROR_RSRC_IN_USE;
297
298   if (pool_is_free_index (im->esp_backends, backend_idx))
299     return VNET_API_ERROR_INVALID_VALUE;
300
301   /* disable current backend */
302   if (im->esp_current_backend != ~0)
303     {
304       ipsec_esp_backend_t *cb = pool_elt_at_index (im->esp_backends,
305                                                    im->esp_current_backend);
306       if (cb->enable_disable_cb)
307         {
308           if ((cb->enable_disable_cb) (0) != 0)
309             return -1;
310         }
311     }
312
313   ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
314   im->esp_current_backend = backend_idx;
315   im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
316   im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
317   im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
318   im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
319   im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
320   im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
321   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
322   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
323   im->esp4_decrypt_tun_node_index = b->esp4_decrypt_tun_node_index;
324   im->esp4_decrypt_tun_next_index = b->esp4_decrypt_tun_next_index;
325   im->esp6_decrypt_tun_node_index = b->esp6_decrypt_tun_node_index;
326   im->esp6_decrypt_tun_next_index = b->esp6_decrypt_tun_next_index;
327   im->esp4_encrypt_tun_node_index = b->esp4_encrypt_tun_node_index;
328   im->esp6_encrypt_tun_node_index = b->esp6_encrypt_tun_node_index;
329   im->esp_mpls_encrypt_tun_node_index = b->esp_mpls_encrypt_tun_node_index;
330
331   if (b->enable_disable_cb)
332     {
333       if ((b->enable_disable_cb) (1) != 0)
334         return -1;
335     }
336   return 0;
337 }
338
339 void
340 ipsec_set_async_mode (u32 is_enabled)
341 {
342   ipsec_main_t *im = &ipsec_main;
343   ipsec_sa_t *sa;
344
345   vnet_crypto_request_async_mode (is_enabled);
346
347   im->async_mode = is_enabled;
348
349   /* change SA crypto op data */
350   pool_foreach (sa, ipsec_sa_pool)
351     {
352       sa->crypto_op_data =
353         (is_enabled ? sa->async_op_data.data : sa->sync_op_data.data);
354     }
355 }
356
357 static void
358 crypto_engine_backend_register_post_node (vlib_main_t * vm)
359 {
360   esp_async_post_next_t *eit;
361   esp_async_post_next_t *dit;
362
363   eit = &esp_encrypt_async_next;
364   eit->esp4_post_next =
365     vnet_crypto_register_post_node (vm, "esp4-encrypt-post");
366   eit->esp6_post_next =
367     vnet_crypto_register_post_node (vm, "esp6-encrypt-post");
368   eit->esp4_tun_post_next =
369     vnet_crypto_register_post_node (vm, "esp4-encrypt-tun-post");
370   eit->esp6_tun_post_next =
371     vnet_crypto_register_post_node (vm, "esp6-encrypt-tun-post");
372   eit->esp_mpls_tun_post_next =
373     vnet_crypto_register_post_node (vm, "esp-mpls-encrypt-tun-post");
374
375   dit = &esp_decrypt_async_next;
376   dit->esp4_post_next =
377     vnet_crypto_register_post_node (vm, "esp4-decrypt-post");
378   dit->esp6_post_next =
379     vnet_crypto_register_post_node (vm, "esp6-decrypt-post");
380   dit->esp4_tun_post_next =
381     vnet_crypto_register_post_node (vm, "esp4-decrypt-tun-post");
382   dit->esp6_tun_post_next =
383     vnet_crypto_register_post_node (vm, "esp6-decrypt-tun-post");
384 }
385
386 static clib_error_t *
387 ipsec_init (vlib_main_t * vm)
388 {
389   clib_error_t *error;
390   ipsec_main_t *im = &ipsec_main;
391   ipsec_main_crypto_alg_t *a;
392
393   /* Backend registration requires the feature arcs to be set up */
394   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
395     return (error);
396
397   im->vnet_main = vnet_get_main ();
398   im->vlib_main = vm;
399
400   im->spd_index_by_spd_id = hash_create (0, sizeof (uword));
401   im->sa_index_by_sa_id = hash_create (0, sizeof (uword));
402   im->spd_index_by_sw_if_index = hash_create (0, sizeof (uword));
403
404   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
405   ASSERT (node);
406   im->error_drop_node_index = node->index;
407
408   im->ah_current_backend = ~0;
409   im->esp_current_backend = ~0;
410
411   u32 idx = ipsec_register_ah_backend (vm, im, "crypto engine backend",
412                                        "ah4-encrypt",
413                                        "ah4-decrypt",
414                                        "ah6-encrypt",
415                                        "ah6-decrypt",
416                                        ipsec_check_ah_support,
417                                        NULL);
418
419   im->ah_default_backend = idx;
420   int rv = ipsec_select_ah_backend (im, idx);
421   ASSERT (0 == rv);
422   (void) (rv);                  // avoid warning
423
424   idx = ipsec_register_esp_backend (
425     vm, im, "crypto engine backend", "esp4-encrypt", "esp4-encrypt-tun",
426     "esp4-decrypt", "esp4-decrypt-tun", "esp6-encrypt", "esp6-encrypt-tun",
427     "esp6-decrypt", "esp6-decrypt-tun", "esp-mpls-encrypt-tun",
428     ipsec_check_esp_support, NULL, crypto_dispatch_enable_disable);
429   im->esp_default_backend = idx;
430
431   rv = ipsec_select_esp_backend (im, idx);
432   ASSERT (0 == rv);
433   (void) (rv);                  // avoid warning
434
435   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
436     return error;
437
438   vec_validate (im->crypto_algs, IPSEC_CRYPTO_N_ALG - 1);
439
440   a = im->crypto_algs + IPSEC_CRYPTO_ALG_NONE;
441   a->enc_op_id = VNET_CRYPTO_OP_NONE;
442   a->dec_op_id = VNET_CRYPTO_OP_NONE;
443   a->alg = VNET_CRYPTO_ALG_NONE;
444   a->iv_size = 0;
445   a->block_align = 1;
446
447   a = im->crypto_algs + IPSEC_CRYPTO_ALG_DES_CBC;
448   a->enc_op_id = VNET_CRYPTO_OP_DES_CBC_ENC;
449   a->dec_op_id = VNET_CRYPTO_OP_DES_CBC_DEC;
450   a->alg = VNET_CRYPTO_ALG_DES_CBC;
451   a->iv_size = a->block_align = 8;
452
453   a = im->crypto_algs + IPSEC_CRYPTO_ALG_3DES_CBC;
454   a->enc_op_id = VNET_CRYPTO_OP_3DES_CBC_ENC;
455   a->dec_op_id = VNET_CRYPTO_OP_3DES_CBC_DEC;
456   a->alg = VNET_CRYPTO_ALG_3DES_CBC;
457   a->iv_size = a->block_align = 8;
458
459   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_128;
460   a->enc_op_id = VNET_CRYPTO_OP_AES_128_CBC_ENC;
461   a->dec_op_id = VNET_CRYPTO_OP_AES_128_CBC_DEC;
462   a->alg = VNET_CRYPTO_ALG_AES_128_CBC;
463   a->iv_size = a->block_align = 16;
464
465   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_192;
466   a->enc_op_id = VNET_CRYPTO_OP_AES_192_CBC_ENC;
467   a->dec_op_id = VNET_CRYPTO_OP_AES_192_CBC_DEC;
468   a->alg = VNET_CRYPTO_ALG_AES_192_CBC;
469   a->iv_size = a->block_align = 16;
470
471   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_256;
472   a->enc_op_id = VNET_CRYPTO_OP_AES_256_CBC_ENC;
473   a->dec_op_id = VNET_CRYPTO_OP_AES_256_CBC_DEC;
474   a->alg = VNET_CRYPTO_ALG_AES_256_CBC;
475   a->iv_size = a->block_align = 16;
476
477   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CTR_128;
478   a->enc_op_id = VNET_CRYPTO_OP_AES_128_CTR_ENC;
479   a->dec_op_id = VNET_CRYPTO_OP_AES_128_CTR_DEC;
480   a->alg = VNET_CRYPTO_ALG_AES_128_CTR;
481   a->iv_size = 8;
482   a->block_align = 1;
483
484   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CTR_192;
485   a->enc_op_id = VNET_CRYPTO_OP_AES_192_CTR_ENC;
486   a->dec_op_id = VNET_CRYPTO_OP_AES_192_CTR_DEC;
487   a->alg = VNET_CRYPTO_ALG_AES_192_CTR;
488   a->iv_size = 8;
489   a->block_align = 1;
490
491   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CTR_256;
492   a->enc_op_id = VNET_CRYPTO_OP_AES_256_CTR_ENC;
493   a->dec_op_id = VNET_CRYPTO_OP_AES_256_CTR_DEC;
494   a->alg = VNET_CRYPTO_ALG_AES_256_CTR;
495   a->iv_size = 8;
496   a->block_align = 1;
497
498   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_128;
499   a->enc_op_id = VNET_CRYPTO_OP_AES_128_GCM_ENC;
500   a->dec_op_id = VNET_CRYPTO_OP_AES_128_GCM_DEC;
501   a->alg = VNET_CRYPTO_ALG_AES_128_GCM;
502   a->iv_size = 8;
503   a->block_align = 1;
504   a->icv_size = 16;
505
506   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_192;
507   a->enc_op_id = VNET_CRYPTO_OP_AES_192_GCM_ENC;
508   a->dec_op_id = VNET_CRYPTO_OP_AES_192_GCM_DEC;
509   a->alg = VNET_CRYPTO_ALG_AES_192_GCM;
510   a->iv_size = 8;
511   a->block_align = 1;
512   a->icv_size = 16;
513
514   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_256;
515   a->enc_op_id = VNET_CRYPTO_OP_AES_256_GCM_ENC;
516   a->dec_op_id = VNET_CRYPTO_OP_AES_256_GCM_DEC;
517   a->alg = VNET_CRYPTO_ALG_AES_256_GCM;
518   a->iv_size = 8;
519   a->block_align = 1;
520   a->icv_size = 16;
521
522   vec_validate (im->integ_algs, IPSEC_INTEG_N_ALG - 1);
523   ipsec_main_integ_alg_t *i;
524
525   i = &im->integ_algs[IPSEC_INTEG_ALG_MD5_96];
526   i->op_id = VNET_CRYPTO_OP_MD5_HMAC;
527   i->alg = VNET_CRYPTO_ALG_HMAC_MD5;
528   i->icv_size = 12;
529
530   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA1_96];
531   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
532   i->alg = VNET_CRYPTO_ALG_HMAC_SHA1;
533   i->icv_size = 12;
534
535   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_96];
536   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
537   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
538   i->icv_size = 12;
539
540   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_128];
541   i->op_id = VNET_CRYPTO_OP_SHA256_HMAC;
542   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
543   i->icv_size = 16;
544
545   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_384_192];
546   i->op_id = VNET_CRYPTO_OP_SHA384_HMAC;
547   i->alg = VNET_CRYPTO_ALG_HMAC_SHA384;
548   i->icv_size = 24;
549
550   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_512_256];
551   i->op_id = VNET_CRYPTO_OP_SHA512_HMAC;
552   i->alg = VNET_CRYPTO_ALG_HMAC_SHA512;
553   i->icv_size = 32;
554
555   vec_validate_aligned (im->ptd, vlib_num_workers (), CLIB_CACHE_LINE_BYTES);
556
557   im->async_mode = 0;
558   crypto_engine_backend_register_post_node (vm);
559
560   im->ipsec4_out_spd_hash_tbl = NULL;
561   im->output_flow_cache_flag = 0;
562   im->ipsec4_out_spd_flow_cache_entries = 0;
563   im->epoch_count = 0;
564   im->ipsec4_out_spd_hash_num_buckets =
565     IPSEC4_OUT_SPD_DEFAULT_HASH_NUM_BUCKETS;
566
567   im->ipsec4_in_spd_hash_tbl = NULL;
568   im->input_flow_cache_flag = 0;
569   im->ipsec4_in_spd_flow_cache_entries = 0;
570   im->input_epoch_count = 0;
571   im->ipsec4_in_spd_hash_num_buckets = IPSEC4_SPD_DEFAULT_HASH_NUM_BUCKETS;
572
573   return 0;
574 }
575
576 VLIB_INIT_FUNCTION (ipsec_init);
577
578 static clib_error_t *
579 ipsec_config (vlib_main_t *vm, unformat_input_t *input)
580 {
581   ipsec_main_t *im = &ipsec_main;
582   unformat_input_t sub_input;
583
584   u32 ipsec4_out_spd_hash_num_buckets;
585   u32 ipsec4_in_spd_hash_num_buckets;
586
587   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
588     {
589       if (unformat (input, "ipv4-outbound-spd-flow-cache on"))
590         im->output_flow_cache_flag = 1;
591       else if (unformat (input, "ipv4-outbound-spd-flow-cache off"))
592         im->output_flow_cache_flag = 0;
593       else if (unformat (input, "ipv4-outbound-spd-hash-buckets %d",
594                          &ipsec4_out_spd_hash_num_buckets))
595         {
596           /* Size of hash is power of 2 >= number of buckets */
597           im->ipsec4_out_spd_hash_num_buckets =
598             1ULL << max_log2 (ipsec4_out_spd_hash_num_buckets);
599         }
600       else if (unformat (input, "ipv4-inbound-spd-flow-cache on"))
601         im->input_flow_cache_flag = 1;
602       else if (unformat (input, "ipv4-inbound-spd-flow-cache off"))
603         im->input_flow_cache_flag = 0;
604       else if (unformat (input, "ipv4-inbound-spd-hash-buckets %d",
605                          &ipsec4_in_spd_hash_num_buckets))
606         {
607           im->ipsec4_in_spd_hash_num_buckets =
608             1ULL << max_log2 (ipsec4_in_spd_hash_num_buckets);
609         }
610       else if (unformat (input, "ip4 %U", unformat_vlib_cli_sub_input,
611                          &sub_input))
612         {
613           uword table_size = ~0;
614           u32 n_buckets = ~0;
615
616           while (unformat_check_input (&sub_input) != UNFORMAT_END_OF_INPUT)
617             {
618               if (unformat (&sub_input, "num-buckets %u", &n_buckets))
619                 ;
620               else
621                 return clib_error_return (0, "unknown input `%U'",
622                                           format_unformat_error, &sub_input);
623             }
624
625           ipsec_tun_table_init (AF_IP4, table_size, n_buckets);
626         }
627       else if (unformat (input, "ip6 %U", unformat_vlib_cli_sub_input,
628                          &sub_input))
629         {
630           uword table_size = ~0;
631           u32 n_buckets = ~0;
632
633           while (unformat_check_input (&sub_input) != UNFORMAT_END_OF_INPUT)
634             {
635               if (unformat (&sub_input, "num-buckets %u", &n_buckets))
636                 ;
637               else
638                 return clib_error_return (0, "unknown input `%U'",
639                                           format_unformat_error, &sub_input);
640             }
641
642           ipsec_tun_table_init (AF_IP6, table_size, n_buckets);
643         }
644       else
645         return clib_error_return (0, "unknown input `%U'",
646                                   format_unformat_error, input);
647     }
648   if (im->output_flow_cache_flag)
649     {
650       vec_add2 (im->ipsec4_out_spd_hash_tbl, im->ipsec4_out_spd_hash_tbl,
651                 im->ipsec4_out_spd_hash_num_buckets);
652     }
653   if (im->input_flow_cache_flag)
654     {
655       vec_add2 (im->ipsec4_in_spd_hash_tbl, im->ipsec4_in_spd_hash_tbl,
656                 im->ipsec4_in_spd_hash_num_buckets);
657     }
658
659   return 0;
660 }
661
662 VLIB_CONFIG_FUNCTION (ipsec_config, "ipsec");
663
664 /*
665  * fd.io coding-style-patch-verification: ON
666  *
667  * Local Variables:
668  * eval: (c-set-style "gnu")
669  * End:
670  */