ipsec: Targeted unit testing
[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.h>
23
24 #include <vnet/ipsec/ipsec.h>
25 #include <vnet/ipsec/esp.h>
26 #include <vnet/ipsec/ah.h>
27
28 ipsec_main_t ipsec_main;
29
30 static clib_error_t *
31 ipsec_check_ah_support (ipsec_sa_t * sa)
32 {
33   ipsec_main_t *im = &ipsec_main;
34
35   if (sa->integ_alg == IPSEC_INTEG_ALG_NONE)
36     return clib_error_return (0, "unsupported none integ-alg");
37
38   if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
39     return clib_error_return (0, "No crypto engine support for %U",
40                               format_ipsec_integ_alg, sa->integ_alg);
41
42   return 0;
43 }
44
45 static clib_error_t *
46 ipsec_check_esp_support (ipsec_sa_t * sa)
47 {
48   ipsec_main_t *im = &ipsec_main;
49
50   if (IPSEC_INTEG_ALG_NONE != sa->integ_alg)
51     {
52       if (!vnet_crypto_is_set_handler (im->integ_algs[sa->integ_alg].alg))
53         return clib_error_return (0, "No crypto engine support for %U",
54                                   format_ipsec_integ_alg, sa->integ_alg);
55     }
56   if (IPSEC_CRYPTO_ALG_NONE != sa->crypto_alg)
57     {
58       if (!vnet_crypto_is_set_handler (im->crypto_algs[sa->crypto_alg].alg))
59         return clib_error_return (0, "No crypto engine support for %U",
60                                   format_ipsec_crypto_alg, sa->crypto_alg);
61     }
62
63   return (0);
64 }
65
66 clib_error_t *
67 ipsec_add_del_sa_sess_cb (ipsec_main_t * im, u32 sa_index, u8 is_add)
68 {
69   ipsec_ah_backend_t *ah =
70     pool_elt_at_index (im->ah_backends, im->ah_current_backend);
71   if (ah->add_del_sa_sess_cb)
72     {
73       clib_error_t *err = ah->add_del_sa_sess_cb (sa_index, is_add);
74       if (err)
75         return err;
76     }
77   ipsec_esp_backend_t *esp =
78     pool_elt_at_index (im->esp_backends, im->esp_current_backend);
79   if (esp->add_del_sa_sess_cb)
80     {
81       clib_error_t *err = esp->add_del_sa_sess_cb (sa_index, is_add);
82       if (err)
83         return err;
84     }
85   return 0;
86 }
87
88 clib_error_t *
89 ipsec_check_support_cb (ipsec_main_t * im, ipsec_sa_t * sa)
90 {
91   clib_error_t *error = 0;
92
93   if (PREDICT_FALSE (sa->protocol == IPSEC_PROTOCOL_AH))
94     {
95       ipsec_ah_backend_t *ah =
96         pool_elt_at_index (im->ah_backends, im->ah_current_backend);
97       ASSERT (ah->check_support_cb);
98       error = ah->check_support_cb (sa);
99     }
100   else
101     {
102       ipsec_esp_backend_t *esp =
103         pool_elt_at_index (im->esp_backends, im->esp_current_backend);
104       ASSERT (esp->check_support_cb);
105       error = esp->check_support_cb (sa);
106     }
107   return error;
108 }
109
110
111 static void
112 ipsec_add_node (vlib_main_t * vm, const char *node_name,
113                 const char *prev_node_name, u32 * out_node_index,
114                 u32 * out_next_index)
115 {
116   vlib_node_t *prev_node, *node;
117   prev_node = vlib_get_node_by_name (vm, (u8 *) prev_node_name);
118   ASSERT (prev_node);
119   node = vlib_get_node_by_name (vm, (u8 *) node_name);
120   ASSERT (node);
121   *out_node_index = node->index;
122   *out_next_index = vlib_node_add_next (vm, prev_node->index, node->index);
123 }
124
125 void
126 ipsec_add_feature (const char *arc_name,
127                    const char *node_name, u32 * out_feature_index)
128 {
129   u8 arc;
130
131   arc = vnet_get_feature_arc_index (arc_name);
132   ASSERT (arc != (u8) ~ 0);
133   *out_feature_index = vnet_get_feature_index (arc, node_name);
134 }
135
136 u32
137 ipsec_register_ah_backend (vlib_main_t * vm, ipsec_main_t * im,
138                            const char *name,
139                            const char *ah4_encrypt_node_name,
140                            const char *ah4_decrypt_node_name,
141                            const char *ah6_encrypt_node_name,
142                            const char *ah6_decrypt_node_name,
143                            check_support_cb_t ah_check_support_cb,
144                            add_del_sa_sess_cb_t ah_add_del_sa_sess_cb)
145 {
146   ipsec_ah_backend_t *b;
147   pool_get (im->ah_backends, b);
148   b->name = format (0, "%s%c", name, 0);
149
150   ipsec_add_node (vm, ah4_encrypt_node_name, "ipsec4-output-feature",
151                   &b->ah4_encrypt_node_index, &b->ah4_encrypt_next_index);
152   ipsec_add_node (vm, ah4_decrypt_node_name, "ipsec4-input-feature",
153                   &b->ah4_decrypt_node_index, &b->ah4_decrypt_next_index);
154   ipsec_add_node (vm, ah6_encrypt_node_name, "ipsec6-output-feature",
155                   &b->ah6_encrypt_node_index, &b->ah6_encrypt_next_index);
156   ipsec_add_node (vm, ah6_decrypt_node_name, "ipsec6-input-feature",
157                   &b->ah6_decrypt_node_index, &b->ah6_decrypt_next_index);
158
159   b->check_support_cb = ah_check_support_cb;
160   b->add_del_sa_sess_cb = ah_add_del_sa_sess_cb;
161   return b - im->ah_backends;
162 }
163
164 u32
165 ipsec_register_esp_backend (vlib_main_t * vm, ipsec_main_t * im,
166                             const char *name,
167                             const char *esp4_encrypt_node_name,
168                             const char *esp4_encrypt_node_tun_name,
169                             const char *esp4_decrypt_node_name,
170                             const char *esp6_encrypt_node_name,
171                             const char *esp6_encrypt_node_tun_name,
172                             const char *esp6_decrypt_node_name,
173                             check_support_cb_t esp_check_support_cb,
174                             add_del_sa_sess_cb_t esp_add_del_sa_sess_cb)
175 {
176   ipsec_esp_backend_t *b;
177
178   pool_get (im->esp_backends, b);
179   b->name = format (0, "%s%c", name, 0);
180
181   ipsec_add_node (vm, esp4_encrypt_node_name, "ipsec4-output-feature",
182                   &b->esp4_encrypt_node_index, &b->esp4_encrypt_next_index);
183   ipsec_add_node (vm, esp4_decrypt_node_name, "ipsec4-input-feature",
184                   &b->esp4_decrypt_node_index, &b->esp4_decrypt_next_index);
185   ipsec_add_node (vm, esp6_encrypt_node_name, "ipsec6-output-feature",
186                   &b->esp6_encrypt_node_index, &b->esp6_encrypt_next_index);
187   ipsec_add_node (vm, esp6_decrypt_node_name, "ipsec6-input-feature",
188                   &b->esp6_decrypt_node_index, &b->esp6_decrypt_next_index);
189
190   ipsec_add_feature ("ip4-output", esp4_encrypt_node_tun_name,
191                      &b->esp44_encrypt_tun_feature_index);
192   ipsec_add_feature ("ip4-output", esp6_encrypt_node_tun_name,
193                      &b->esp46_encrypt_tun_feature_index);
194   ipsec_add_feature ("ip6-output", esp6_encrypt_node_tun_name,
195                      &b->esp66_encrypt_tun_feature_index);
196   ipsec_add_feature ("ip6-output", esp4_encrypt_node_tun_name,
197                      &b->esp64_encrypt_tun_feature_index);
198
199   b->check_support_cb = esp_check_support_cb;
200   b->add_del_sa_sess_cb = esp_add_del_sa_sess_cb;
201   return b - im->esp_backends;
202 }
203
204 clib_error_t *
205 ipsec_rsc_in_use (ipsec_main_t * im)
206 {
207   /* return an error is crypto resource are in use */
208   if (pool_elts (im->sad) > 0)
209     return clib_error_return (0,
210                               "%d SA entries configured",
211                               pool_elts (im->sad));
212
213   return (NULL);
214 }
215
216 int
217 ipsec_select_ah_backend (ipsec_main_t * im, u32 backend_idx)
218 {
219   if (ipsec_rsc_in_use (im))
220     return VNET_API_ERROR_RSRC_IN_USE;
221
222   if (pool_is_free_index (im->ah_backends, backend_idx))
223     return VNET_API_ERROR_INVALID_VALUE;
224
225   ipsec_ah_backend_t *b = pool_elt_at_index (im->ah_backends, backend_idx);
226   im->ah_current_backend = backend_idx;
227   im->ah4_encrypt_node_index = b->ah4_encrypt_node_index;
228   im->ah4_decrypt_node_index = b->ah4_decrypt_node_index;
229   im->ah4_encrypt_next_index = b->ah4_encrypt_next_index;
230   im->ah4_decrypt_next_index = b->ah4_decrypt_next_index;
231   im->ah6_encrypt_node_index = b->ah6_encrypt_node_index;
232   im->ah6_decrypt_node_index = b->ah6_decrypt_node_index;
233   im->ah6_encrypt_next_index = b->ah6_encrypt_next_index;
234   im->ah6_decrypt_next_index = b->ah6_decrypt_next_index;
235
236   return 0;
237 }
238
239 int
240 ipsec_select_esp_backend (ipsec_main_t * im, u32 backend_idx)
241 {
242   if (ipsec_rsc_in_use (im))
243     return VNET_API_ERROR_RSRC_IN_USE;
244
245   if (pool_is_free_index (im->esp_backends, backend_idx))
246     return VNET_API_ERROR_INVALID_VALUE;
247
248   ipsec_esp_backend_t *b = pool_elt_at_index (im->esp_backends, backend_idx);
249   im->esp_current_backend = backend_idx;
250   im->esp4_encrypt_node_index = b->esp4_encrypt_node_index;
251   im->esp4_decrypt_node_index = b->esp4_decrypt_node_index;
252   im->esp4_encrypt_next_index = b->esp4_encrypt_next_index;
253   im->esp4_decrypt_next_index = b->esp4_decrypt_next_index;
254   im->esp6_encrypt_node_index = b->esp6_encrypt_node_index;
255   im->esp6_decrypt_node_index = b->esp6_decrypt_node_index;
256   im->esp6_encrypt_next_index = b->esp6_encrypt_next_index;
257   im->esp6_decrypt_next_index = b->esp6_decrypt_next_index;
258
259   im->esp44_encrypt_tun_feature_index = b->esp44_encrypt_tun_feature_index;
260   im->esp64_encrypt_tun_feature_index = b->esp64_encrypt_tun_feature_index;
261   im->esp46_encrypt_tun_feature_index = b->esp46_encrypt_tun_feature_index;
262   im->esp66_encrypt_tun_feature_index = b->esp66_encrypt_tun_feature_index;
263
264   return 0;
265 }
266
267 static clib_error_t *
268 ipsec_init (vlib_main_t * vm)
269 {
270   clib_error_t *error;
271   ipsec_main_t *im = &ipsec_main;
272   ipsec_main_crypto_alg_t *a;
273
274   /* Backend registration requires the feature arcs to be set up */
275   if ((error = vlib_call_init_function (vm, vnet_feature_init)))
276     return (error);
277
278   im->vnet_main = vnet_get_main ();
279   im->vlib_main = vm;
280
281   im->spd_index_by_spd_id = hash_create (0, sizeof (uword));
282   im->sa_index_by_sa_id = hash_create (0, sizeof (uword));
283   im->spd_index_by_sw_if_index = hash_create (0, sizeof (uword));
284
285   vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "error-drop");
286   ASSERT (node);
287   im->error_drop_node_index = node->index;
288
289   u32 idx = ipsec_register_ah_backend (vm, im, "crypto engine backend",
290                                        "ah4-encrypt",
291                                        "ah4-decrypt",
292                                        "ah6-encrypt",
293                                        "ah6-decrypt",
294                                        ipsec_check_ah_support,
295                                        NULL);
296
297   im->ah_default_backend = idx;
298   int rv = ipsec_select_ah_backend (im, idx);
299   ASSERT (0 == rv);
300   (void) (rv);                  // avoid warning
301
302   idx = ipsec_register_esp_backend (vm, im, "crypto engine backend",
303                                     "esp4-encrypt",
304                                     "esp4-encrypt-tun",
305                                     "esp4-decrypt",
306                                     "esp6-encrypt",
307                                     "esp6-encrypt-tun",
308                                     "esp6-decrypt",
309                                     ipsec_check_esp_support, NULL);
310   im->esp_default_backend = idx;
311
312   rv = ipsec_select_esp_backend (im, idx);
313   ASSERT (0 == rv);
314   (void) (rv);                  // avoid warning
315
316   if ((error = vlib_call_init_function (vm, ipsec_cli_init)))
317     return error;
318
319   vec_validate (im->crypto_algs, IPSEC_CRYPTO_N_ALG - 1);
320
321   a = im->crypto_algs + IPSEC_CRYPTO_ALG_NONE;
322   a->enc_op_id = VNET_CRYPTO_OP_NONE;
323   a->dec_op_id = VNET_CRYPTO_OP_NONE;
324   a->alg = VNET_CRYPTO_ALG_NONE;
325   a->iv_size = 0;
326   a->block_size = 1;
327
328   a = im->crypto_algs + IPSEC_CRYPTO_ALG_DES_CBC;
329   a->enc_op_id = VNET_CRYPTO_OP_DES_CBC_ENC;
330   a->dec_op_id = VNET_CRYPTO_OP_DES_CBC_DEC;
331   a->alg = VNET_CRYPTO_ALG_DES_CBC;
332   a->iv_size = a->block_size = 8;
333
334   a = im->crypto_algs + IPSEC_CRYPTO_ALG_3DES_CBC;
335   a->enc_op_id = VNET_CRYPTO_OP_3DES_CBC_ENC;
336   a->dec_op_id = VNET_CRYPTO_OP_3DES_CBC_DEC;
337   a->alg = VNET_CRYPTO_ALG_3DES_CBC;
338   a->iv_size = a->block_size = 8;
339
340   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_128;
341   a->enc_op_id = VNET_CRYPTO_OP_AES_128_CBC_ENC;
342   a->dec_op_id = VNET_CRYPTO_OP_AES_128_CBC_DEC;
343   a->alg = VNET_CRYPTO_ALG_AES_128_CBC;
344   a->iv_size = a->block_size = 16;
345
346   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_192;
347   a->enc_op_id = VNET_CRYPTO_OP_AES_192_CBC_ENC;
348   a->dec_op_id = VNET_CRYPTO_OP_AES_192_CBC_DEC;
349   a->alg = VNET_CRYPTO_ALG_AES_192_CBC;
350   a->iv_size = a->block_size = 16;
351
352   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_CBC_256;
353   a->enc_op_id = VNET_CRYPTO_OP_AES_256_CBC_ENC;
354   a->dec_op_id = VNET_CRYPTO_OP_AES_256_CBC_DEC;
355   a->alg = VNET_CRYPTO_ALG_AES_256_CBC;
356   a->iv_size = a->block_size = 16;
357
358   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_128;
359   a->enc_op_id = VNET_CRYPTO_OP_AES_128_GCM_ENC;
360   a->dec_op_id = VNET_CRYPTO_OP_AES_128_GCM_DEC;
361   a->alg = VNET_CRYPTO_ALG_AES_128_GCM;
362   a->iv_size = a->block_size = 8;
363   a->icv_size = 16;
364
365   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_192;
366   a->enc_op_id = VNET_CRYPTO_OP_AES_192_GCM_ENC;
367   a->dec_op_id = VNET_CRYPTO_OP_AES_192_GCM_DEC;
368   a->alg = VNET_CRYPTO_ALG_AES_192_GCM;
369   a->iv_size = a->block_size = 8;
370   a->icv_size = 16;
371
372   a = im->crypto_algs + IPSEC_CRYPTO_ALG_AES_GCM_256;
373   a->enc_op_id = VNET_CRYPTO_OP_AES_256_GCM_ENC;
374   a->dec_op_id = VNET_CRYPTO_OP_AES_256_GCM_DEC;
375   a->alg = VNET_CRYPTO_ALG_AES_256_GCM;
376   a->iv_size = a->block_size = 8;
377   a->icv_size = 16;
378
379   vec_validate (im->integ_algs, IPSEC_INTEG_N_ALG - 1);
380   ipsec_main_integ_alg_t *i;
381
382   i = &im->integ_algs[IPSEC_INTEG_ALG_MD5_96];
383   i->op_id = VNET_CRYPTO_OP_MD5_HMAC;
384   i->alg = VNET_CRYPTO_ALG_HMAC_MD5;
385   i->icv_size = 12;
386
387   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA1_96];
388   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
389   i->alg = VNET_CRYPTO_ALG_HMAC_SHA1;
390   i->icv_size = 12;
391
392   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_96];
393   i->op_id = VNET_CRYPTO_OP_SHA1_HMAC;
394   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
395   i->icv_size = 12;
396
397   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_256_128];
398   i->op_id = VNET_CRYPTO_OP_SHA256_HMAC;
399   i->alg = VNET_CRYPTO_ALG_HMAC_SHA256;
400   i->icv_size = 16;
401
402   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_384_192];
403   i->op_id = VNET_CRYPTO_OP_SHA384_HMAC;
404   i->alg = VNET_CRYPTO_ALG_HMAC_SHA384;
405   i->icv_size = 24;
406
407   i = &im->integ_algs[IPSEC_INTEG_ALG_SHA_512_256];
408   i->op_id = VNET_CRYPTO_OP_SHA512_HMAC;
409   i->alg = VNET_CRYPTO_ALG_HMAC_SHA512;
410   i->icv_size = 32;
411
412   vec_validate_aligned (im->ptd, vlib_num_workers (), CLIB_CACHE_LINE_BYTES);
413
414   im->ah4_enc_fq_index =
415     vlib_frame_queue_main_init (ah4_encrypt_node.index, 0);
416   im->ah4_dec_fq_index =
417     vlib_frame_queue_main_init (ah4_decrypt_node.index, 0);
418   im->ah6_enc_fq_index =
419     vlib_frame_queue_main_init (ah6_encrypt_node.index, 0);
420   im->ah6_dec_fq_index =
421     vlib_frame_queue_main_init (ah6_decrypt_node.index, 0);
422
423   im->esp4_enc_fq_index =
424     vlib_frame_queue_main_init (esp4_encrypt_node.index, 0);
425   im->esp4_dec_fq_index =
426     vlib_frame_queue_main_init (esp4_decrypt_node.index, 0);
427   im->esp6_enc_fq_index =
428     vlib_frame_queue_main_init (esp6_encrypt_node.index, 0);
429   im->esp6_dec_fq_index =
430     vlib_frame_queue_main_init (esp6_decrypt_node.index, 0);
431   im->esp4_enc_tun_fq_index =
432     vlib_frame_queue_main_init (esp4_encrypt_tun_node.index, 0);
433   im->esp6_enc_tun_fq_index =
434     vlib_frame_queue_main_init (esp6_encrypt_tun_node.index, 0);
435   im->esp4_dec_tun_fq_index =
436     vlib_frame_queue_main_init (esp4_decrypt_tun_node.index, 0);
437   im->esp6_dec_tun_fq_index =
438     vlib_frame_queue_main_init (esp6_decrypt_tun_node.index, 0);
439
440   return 0;
441 }
442
443 VLIB_INIT_FUNCTION (ipsec_init);
444
445 /*
446  * fd.io coding-style-patch-verification: ON
447  *
448  * Local Variables:
449  * eval: (c-set-style "gnu")
450  * End:
451  */