Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018-2020 Intel Corporation
3 : : */
4 : :
5 : : #include <eal_export.h>
6 : : #include <rte_ipsec.h>
7 : : #include <rte_esp.h>
8 : : #include <rte_ip.h>
9 : : #include <rte_udp.h>
10 : : #include <rte_errno.h>
11 : :
12 : : #include "sa.h"
13 : : #include "ipsec_sqn.h"
14 : : #include "crypto.h"
15 : : #include "misc.h"
16 : :
17 : : #define MBUF_MAX_L2_LEN RTE_LEN2MASK(RTE_MBUF_L2_LEN_BITS, uint64_t)
18 : : #define MBUF_MAX_L3_LEN RTE_LEN2MASK(RTE_MBUF_L3_LEN_BITS, uint64_t)
19 : :
20 : : /* some helper structures */
21 : : struct crypto_xform {
22 : : struct rte_crypto_auth_xform *auth;
23 : : struct rte_crypto_cipher_xform *cipher;
24 : : struct rte_crypto_aead_xform *aead;
25 : : };
26 : :
27 : : /*
28 : : * helper routine, fills internal crypto_xform structure.
29 : : */
30 : : static int
31 [ # # ]: 0 : fill_crypto_xform(struct crypto_xform *xform, uint64_t type,
32 : : const struct rte_ipsec_sa_prm *prm)
33 : : {
34 : : struct rte_crypto_sym_xform *xf, *xfn;
35 : :
36 : : memset(xform, 0, sizeof(*xform));
37 : :
38 : 0 : xf = prm->crypto_xform;
39 [ # # ]: 0 : if (xf == NULL)
40 : : return -EINVAL;
41 : :
42 : 0 : xfn = xf->next;
43 : :
44 : : /* for AEAD just one xform required */
45 [ # # ]: 0 : if (xf->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
46 [ # # ]: 0 : if (xfn != NULL)
47 : : return -EINVAL;
48 : 0 : xform->aead = &xf->aead;
49 : :
50 : : /* GMAC has only auth */
51 [ # # ]: 0 : } else if (xf->type == RTE_CRYPTO_SYM_XFORM_AUTH &&
52 [ # # ]: 0 : xf->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) {
53 [ # # ]: 0 : if (xfn != NULL)
54 : : return -EINVAL;
55 : 0 : xform->auth = &xf->auth;
56 : 0 : xform->cipher = &xfn->cipher;
57 : :
58 : : /*
59 : : * CIPHER+AUTH xforms are expected in strict order,
60 : : * depending on SA direction:
61 : : * inbound: AUTH+CIPHER
62 : : * outbound: CIPHER+AUTH
63 : : */
64 [ # # ]: 0 : } else if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
65 : :
66 : : /* wrong order or no cipher */
67 [ # # # # ]: 0 : if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_AUTH ||
68 [ # # ]: 0 : xfn->type != RTE_CRYPTO_SYM_XFORM_CIPHER)
69 : : return -EINVAL;
70 : :
71 : 0 : xform->auth = &xf->auth;
72 : 0 : xform->cipher = &xfn->cipher;
73 : :
74 : : } else {
75 : :
76 : : /* wrong order or no auth */
77 [ # # # # ]: 0 : if (xfn == NULL || xf->type != RTE_CRYPTO_SYM_XFORM_CIPHER ||
78 [ # # ]: 0 : xfn->type != RTE_CRYPTO_SYM_XFORM_AUTH)
79 : : return -EINVAL;
80 : :
81 : 0 : xform->cipher = &xf->cipher;
82 : 0 : xform->auth = &xfn->auth;
83 : : }
84 : :
85 : : return 0;
86 : : }
87 : :
88 : : RTE_EXPORT_SYMBOL(rte_ipsec_sa_type)
89 : : uint64_t
90 : 0 : rte_ipsec_sa_type(const struct rte_ipsec_sa *sa)
91 : : {
92 : 0 : return sa->type;
93 : : }
94 : :
95 : : /**
96 : : * Based on number of buckets calculated required size for the
97 : : * structure that holds replay window and sequence number (RSN) information.
98 : : */
99 : : static size_t
100 : : rsn_size(uint32_t nb_bucket)
101 : : {
102 : : size_t sz;
103 : : struct replay_sqn *rsn;
104 : :
105 : 0 : sz = sizeof(*rsn) + nb_bucket * sizeof(rsn->window[0]);
106 : 0 : sz = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
107 : : return sz;
108 : : }
109 : :
110 : : /*
111 : : * for given size, calculate required number of buckets.
112 : : */
113 : : static uint32_t
114 : : replay_num_bucket(uint32_t wsz)
115 : : {
116 : : uint32_t nb;
117 : :
118 [ # # ]: 0 : nb = rte_align32pow2(RTE_ALIGN_MUL_CEIL(wsz, WINDOW_BUCKET_SIZE) /
119 : : WINDOW_BUCKET_SIZE);
120 : 0 : nb = RTE_MAX(nb, (uint32_t)WINDOW_BUCKET_MIN);
121 : :
122 : : return nb;
123 : : }
124 : :
125 : : static int32_t
126 : 0 : ipsec_sa_size(uint64_t type, uint32_t *wnd_sz, uint32_t *nb_bucket)
127 : : {
128 : : uint32_t n, sz, wsz;
129 : :
130 : 0 : wsz = *wnd_sz;
131 : : n = 0;
132 : :
133 [ # # ]: 0 : if ((type & RTE_IPSEC_SATP_DIR_MASK) == RTE_IPSEC_SATP_DIR_IB) {
134 : :
135 : : /*
136 : : * RFC 4303 recommends 64 as minimum window size.
137 : : * there is no point to use ESN mode without SQN window,
138 : : * so make sure we have at least 64 window when ESN is enabled.
139 : : */
140 : 0 : wsz = ((type & RTE_IPSEC_SATP_ESN_MASK) ==
141 : : RTE_IPSEC_SATP_ESN_DISABLE) ?
142 [ # # ]: 0 : wsz : RTE_MAX(wsz, (uint32_t)WINDOW_BUCKET_SIZE);
143 [ # # ]: 0 : if (wsz != 0)
144 : : n = replay_num_bucket(wsz);
145 : : }
146 : :
147 [ # # ]: 0 : if (n > WINDOW_BUCKET_MAX)
148 : : return -EINVAL;
149 : :
150 : 0 : *wnd_sz = wsz;
151 : 0 : *nb_bucket = n;
152 : :
153 : 0 : sz = rsn_size(n);
154 [ # # ]: 0 : if ((type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM)
155 : 0 : sz *= REPLAY_SQN_NUM;
156 : :
157 : 0 : sz += sizeof(struct rte_ipsec_sa);
158 : 0 : return sz;
159 : : }
160 : :
161 : : RTE_EXPORT_SYMBOL(rte_ipsec_sa_fini)
162 : : void
163 : 0 : rte_ipsec_sa_fini(struct rte_ipsec_sa *sa)
164 : : {
165 : 0 : memset(sa, 0, sa->size);
166 : 0 : }
167 : :
168 : : /*
169 : : * Determine expected SA type based on input parameters.
170 : : */
171 : : static int
172 : 0 : fill_sa_type(const struct rte_ipsec_sa_prm *prm, uint64_t *type)
173 : : {
174 : : uint64_t tp;
175 : :
176 : : tp = 0;
177 : :
178 [ # # ]: 0 : if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_AH)
179 : : tp |= RTE_IPSEC_SATP_PROTO_AH;
180 [ # # ]: 0 : else if (prm->ipsec_xform.proto == RTE_SECURITY_IPSEC_SA_PROTO_ESP)
181 : : tp |= RTE_IPSEC_SATP_PROTO_ESP;
182 : : else
183 : : return -EINVAL;
184 : :
185 [ # # ]: 0 : if (prm->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS)
186 : 0 : tp |= RTE_IPSEC_SATP_DIR_OB;
187 [ # # ]: 0 : else if (prm->ipsec_xform.direction ==
188 : : RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
189 : : tp |= RTE_IPSEC_SATP_DIR_IB;
190 : : else
191 : : return -EINVAL;
192 : :
193 [ # # ]: 0 : if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
194 [ # # ]: 0 : if (prm->ipsec_xform.tunnel.type ==
195 : : RTE_SECURITY_IPSEC_TUNNEL_IPV4)
196 : 0 : tp |= RTE_IPSEC_SATP_MODE_TUNLV4;
197 [ # # ]: 0 : else if (prm->ipsec_xform.tunnel.type ==
198 : : RTE_SECURITY_IPSEC_TUNNEL_IPV6)
199 : 0 : tp |= RTE_IPSEC_SATP_MODE_TUNLV6;
200 : : else
201 : : return -EINVAL;
202 : :
203 [ # # ]: 0 : if (prm->tun.next_proto == IPPROTO_IPIP)
204 : : tp |= RTE_IPSEC_SATP_IPV4;
205 [ # # ]: 0 : else if (prm->tun.next_proto == IPPROTO_IPV6)
206 : 0 : tp |= RTE_IPSEC_SATP_IPV6;
207 : : else
208 : : return -EINVAL;
209 [ # # ]: 0 : } else if (prm->ipsec_xform.mode ==
210 : : RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT) {
211 : : tp |= RTE_IPSEC_SATP_MODE_TRANS;
212 [ # # ]: 0 : if (prm->trs.proto == IPPROTO_IPIP)
213 : : tp |= RTE_IPSEC_SATP_IPV4;
214 [ # # ]: 0 : else if (prm->trs.proto == IPPROTO_IPV6)
215 : 0 : tp |= RTE_IPSEC_SATP_IPV6;
216 : : else
217 : : return -EINVAL;
218 : : } else
219 : : return -EINVAL;
220 : :
221 : : /* check for UDP encapsulation flag */
222 [ # # ]: 0 : if (prm->ipsec_xform.options.udp_encap == 1)
223 : 0 : tp |= RTE_IPSEC_SATP_NATT_ENABLE;
224 : :
225 : : /* check for ESN flag */
226 [ # # ]: 0 : if (prm->ipsec_xform.options.esn == 0)
227 : : tp |= RTE_IPSEC_SATP_ESN_DISABLE;
228 : : else
229 : 0 : tp |= RTE_IPSEC_SATP_ESN_ENABLE;
230 : :
231 : : /* check for ECN flag */
232 [ # # ]: 0 : if (prm->ipsec_xform.options.ecn == 0)
233 : : tp |= RTE_IPSEC_SATP_ECN_DISABLE;
234 : : else
235 : 0 : tp |= RTE_IPSEC_SATP_ECN_ENABLE;
236 : :
237 : : /* check for DSCP flag */
238 [ # # ]: 0 : if (prm->ipsec_xform.options.copy_dscp == 0)
239 : : tp |= RTE_IPSEC_SATP_DSCP_DISABLE;
240 : : else
241 : 0 : tp |= RTE_IPSEC_SATP_DSCP_ENABLE;
242 : :
243 : : /* interpret flags */
244 [ # # ]: 0 : if (prm->flags & RTE_IPSEC_SAFLAG_SQN_ATOM)
245 : 0 : tp |= RTE_IPSEC_SATP_SQN_ATOM;
246 : : else
247 : : tp |= RTE_IPSEC_SATP_SQN_RAW;
248 : :
249 : 0 : *type = tp;
250 : 0 : return 0;
251 : : }
252 : :
253 : : /*
254 : : * Init ESP inbound specific things.
255 : : */
256 : : static void
257 : : esp_inb_init(struct rte_ipsec_sa *sa)
258 : : {
259 : : /* these params may differ with new algorithms support */
260 : 0 : sa->ctp.cipher.offset = sizeof(struct rte_esp_hdr) + sa->iv_len;
261 : 0 : sa->ctp.cipher.length = sa->icv_len + sa->ctp.cipher.offset;
262 : :
263 : : /*
264 : : * for AEAD algorithms we can assume that
265 : : * auth and cipher offsets would be equal.
266 : : */
267 [ # # ]: 0 : switch (sa->algo_type) {
268 : 0 : case ALGO_TYPE_AES_GCM:
269 : : case ALGO_TYPE_AES_CCM:
270 : : case ALGO_TYPE_CHACHA20_POLY1305:
271 : 0 : sa->ctp.auth.raw = sa->ctp.cipher.raw;
272 : 0 : break;
273 : 0 : default:
274 : 0 : sa->ctp.auth.offset = 0;
275 : 0 : sa->ctp.auth.length = sa->icv_len - sa->sqh_len;
276 : 0 : sa->cofs.ofs.cipher.tail = sa->sqh_len;
277 : 0 : break;
278 : : }
279 : :
280 : 0 : sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
281 : 0 : }
282 : :
283 : : /*
284 : : * Init ESP inbound tunnel specific things.
285 : : */
286 : : static void
287 : : esp_inb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
288 : : {
289 [ # # ]: 0 : sa->proto = prm->tun.next_proto;
290 : : esp_inb_init(sa);
291 : 0 : }
292 : :
293 : : /*
294 : : * Init ESP outbound specific things.
295 : : */
296 : : static void
297 : 0 : esp_outb_init(struct rte_ipsec_sa *sa, uint32_t hlen, uint64_t sqn)
298 : : {
299 : : uint8_t algo_type;
300 : :
301 : 0 : sa->sqn.outb = sqn > 1 ? sqn : 1;
302 : :
303 : 0 : algo_type = sa->algo_type;
304 : :
305 : : /*
306 : : * Setup auth and cipher length and offset.
307 : : * these params may differ with new algorithms support
308 : : */
309 : :
310 [ # # # # ]: 0 : switch (algo_type) {
311 : 0 : case ALGO_TYPE_AES_GCM:
312 : : case ALGO_TYPE_AES_CCM:
313 : : case ALGO_TYPE_CHACHA20_POLY1305:
314 : : case ALGO_TYPE_AES_CTR:
315 : : case ALGO_TYPE_NULL:
316 : 0 : sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr) +
317 : 0 : sa->iv_len;
318 : 0 : sa->ctp.cipher.length = 0;
319 : 0 : break;
320 : 0 : case ALGO_TYPE_AES_CBC:
321 : : case ALGO_TYPE_3DES_CBC:
322 : 0 : sa->ctp.cipher.offset = hlen + sizeof(struct rte_esp_hdr);
323 : 0 : sa->ctp.cipher.length = sa->iv_len;
324 : 0 : break;
325 : 0 : case ALGO_TYPE_AES_GMAC:
326 : 0 : sa->ctp.cipher.offset = 0;
327 : 0 : sa->ctp.cipher.length = 0;
328 : 0 : break;
329 : : }
330 : :
331 : : /*
332 : : * for AEAD algorithms we can assume that
333 : : * auth and cipher offsets would be equal.
334 : : */
335 [ # # ]: 0 : switch (algo_type) {
336 : 0 : case ALGO_TYPE_AES_GCM:
337 : : case ALGO_TYPE_AES_CCM:
338 : : case ALGO_TYPE_CHACHA20_POLY1305:
339 : 0 : sa->ctp.auth.raw = sa->ctp.cipher.raw;
340 : 0 : break;
341 : 0 : default:
342 : 0 : sa->ctp.auth.offset = hlen;
343 : 0 : sa->ctp.auth.length = sizeof(struct rte_esp_hdr) +
344 : 0 : sa->iv_len + sa->sqh_len;
345 : 0 : break;
346 : : }
347 : :
348 : 0 : sa->cofs.ofs.cipher.head = sa->ctp.cipher.offset - sa->ctp.auth.offset;
349 : 0 : sa->cofs.ofs.cipher.tail = (sa->ctp.auth.offset + sa->ctp.auth.length) -
350 : 0 : (sa->ctp.cipher.offset + sa->ctp.cipher.length);
351 : 0 : }
352 : :
353 : : /*
354 : : * Init ESP outbound tunnel specific things.
355 : : */
356 : : static void
357 : 0 : esp_outb_tun_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm)
358 : : {
359 : 0 : sa->proto = prm->tun.next_proto;
360 : 0 : sa->hdr_len = prm->tun.hdr_len;
361 : 0 : sa->hdr_l3_off = prm->tun.hdr_l3_off;
362 : :
363 [ # # ]: 0 : memcpy(sa->hdr, prm->tun.hdr, prm->tun.hdr_len);
364 : :
365 : : /* insert UDP header if UDP encapsulation is enabled */
366 [ # # ]: 0 : if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE) {
367 : 0 : struct rte_udp_hdr *udph = (struct rte_udp_hdr *)
368 : 0 : &sa->hdr[prm->tun.hdr_len];
369 : 0 : sa->hdr_len += sizeof(struct rte_udp_hdr);
370 [ # # ]: 0 : udph->src_port = rte_cpu_to_be_16(prm->ipsec_xform.udp.sport);
371 [ # # ]: 0 : udph->dst_port = rte_cpu_to_be_16(prm->ipsec_xform.udp.dport);
372 : 0 : udph->dgram_cksum = 0;
373 : : }
374 : :
375 : : /* update l2_len and l3_len fields for outbound mbuf */
376 : 0 : sa->tx_offload.val = rte_mbuf_tx_offload(sa->hdr_l3_off,
377 : 0 : prm->tun.hdr_len - sa->hdr_l3_off, 0, 0, 0, 0, 0);
378 : :
379 : 0 : esp_outb_init(sa, sa->hdr_len, prm->ipsec_xform.esn.value);
380 : 0 : }
381 : :
382 : : /*
383 : : * helper function, init SA structure.
384 : : */
385 : : static int
386 : 0 : esp_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
387 : : const struct crypto_xform *cxf)
388 : : {
389 : : static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
390 : : RTE_IPSEC_SATP_MODE_MASK |
391 : : RTE_IPSEC_SATP_NATT_MASK;
392 : :
393 [ # # ]: 0 : if (prm->ipsec_xform.options.ecn)
394 : 0 : sa->tos_mask |= RTE_IPV4_HDR_ECN_MASK;
395 : :
396 [ # # ]: 0 : if (prm->ipsec_xform.options.copy_dscp)
397 : 0 : sa->tos_mask |= RTE_IPV4_HDR_DSCP_MASK;
398 : :
399 [ # # ]: 0 : if (cxf->aead != NULL) {
400 [ # # # # ]: 0 : switch (cxf->aead->algo) {
401 : 0 : case RTE_CRYPTO_AEAD_AES_GCM:
402 : : /* RFC 4106 */
403 : 0 : sa->aad_len = sizeof(struct aead_gcm_aad);
404 : 0 : sa->icv_len = cxf->aead->digest_length;
405 : 0 : sa->iv_ofs = cxf->aead->iv.offset;
406 : 0 : sa->iv_len = sizeof(uint64_t);
407 : 0 : sa->pad_align = IPSEC_PAD_AES_GCM;
408 : 0 : sa->algo_type = ALGO_TYPE_AES_GCM;
409 : 0 : break;
410 : 0 : case RTE_CRYPTO_AEAD_AES_CCM:
411 : : /* RFC 4309 */
412 : 0 : sa->aad_len = sizeof(struct aead_ccm_aad);
413 : 0 : sa->icv_len = cxf->aead->digest_length;
414 : 0 : sa->iv_ofs = cxf->aead->iv.offset;
415 : 0 : sa->iv_len = sizeof(uint64_t);
416 : 0 : sa->pad_align = IPSEC_PAD_AES_CCM;
417 : 0 : sa->algo_type = ALGO_TYPE_AES_CCM;
418 : 0 : break;
419 : 0 : case RTE_CRYPTO_AEAD_CHACHA20_POLY1305:
420 : : /* RFC 7634 & 8439*/
421 : 0 : sa->aad_len = sizeof(struct aead_chacha20_poly1305_aad);
422 : 0 : sa->icv_len = cxf->aead->digest_length;
423 : 0 : sa->iv_ofs = cxf->aead->iv.offset;
424 : 0 : sa->iv_len = sizeof(uint64_t);
425 : 0 : sa->pad_align = IPSEC_PAD_CHACHA20_POLY1305;
426 : 0 : sa->algo_type = ALGO_TYPE_CHACHA20_POLY1305;
427 : 0 : break;
428 : : default:
429 : : return -EINVAL;
430 : : }
431 [ # # ]: 0 : } else if (cxf->auth->algo == RTE_CRYPTO_AUTH_AES_GMAC) {
432 : : /* RFC 4543 */
433 : : /* AES-GMAC is a special case of auth that needs IV */
434 : 0 : sa->pad_align = IPSEC_PAD_AES_GMAC;
435 : 0 : sa->iv_len = sizeof(uint64_t);
436 : 0 : sa->icv_len = cxf->auth->digest_length;
437 : 0 : sa->iv_ofs = cxf->auth->iv.offset;
438 : 0 : sa->algo_type = ALGO_TYPE_AES_GMAC;
439 : :
440 : : } else {
441 : 0 : sa->icv_len = cxf->auth->digest_length;
442 : 0 : sa->iv_ofs = cxf->cipher->iv.offset;
443 : :
444 [ # # # # : 0 : switch (cxf->cipher->algo) {
# ]
445 : 0 : case RTE_CRYPTO_CIPHER_NULL:
446 : 0 : sa->pad_align = IPSEC_PAD_NULL;
447 : 0 : sa->iv_len = 0;
448 : 0 : sa->algo_type = ALGO_TYPE_NULL;
449 : 0 : break;
450 : :
451 : 0 : case RTE_CRYPTO_CIPHER_AES_CBC:
452 : 0 : sa->pad_align = IPSEC_PAD_AES_CBC;
453 : 0 : sa->iv_len = IPSEC_MAX_IV_SIZE;
454 : 0 : sa->algo_type = ALGO_TYPE_AES_CBC;
455 : 0 : break;
456 : :
457 : 0 : case RTE_CRYPTO_CIPHER_AES_CTR:
458 : : /* RFC 3686 */
459 : 0 : sa->pad_align = IPSEC_PAD_AES_CTR;
460 : 0 : sa->iv_len = IPSEC_AES_CTR_IV_SIZE;
461 : 0 : sa->algo_type = ALGO_TYPE_AES_CTR;
462 : 0 : break;
463 : :
464 : 0 : case RTE_CRYPTO_CIPHER_3DES_CBC:
465 : : /* RFC 1851 */
466 : 0 : sa->pad_align = IPSEC_PAD_3DES_CBC;
467 : 0 : sa->iv_len = IPSEC_3DES_IV_SIZE;
468 : 0 : sa->algo_type = ALGO_TYPE_3DES_CBC;
469 : 0 : break;
470 : :
471 : : default:
472 : : return -EINVAL;
473 : : }
474 : : }
475 : :
476 [ # # ]: 0 : sa->sqh_len = IS_ESN(sa) ? sizeof(uint32_t) : 0;
477 : 0 : sa->udata = prm->userdata;
478 [ # # ]: 0 : sa->spi = rte_cpu_to_be_32(prm->ipsec_xform.spi);
479 : 0 : sa->salt = prm->ipsec_xform.salt;
480 : :
481 : : /* preserve all values except l2_len and l3_len */
482 : 0 : sa->tx_offload.msk =
483 : : ~rte_mbuf_tx_offload(MBUF_MAX_L2_LEN, MBUF_MAX_L3_LEN,
484 : : 0, 0, 0, 0, 0);
485 : :
486 [ # # # # : 0 : switch (sa->type & msk) {
# ]
487 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
488 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
489 : : esp_inb_tun_init(sa, prm);
490 : : break;
491 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
492 : : esp_inb_init(sa);
493 : : break;
494 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4 |
495 : : RTE_IPSEC_SATP_NATT_ENABLE):
496 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6 |
497 : : RTE_IPSEC_SATP_NATT_ENABLE):
498 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
499 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
500 : 0 : esp_outb_tun_init(sa, prm);
501 : 0 : break;
502 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS |
503 : : RTE_IPSEC_SATP_NATT_ENABLE):
504 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
505 : 0 : esp_outb_init(sa, 0, prm->ipsec_xform.esn.value);
506 : 0 : break;
507 : : }
508 : :
509 : : return 0;
510 : : }
511 : :
512 : : /*
513 : : * helper function, init SA replay structure.
514 : : */
515 : : static void
516 : : fill_sa_replay(struct rte_ipsec_sa *sa, uint32_t wnd_sz, uint32_t nb_bucket,
517 : : uint64_t sqn)
518 : : {
519 : 0 : sa->replay.win_sz = wnd_sz;
520 : 0 : sa->replay.nb_bucket = nb_bucket;
521 : 0 : sa->replay.bucket_index_mask = nb_bucket - 1;
522 : 0 : sa->sqn.inb.rsn[0] = (struct replay_sqn *)(sa + 1);
523 : 0 : sa->sqn.inb.rsn[0]->sqn = sqn;
524 : 0 : if ((sa->type & RTE_IPSEC_SATP_SQN_MASK) == RTE_IPSEC_SATP_SQN_ATOM) {
525 : 0 : sa->sqn.inb.rsn[1] = (struct replay_sqn *)
526 : 0 : ((uintptr_t)sa->sqn.inb.rsn[0] + rsn_size(nb_bucket));
527 : 0 : sa->sqn.inb.rsn[1]->sqn = sqn;
528 : : }
529 : : }
530 : :
531 : : RTE_EXPORT_SYMBOL(rte_ipsec_sa_size)
532 : : int
533 : 0 : rte_ipsec_sa_size(const struct rte_ipsec_sa_prm *prm)
534 : : {
535 : : uint64_t type;
536 : : uint32_t nb, wsz;
537 : : int32_t rc;
538 : :
539 [ # # ]: 0 : if (prm == NULL)
540 : : return -EINVAL;
541 : :
542 : : /* determine SA type */
543 : 0 : rc = fill_sa_type(prm, &type);
544 [ # # ]: 0 : if (rc != 0)
545 : : return rc;
546 : :
547 : : /* determine required size */
548 : 0 : wsz = prm->ipsec_xform.replay_win_sz;
549 : 0 : return ipsec_sa_size(type, &wsz, &nb);
550 : : }
551 : :
552 : : RTE_EXPORT_SYMBOL(rte_ipsec_sa_init)
553 : : int
554 : 0 : rte_ipsec_sa_init(struct rte_ipsec_sa *sa, const struct rte_ipsec_sa_prm *prm,
555 : : uint32_t size)
556 : : {
557 : : int32_t rc, sz;
558 : : uint32_t nb, wsz;
559 : : uint64_t type;
560 : : struct crypto_xform cxf;
561 : :
562 [ # # ]: 0 : if (sa == NULL || prm == NULL)
563 : : return -EINVAL;
564 : :
565 : : /* determine SA type */
566 : 0 : rc = fill_sa_type(prm, &type);
567 [ # # ]: 0 : if (rc != 0)
568 : : return rc;
569 : :
570 : : /* determine required size */
571 : 0 : wsz = prm->ipsec_xform.replay_win_sz;
572 : 0 : sz = ipsec_sa_size(type, &wsz, &nb);
573 [ # # ]: 0 : if (sz < 0)
574 : : return sz;
575 [ # # ]: 0 : else if (size < (uint32_t)sz)
576 : : return -ENOSPC;
577 : :
578 : : /* only esp is supported right now */
579 [ # # ]: 0 : if (prm->ipsec_xform.proto != RTE_SECURITY_IPSEC_SA_PROTO_ESP)
580 : : return -EINVAL;
581 : :
582 [ # # ]: 0 : if (prm->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) {
583 : 0 : uint32_t hlen = prm->tun.hdr_len;
584 [ # # ]: 0 : if (sa->type & RTE_IPSEC_SATP_NATT_ENABLE)
585 : 0 : hlen += sizeof(struct rte_udp_hdr);
586 [ # # ]: 0 : if (hlen > sizeof(sa->hdr))
587 : : return -EINVAL;
588 : : }
589 : :
590 : 0 : rc = fill_crypto_xform(&cxf, type, prm);
591 [ # # ]: 0 : if (rc != 0)
592 : : return rc;
593 : :
594 : : /* initialize SA */
595 : :
596 [ # # ]: 0 : memset(sa, 0, sz);
597 : 0 : sa->type = type;
598 : 0 : sa->size = sz;
599 : :
600 : : /* check for ESN flag */
601 : 0 : sa->sqn_mask = (prm->ipsec_xform.options.esn == 0) ?
602 [ # # ]: 0 : UINT32_MAX : UINT64_MAX;
603 : :
604 : 0 : rc = esp_sa_init(sa, prm, &cxf);
605 [ # # ]: 0 : if (rc != 0)
606 : 0 : rte_ipsec_sa_fini(sa);
607 : :
608 : : /* fill replay window related fields */
609 [ # # ]: 0 : if (nb != 0)
610 [ # # ]: 0 : fill_sa_replay(sa, wsz, nb, prm->ipsec_xform.esn.value);
611 : :
612 : : return sz;
613 : : }
614 : :
615 : : /*
616 : : * setup crypto ops for LOOKASIDE_PROTO type of devices.
617 : : */
618 : : static inline void
619 : : lksd_proto_cop_prepare(const struct rte_ipsec_session *ss,
620 : : struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
621 : : {
622 : : uint32_t i;
623 : : struct rte_crypto_sym_op *sop;
624 : :
625 [ # # ]: 0 : for (i = 0; i != num; i++) {
626 : 0 : sop = cop[i]->sym;
627 : 0 : cop[i]->type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
628 : 0 : cop[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
629 : 0 : cop[i]->sess_type = RTE_CRYPTO_OP_SECURITY_SESSION;
630 : 0 : sop->m_src = mb[i];
631 : 0 : __rte_security_attach_session(sop, ss->security.ses);
632 : : }
633 : : }
634 : :
635 : : /*
636 : : * setup packets and crypto ops for LOOKASIDE_PROTO type of devices.
637 : : * Note that for LOOKASIDE_PROTO all packet modifications will be
638 : : * performed by PMD/HW.
639 : : * SW has only to prepare crypto op.
640 : : */
641 : : static uint16_t
642 : 0 : lksd_proto_prepare(const struct rte_ipsec_session *ss,
643 : : struct rte_mbuf *mb[], struct rte_crypto_op *cop[], uint16_t num)
644 : : {
645 : : lksd_proto_cop_prepare(ss, mb, cop, num);
646 : 0 : return num;
647 : : }
648 : :
649 : : /*
650 : : * simplest pkt process routine:
651 : : * all actual processing is already done by HW/PMD,
652 : : * just check mbuf ol_flags.
653 : : * used for:
654 : : * - inbound for RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL
655 : : * - inbound/outbound for RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL
656 : : * - outbound for RTE_SECURITY_ACTION_TYPE_NONE when ESN is disabled
657 : : */
658 : : uint16_t
659 : 0 : pkt_flag_process(const struct rte_ipsec_session *ss,
660 : : struct rte_mbuf *mb[], uint16_t num)
661 : 0 : {
662 : : uint32_t i, k, bytes;
663 : 0 : uint32_t dr[num];
664 : :
665 : : RTE_SET_USED(ss);
666 : :
667 : : k = 0;
668 : : bytes = 0;
669 [ # # ]: 0 : for (i = 0; i != num; i++) {
670 [ # # ]: 0 : if ((mb[i]->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED) == 0) {
671 : 0 : k++;
672 : 0 : bytes += mb[i]->pkt_len;
673 : : }
674 : : else
675 : 0 : dr[i - k] = i;
676 : : }
677 : :
678 : 0 : ss->sa->statistics.count += k;
679 : 0 : ss->sa->statistics.bytes += bytes;
680 : :
681 : : /* handle unprocessed mbufs */
682 [ # # ]: 0 : if (k != num) {
683 : 0 : rte_errno = EBADMSG;
684 [ # # ]: 0 : if (k != 0)
685 : 0 : move_bad_mbufs(mb, dr, num, num - k);
686 : : }
687 : :
688 : 0 : return k;
689 : : }
690 : :
691 : : /*
692 : : * Select packet processing function for session on LOOKASIDE_NONE
693 : : * type of device.
694 : : */
695 : : static int
696 : 0 : lksd_none_pkt_func_select(const struct rte_ipsec_sa *sa,
697 : : struct rte_ipsec_sa_pkt_func *pf)
698 : : {
699 : : int32_t rc;
700 : :
701 : : static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
702 : : RTE_IPSEC_SATP_MODE_MASK;
703 : :
704 : : rc = 0;
705 [ # # # # : 0 : switch (sa->type & msk) {
# ]
706 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
707 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
708 : 0 : pf->prepare.async = esp_inb_pkt_prepare;
709 : 0 : pf->process = esp_inb_tun_pkt_process;
710 : 0 : break;
711 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
712 : 0 : pf->prepare.async = esp_inb_pkt_prepare;
713 : 0 : pf->process = esp_inb_trs_pkt_process;
714 : 0 : break;
715 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
716 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
717 : 0 : pf->prepare.async = esp_outb_tun_prepare;
718 : 0 : pf->prepare_stateless.async = esp_outb_tun_prepare_stateless;
719 [ # # ]: 0 : pf->process = (sa->sqh_len != 0) ?
720 : : esp_outb_sqh_process : pkt_flag_process;
721 : 0 : break;
722 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
723 : 0 : pf->prepare.async = esp_outb_trs_prepare;
724 [ # # ]: 0 : pf->process = (sa->sqh_len != 0) ?
725 : : esp_outb_sqh_process : pkt_flag_process;
726 : 0 : break;
727 : : default:
728 : : rc = -ENOTSUP;
729 : : }
730 : :
731 : 0 : return rc;
732 : : }
733 : :
734 : : static int
735 : 0 : cpu_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
736 : : struct rte_ipsec_sa_pkt_func *pf)
737 : : {
738 : : int32_t rc;
739 : :
740 : : static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
741 : : RTE_IPSEC_SATP_MODE_MASK;
742 : :
743 : : rc = 0;
744 [ # # # # : 0 : switch (sa->type & msk) {
# ]
745 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
746 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
747 : 0 : pf->prepare.sync = cpu_inb_pkt_prepare;
748 : 0 : pf->process = esp_inb_tun_pkt_process;
749 : 0 : break;
750 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
751 : 0 : pf->prepare.sync = cpu_inb_pkt_prepare;
752 : 0 : pf->process = esp_inb_trs_pkt_process;
753 : 0 : break;
754 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
755 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
756 : 0 : pf->prepare.sync = cpu_outb_tun_pkt_prepare;
757 : 0 : pf->prepare_stateless.sync = cpu_outb_tun_pkt_prepare_stateless;
758 [ # # ]: 0 : pf->process = (sa->sqh_len != 0) ?
759 : : esp_outb_sqh_process : pkt_flag_process;
760 : 0 : break;
761 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
762 : 0 : pf->prepare.sync = cpu_outb_trs_pkt_prepare;
763 [ # # ]: 0 : pf->process = (sa->sqh_len != 0) ?
764 : : esp_outb_sqh_process : pkt_flag_process;
765 : 0 : break;
766 : : default:
767 : : rc = -ENOTSUP;
768 : : }
769 : :
770 : 0 : return rc;
771 : : }
772 : :
773 : : /*
774 : : * Select packet processing function for session on INLINE_CRYPTO
775 : : * type of device.
776 : : */
777 : : static int
778 : : inline_crypto_pkt_func_select(const struct rte_ipsec_sa *sa,
779 : : struct rte_ipsec_sa_pkt_func *pf)
780 : : {
781 : : int32_t rc;
782 : :
783 : : static const uint64_t msk = RTE_IPSEC_SATP_DIR_MASK |
784 : : RTE_IPSEC_SATP_MODE_MASK;
785 : :
786 : : rc = 0;
787 [ # # # # : 0 : switch (sa->type & msk) {
# ]
788 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV4):
789 : : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TUNLV6):
790 : 0 : pf->process = inline_inb_tun_pkt_process;
791 : 0 : break;
792 : 0 : case (RTE_IPSEC_SATP_DIR_IB | RTE_IPSEC_SATP_MODE_TRANS):
793 : 0 : pf->process = inline_inb_trs_pkt_process;
794 : 0 : break;
795 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV4):
796 : : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TUNLV6):
797 : 0 : pf->process = inline_outb_tun_pkt_process;
798 : 0 : break;
799 : 0 : case (RTE_IPSEC_SATP_DIR_OB | RTE_IPSEC_SATP_MODE_TRANS):
800 : 0 : pf->process = inline_outb_trs_pkt_process;
801 : 0 : break;
802 : : default:
803 : : rc = -ENOTSUP;
804 : : }
805 : :
806 : : return rc;
807 : : }
808 : :
809 : : /*
810 : : * Select packet processing function for given session based on SA parameters
811 : : * and type of associated with the session device.
812 : : */
813 : : int
814 : 0 : ipsec_sa_pkt_func_select(const struct rte_ipsec_session *ss,
815 : : const struct rte_ipsec_sa *sa, struct rte_ipsec_sa_pkt_func *pf)
816 : : {
817 : : int32_t rc;
818 : :
819 : : rc = 0;
820 : 0 : pf[0] = (struct rte_ipsec_sa_pkt_func) { {NULL}, {NULL}, NULL };
821 : :
822 [ # # # # : 0 : switch (ss->type) {
# # ]
823 : 0 : case RTE_SECURITY_ACTION_TYPE_NONE:
824 : 0 : rc = lksd_none_pkt_func_select(sa, pf);
825 : 0 : break;
826 : : case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO:
827 : : rc = inline_crypto_pkt_func_select(sa, pf);
828 : : break;
829 : 0 : case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL:
830 [ # # ]: 0 : if ((sa->type & RTE_IPSEC_SATP_DIR_MASK) ==
831 : : RTE_IPSEC_SATP_DIR_IB)
832 : 0 : pf->process = pkt_flag_process;
833 : : else
834 : 0 : pf->process = inline_proto_outb_pkt_process;
835 : : break;
836 : 0 : case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL:
837 : 0 : pf->prepare.async = lksd_proto_prepare;
838 : 0 : pf->process = pkt_flag_process;
839 : 0 : break;
840 : 0 : case RTE_SECURITY_ACTION_TYPE_CPU_CRYPTO:
841 : 0 : rc = cpu_crypto_pkt_func_select(sa, pf);
842 : 0 : break;
843 : : default:
844 : : rc = -ENOTSUP;
845 : : }
846 : :
847 : 0 : return rc;
848 : : }
|