1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2015-2017 Intel Corporation
5 #include <intel-ipsec-mb.h>
7 #include <rte_common.h>
8 #include <rte_hexdump.h>
9 #include <rte_cryptodev.h>
10 #include <rte_cryptodev_pmd.h>
11 #include <rte_bus_vdev.h>
12 #include <rte_malloc.h>
13 #include <rte_cpuflags.h>
15 #include "aesni_mb_pmd_private.h"
17 int aesni_mb_logtype_driver;
19 #define AES_CCM_DIGEST_MIN_LEN 4
20 #define AES_CCM_DIGEST_MAX_LEN 16
21 #define HMAC_MAX_BLOCK_SIZE 128
22 static uint8_t cryptodev_driver_id;
24 typedef void (*hash_one_block_t)(const void *data, void *digest);
25 typedef void (*aes_keyexp_t)(const void *key, void *enc_exp_keys, void *dec_exp_keys);
28 * Calculate the authentication pre-computes
30 * @param one_block_hash Function pointer to calculate digest on ipad/opad
31 * @param ipad Inner pad output byte array
32 * @param opad Outer pad output byte array
33 * @param hkey Authentication key
34 * @param hkey_len Authentication key length
35 * @param blocksize Block size of selected hash algo
38 calculate_auth_precomputes(hash_one_block_t one_block_hash,
39 uint8_t *ipad, uint8_t *opad,
40 const uint8_t *hkey, uint16_t hkey_len,
45 uint8_t ipad_buf[blocksize] __rte_aligned(16);
46 uint8_t opad_buf[blocksize] __rte_aligned(16);
48 /* Setup inner and outer pads */
49 memset(ipad_buf, HMAC_IPAD_VALUE, blocksize);
50 memset(opad_buf, HMAC_OPAD_VALUE, blocksize);
52 /* XOR hash key with inner and outer pads */
53 length = hkey_len > blocksize ? blocksize : hkey_len;
55 for (i = 0; i < length; i++) {
56 ipad_buf[i] ^= hkey[i];
57 opad_buf[i] ^= hkey[i];
60 /* Compute partial hashes */
61 (*one_block_hash)(ipad_buf, ipad);
62 (*one_block_hash)(opad_buf, opad);
65 memset(ipad_buf, 0, blocksize);
66 memset(opad_buf, 0, blocksize);
69 /** Get xform chain order */
70 static enum aesni_mb_operation
71 aesni_mb_get_chain_order(const struct rte_crypto_sym_xform *xform)
74 return AESNI_MB_OP_NOT_SUPPORTED;
76 if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
77 if (xform->next == NULL)
78 return AESNI_MB_OP_CIPHER_ONLY;
79 if (xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH)
80 return AESNI_MB_OP_CIPHER_HASH;
83 if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
84 if (xform->next == NULL)
85 return AESNI_MB_OP_HASH_ONLY;
86 if (xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
87 return AESNI_MB_OP_HASH_CIPHER;
89 #if IMB_VERSION_NUM > IMB_VERSION(0, 52, 0)
90 if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
91 if (xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) {
93 * CCM requires to hash first and cipher later
96 if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM)
97 return AESNI_MB_OP_AEAD_HASH_CIPHER;
99 return AESNI_MB_OP_AEAD_CIPHER_HASH;
101 if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM)
102 return AESNI_MB_OP_AEAD_CIPHER_HASH;
104 return AESNI_MB_OP_AEAD_HASH_CIPHER;
108 if (xform->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
109 if (xform->aead.algo == RTE_CRYPTO_AEAD_AES_CCM ||
110 xform->aead.algo == RTE_CRYPTO_AEAD_AES_GCM) {
111 if (xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT)
112 return AESNI_MB_OP_AEAD_CIPHER_HASH;
114 return AESNI_MB_OP_AEAD_HASH_CIPHER;
119 return AESNI_MB_OP_NOT_SUPPORTED;
122 /** Set session authentication parameters */
124 aesni_mb_set_session_auth_parameters(const MB_MGR *mb_mgr,
125 struct aesni_mb_session *sess,
126 const struct rte_crypto_sym_xform *xform)
128 hash_one_block_t hash_oneblock_fn = NULL;
129 unsigned int key_larger_block_size = 0;
130 uint8_t hashed_key[HMAC_MAX_BLOCK_SIZE] = { 0 };
131 uint32_t auth_precompute = 1;
134 sess->auth.algo = NULL_HASH;
138 if (xform->type != RTE_CRYPTO_SYM_XFORM_AUTH) {
139 AESNI_MB_LOG(ERR, "Crypto xform struct not of type auth");
143 /* Set the request digest size */
144 sess->auth.req_digest_len = xform->auth.digest_length;
146 /* Select auth generate/verify */
147 sess->auth.operation = xform->auth.op;
149 /* Set Authentication Parameters */
150 if (xform->auth.algo == RTE_CRYPTO_AUTH_AES_XCBC_MAC) {
151 sess->auth.algo = AES_XCBC;
153 uint16_t xcbc_mac_digest_len =
154 get_truncated_digest_byte_length(AES_XCBC);
155 if (sess->auth.req_digest_len != xcbc_mac_digest_len) {
156 AESNI_MB_LOG(ERR, "Invalid digest size\n");
159 sess->auth.gen_digest_len = sess->auth.req_digest_len;
161 IMB_AES_XCBC_KEYEXP(mb_mgr, xform->auth.key.data,
162 sess->auth.xcbc.k1_expanded,
163 sess->auth.xcbc.k2, sess->auth.xcbc.k3);
167 if (xform->auth.algo == RTE_CRYPTO_AUTH_AES_CMAC) {
170 sess->auth.algo = AES_CMAC;
172 uint16_t cmac_digest_len = get_digest_byte_length(AES_CMAC);
174 if (sess->auth.req_digest_len > cmac_digest_len) {
175 AESNI_MB_LOG(ERR, "Invalid digest size\n");
179 * Multi-buffer lib supports digest sizes from 4 to 16 bytes
180 * in version 0.50 and sizes of 12 and 16 bytes,
182 * If size requested is different, generate the full digest
183 * (16 bytes) in a temporary location and then memcpy
184 * the requested number of bytes.
186 if (sess->auth.req_digest_len < 4)
187 sess->auth.gen_digest_len = cmac_digest_len;
189 sess->auth.gen_digest_len = sess->auth.req_digest_len;
191 IMB_AES_KEYEXP_128(mb_mgr, xform->auth.key.data,
192 sess->auth.cmac.expkey, dust);
193 IMB_AES_CMAC_SUBKEY_GEN_128(mb_mgr, sess->auth.cmac.expkey,
194 sess->auth.cmac.skey1, sess->auth.cmac.skey2);
198 if (xform->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) {
199 if (xform->auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) {
200 sess->cipher.direction = ENCRYPT;
201 sess->chain_order = CIPHER_HASH;
203 sess->cipher.direction = DECRYPT;
205 sess->auth.algo = AES_GMAC;
207 * Multi-buffer lib supports 8, 12 and 16 bytes of digest.
208 * If size requested is different, generate the full digest
209 * (16 bytes) in a temporary location and then memcpy
210 * the requested number of bytes.
212 if (sess->auth.req_digest_len != 16 &&
213 sess->auth.req_digest_len != 12 &&
214 sess->auth.req_digest_len != 8) {
215 sess->auth.gen_digest_len = 16;
217 sess->auth.gen_digest_len = sess->auth.req_digest_len;
219 sess->iv.length = xform->auth.iv.length;
220 sess->iv.offset = xform->auth.iv.offset;
222 switch (xform->auth.key.length) {
224 IMB_AES128_GCM_PRE(mb_mgr, xform->auth.key.data,
225 &sess->cipher.gcm_key);
226 sess->cipher.key_length_in_bytes = AES_128_BYTES;
229 IMB_AES192_GCM_PRE(mb_mgr, xform->auth.key.data,
230 &sess->cipher.gcm_key);
231 sess->cipher.key_length_in_bytes = AES_192_BYTES;
234 IMB_AES256_GCM_PRE(mb_mgr, xform->auth.key.data,
235 &sess->cipher.gcm_key);
236 sess->cipher.key_length_in_bytes = AES_256_BYTES;
239 RTE_LOG(ERR, PMD, "failed to parse test type\n");
246 switch (xform->auth.algo) {
247 case RTE_CRYPTO_AUTH_MD5_HMAC:
248 sess->auth.algo = MD5;
249 hash_oneblock_fn = mb_mgr->md5_one_block;
251 case RTE_CRYPTO_AUTH_SHA1_HMAC:
252 sess->auth.algo = SHA1;
253 hash_oneblock_fn = mb_mgr->sha1_one_block;
254 if (xform->auth.key.length > get_auth_algo_blocksize(SHA1)) {
256 xform->auth.key.data,
257 xform->auth.key.length,
259 key_larger_block_size = 1;
262 case RTE_CRYPTO_AUTH_SHA1:
263 sess->auth.algo = PLAIN_SHA1;
266 case RTE_CRYPTO_AUTH_SHA224_HMAC:
267 sess->auth.algo = SHA_224;
268 hash_oneblock_fn = mb_mgr->sha224_one_block;
269 if (xform->auth.key.length > get_auth_algo_blocksize(SHA_224)) {
271 xform->auth.key.data,
272 xform->auth.key.length,
274 key_larger_block_size = 1;
277 case RTE_CRYPTO_AUTH_SHA224:
278 sess->auth.algo = PLAIN_SHA_224;
281 case RTE_CRYPTO_AUTH_SHA256_HMAC:
282 sess->auth.algo = SHA_256;
283 hash_oneblock_fn = mb_mgr->sha256_one_block;
284 if (xform->auth.key.length > get_auth_algo_blocksize(SHA_256)) {
286 xform->auth.key.data,
287 xform->auth.key.length,
289 key_larger_block_size = 1;
292 case RTE_CRYPTO_AUTH_SHA256:
293 sess->auth.algo = PLAIN_SHA_256;
296 case RTE_CRYPTO_AUTH_SHA384_HMAC:
297 sess->auth.algo = SHA_384;
298 hash_oneblock_fn = mb_mgr->sha384_one_block;
299 if (xform->auth.key.length > get_auth_algo_blocksize(SHA_384)) {
301 xform->auth.key.data,
302 xform->auth.key.length,
304 key_larger_block_size = 1;
307 case RTE_CRYPTO_AUTH_SHA384:
308 sess->auth.algo = PLAIN_SHA_384;
311 case RTE_CRYPTO_AUTH_SHA512_HMAC:
312 sess->auth.algo = SHA_512;
313 hash_oneblock_fn = mb_mgr->sha512_one_block;
314 if (xform->auth.key.length > get_auth_algo_blocksize(SHA_512)) {
316 xform->auth.key.data,
317 xform->auth.key.length,
319 key_larger_block_size = 1;
322 case RTE_CRYPTO_AUTH_SHA512:
323 sess->auth.algo = PLAIN_SHA_512;
327 AESNI_MB_LOG(ERR, "Unsupported authentication algorithm selection");
330 uint16_t trunc_digest_size =
331 get_truncated_digest_byte_length(sess->auth.algo);
332 uint16_t full_digest_size =
333 get_digest_byte_length(sess->auth.algo);
335 if (sess->auth.req_digest_len > full_digest_size ||
336 sess->auth.req_digest_len == 0) {
337 AESNI_MB_LOG(ERR, "Invalid digest size\n");
341 if (sess->auth.req_digest_len != trunc_digest_size &&
342 sess->auth.req_digest_len != full_digest_size)
343 sess->auth.gen_digest_len = full_digest_size;
345 sess->auth.gen_digest_len = sess->auth.req_digest_len;
347 /* Plain SHA does not require precompute key */
348 if (auth_precompute == 0)
351 /* Calculate Authentication precomputes */
352 if (key_larger_block_size) {
353 calculate_auth_precomputes(hash_oneblock_fn,
354 sess->auth.pads.inner, sess->auth.pads.outer,
356 xform->auth.key.length,
357 get_auth_algo_blocksize(sess->auth.algo));
359 calculate_auth_precomputes(hash_oneblock_fn,
360 sess->auth.pads.inner, sess->auth.pads.outer,
361 xform->auth.key.data,
362 xform->auth.key.length,
363 get_auth_algo_blocksize(sess->auth.algo));
369 /** Set session cipher parameters */
371 aesni_mb_set_session_cipher_parameters(const MB_MGR *mb_mgr,
372 struct aesni_mb_session *sess,
373 const struct rte_crypto_sym_xform *xform)
379 sess->cipher.mode = NULL_CIPHER;
383 if (xform->type != RTE_CRYPTO_SYM_XFORM_CIPHER) {
384 AESNI_MB_LOG(ERR, "Crypto xform struct not of type cipher");
388 /* Select cipher direction */
389 switch (xform->cipher.op) {
390 case RTE_CRYPTO_CIPHER_OP_ENCRYPT:
391 sess->cipher.direction = ENCRYPT;
393 case RTE_CRYPTO_CIPHER_OP_DECRYPT:
394 sess->cipher.direction = DECRYPT;
397 AESNI_MB_LOG(ERR, "Invalid cipher operation parameter");
401 /* Select cipher mode */
402 switch (xform->cipher.algo) {
403 case RTE_CRYPTO_CIPHER_AES_CBC:
404 sess->cipher.mode = CBC;
407 case RTE_CRYPTO_CIPHER_AES_CTR:
408 sess->cipher.mode = CNTR;
411 case RTE_CRYPTO_CIPHER_AES_DOCSISBPI:
412 sess->cipher.mode = DOCSIS_SEC_BPI;
415 case RTE_CRYPTO_CIPHER_DES_CBC:
416 sess->cipher.mode = DES;
418 case RTE_CRYPTO_CIPHER_DES_DOCSISBPI:
419 sess->cipher.mode = DOCSIS_DES;
421 case RTE_CRYPTO_CIPHER_3DES_CBC:
422 sess->cipher.mode = DES3;
426 AESNI_MB_LOG(ERR, "Unsupported cipher mode parameter");
430 /* Set IV parameters */
431 sess->iv.offset = xform->cipher.iv.offset;
432 sess->iv.length = xform->cipher.iv.length;
434 /* Check key length and choose key expansion function for AES */
436 switch (xform->cipher.key.length) {
438 sess->cipher.key_length_in_bytes = AES_128_BYTES;
439 IMB_AES_KEYEXP_128(mb_mgr, xform->cipher.key.data,
440 sess->cipher.expanded_aes_keys.encode,
441 sess->cipher.expanded_aes_keys.decode);
444 sess->cipher.key_length_in_bytes = AES_192_BYTES;
445 IMB_AES_KEYEXP_192(mb_mgr, xform->cipher.key.data,
446 sess->cipher.expanded_aes_keys.encode,
447 sess->cipher.expanded_aes_keys.decode);
450 sess->cipher.key_length_in_bytes = AES_256_BYTES;
451 IMB_AES_KEYEXP_256(mb_mgr, xform->cipher.key.data,
452 sess->cipher.expanded_aes_keys.encode,
453 sess->cipher.expanded_aes_keys.decode);
456 AESNI_MB_LOG(ERR, "Invalid cipher key length");
459 } else if (is_3DES) {
460 uint64_t *keys[3] = {sess->cipher.exp_3des_keys.key[0],
461 sess->cipher.exp_3des_keys.key[1],
462 sess->cipher.exp_3des_keys.key[2]};
464 switch (xform->cipher.key.length) {
466 IMB_DES_KEYSCHED(mb_mgr, keys[0],
467 xform->cipher.key.data);
468 IMB_DES_KEYSCHED(mb_mgr, keys[1],
469 xform->cipher.key.data + 8);
470 IMB_DES_KEYSCHED(mb_mgr, keys[2],
471 xform->cipher.key.data + 16);
473 /* Initialize keys - 24 bytes: [K1-K2-K3] */
474 sess->cipher.exp_3des_keys.ks_ptr[0] = keys[0];
475 sess->cipher.exp_3des_keys.ks_ptr[1] = keys[1];
476 sess->cipher.exp_3des_keys.ks_ptr[2] = keys[2];
479 IMB_DES_KEYSCHED(mb_mgr, keys[0],
480 xform->cipher.key.data);
481 IMB_DES_KEYSCHED(mb_mgr, keys[1],
482 xform->cipher.key.data + 8);
483 /* Initialize keys - 16 bytes: [K1=K1,K2=K2,K3=K1] */
484 sess->cipher.exp_3des_keys.ks_ptr[0] = keys[0];
485 sess->cipher.exp_3des_keys.ks_ptr[1] = keys[1];
486 sess->cipher.exp_3des_keys.ks_ptr[2] = keys[0];
489 IMB_DES_KEYSCHED(mb_mgr, keys[0],
490 xform->cipher.key.data);
492 /* Initialize keys - 8 bytes: [K1 = K2 = K3] */
493 sess->cipher.exp_3des_keys.ks_ptr[0] = keys[0];
494 sess->cipher.exp_3des_keys.ks_ptr[1] = keys[0];
495 sess->cipher.exp_3des_keys.ks_ptr[2] = keys[0];
498 AESNI_MB_LOG(ERR, "Invalid cipher key length");
502 sess->cipher.key_length_in_bytes = 24;
504 if (xform->cipher.key.length != 8) {
505 AESNI_MB_LOG(ERR, "Invalid cipher key length");
508 sess->cipher.key_length_in_bytes = 8;
510 IMB_DES_KEYSCHED(mb_mgr,
511 (uint64_t *)sess->cipher.expanded_aes_keys.encode,
512 xform->cipher.key.data);
513 IMB_DES_KEYSCHED(mb_mgr,
514 (uint64_t *)sess->cipher.expanded_aes_keys.decode,
515 xform->cipher.key.data);
522 aesni_mb_set_session_aead_parameters(const MB_MGR *mb_mgr,
523 struct aesni_mb_session *sess,
524 const struct rte_crypto_sym_xform *xform)
526 switch (xform->aead.op) {
527 case RTE_CRYPTO_AEAD_OP_ENCRYPT:
528 sess->cipher.direction = ENCRYPT;
529 sess->auth.operation = RTE_CRYPTO_AUTH_OP_GENERATE;
531 case RTE_CRYPTO_AEAD_OP_DECRYPT:
532 sess->cipher.direction = DECRYPT;
533 sess->auth.operation = RTE_CRYPTO_AUTH_OP_VERIFY;
536 AESNI_MB_LOG(ERR, "Invalid aead operation parameter");
540 switch (xform->aead.algo) {
541 case RTE_CRYPTO_AEAD_AES_CCM:
542 sess->cipher.mode = CCM;
543 sess->auth.algo = AES_CCM;
545 /* Check key length and choose key expansion function for AES */
546 switch (xform->aead.key.length) {
548 sess->cipher.key_length_in_bytes = AES_128_BYTES;
549 IMB_AES_KEYEXP_128(mb_mgr, xform->aead.key.data,
550 sess->cipher.expanded_aes_keys.encode,
551 sess->cipher.expanded_aes_keys.decode);
554 AESNI_MB_LOG(ERR, "Invalid cipher key length");
560 case RTE_CRYPTO_AEAD_AES_GCM:
561 sess->cipher.mode = GCM;
562 sess->auth.algo = AES_GMAC;
564 switch (xform->aead.key.length) {
566 sess->cipher.key_length_in_bytes = AES_128_BYTES;
567 IMB_AES128_GCM_PRE(mb_mgr, xform->aead.key.data,
568 &sess->cipher.gcm_key);
571 sess->cipher.key_length_in_bytes = AES_192_BYTES;
572 IMB_AES192_GCM_PRE(mb_mgr, xform->aead.key.data,
573 &sess->cipher.gcm_key);
576 sess->cipher.key_length_in_bytes = AES_256_BYTES;
577 IMB_AES256_GCM_PRE(mb_mgr, xform->aead.key.data,
578 &sess->cipher.gcm_key);
581 AESNI_MB_LOG(ERR, "Invalid cipher key length");
588 AESNI_MB_LOG(ERR, "Unsupported aead mode parameter");
592 /* Set IV parameters */
593 sess->iv.offset = xform->aead.iv.offset;
594 sess->iv.length = xform->aead.iv.length;
596 sess->auth.req_digest_len = xform->aead.digest_length;
597 /* CCM digests must be between 4 and 16 and an even number */
598 if (sess->auth.req_digest_len < AES_CCM_DIGEST_MIN_LEN ||
599 sess->auth.req_digest_len > AES_CCM_DIGEST_MAX_LEN ||
600 (sess->auth.req_digest_len & 1) == 1) {
601 AESNI_MB_LOG(ERR, "Invalid digest size\n");
604 sess->auth.gen_digest_len = sess->auth.req_digest_len;
609 /** Parse crypto xform chain and set private session parameters */
611 aesni_mb_set_session_parameters(const MB_MGR *mb_mgr,
612 struct aesni_mb_session *sess,
613 const struct rte_crypto_sym_xform *xform)
615 const struct rte_crypto_sym_xform *auth_xform = NULL;
616 const struct rte_crypto_sym_xform *cipher_xform = NULL;
617 const struct rte_crypto_sym_xform *aead_xform = NULL;
620 /* Select Crypto operation - hash then cipher / cipher then hash */
621 switch (aesni_mb_get_chain_order(xform)) {
622 case AESNI_MB_OP_HASH_CIPHER:
623 sess->chain_order = HASH_CIPHER;
625 cipher_xform = xform->next;
627 case AESNI_MB_OP_CIPHER_HASH:
628 sess->chain_order = CIPHER_HASH;
629 auth_xform = xform->next;
630 cipher_xform = xform;
632 case AESNI_MB_OP_HASH_ONLY:
633 sess->chain_order = HASH_CIPHER;
637 case AESNI_MB_OP_CIPHER_ONLY:
639 * Multi buffer library operates only at two modes,
640 * CIPHER_HASH and HASH_CIPHER. When doing ciphering only,
641 * chain order depends on cipher operation: encryption is always
642 * the first operation and decryption the last one.
644 if (xform->cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
645 sess->chain_order = CIPHER_HASH;
647 sess->chain_order = HASH_CIPHER;
649 cipher_xform = xform;
651 case AESNI_MB_OP_AEAD_CIPHER_HASH:
652 sess->chain_order = CIPHER_HASH;
653 sess->aead.aad_len = xform->aead.aad_length;
656 case AESNI_MB_OP_AEAD_HASH_CIPHER:
657 sess->chain_order = HASH_CIPHER;
658 sess->aead.aad_len = xform->aead.aad_length;
661 case AESNI_MB_OP_NOT_SUPPORTED:
663 AESNI_MB_LOG(ERR, "Unsupported operation chain order parameter");
667 /* Default IV length = 0 */
670 ret = aesni_mb_set_session_auth_parameters(mb_mgr, sess, auth_xform);
672 AESNI_MB_LOG(ERR, "Invalid/unsupported authentication parameters");
676 ret = aesni_mb_set_session_cipher_parameters(mb_mgr, sess,
679 AESNI_MB_LOG(ERR, "Invalid/unsupported cipher parameters");
684 ret = aesni_mb_set_session_aead_parameters(mb_mgr, sess,
687 AESNI_MB_LOG(ERR, "Invalid/unsupported aead parameters");
696 * burst enqueue, place crypto operations on ingress queue for processing.
698 * @param __qp Queue Pair to process
699 * @param ops Crypto operations for processing
700 * @param nb_ops Number of crypto operations for processing
703 * - Number of crypto operations enqueued
706 aesni_mb_pmd_enqueue_burst(void *__qp, struct rte_crypto_op **ops,
709 struct aesni_mb_qp *qp = __qp;
711 unsigned int nb_enqueued;
713 nb_enqueued = rte_ring_enqueue_burst(qp->ingress_queue,
714 (void **)ops, nb_ops, NULL);
716 qp->stats.enqueued_count += nb_enqueued;
721 /** Get multi buffer session */
722 static inline struct aesni_mb_session *
723 get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *op)
725 struct aesni_mb_session *sess = NULL;
727 if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
728 if (likely(op->sym->session != NULL))
729 sess = (struct aesni_mb_session *)
730 get_sym_session_private_data(
732 cryptodev_driver_id);
734 void *_sess = rte_cryptodev_sym_session_create(qp->sess_mp);
735 void *_sess_private_data = NULL;
740 if (rte_mempool_get(qp->sess_mp_priv,
741 (void **)&_sess_private_data))
744 sess = (struct aesni_mb_session *)_sess_private_data;
746 if (unlikely(aesni_mb_set_session_parameters(qp->mb_mgr,
747 sess, op->sym->xform) != 0)) {
748 rte_mempool_put(qp->sess_mp, _sess);
749 rte_mempool_put(qp->sess_mp_priv, _sess_private_data);
752 op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
753 set_sym_session_private_data(op->sym->session,
754 cryptodev_driver_id, _sess_private_data);
757 if (unlikely(sess == NULL))
758 op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
763 static inline uint64_t
764 auth_start_offset(struct rte_crypto_op *op, struct aesni_mb_session *session,
767 struct rte_mbuf *m_src, *m_dst;
768 uint8_t *p_src, *p_dst;
769 uintptr_t u_src, u_dst;
770 uint32_t cipher_end, auth_end;
772 /* Only cipher then hash needs special calculation. */
773 if (!oop || session->chain_order != CIPHER_HASH)
774 return op->sym->auth.data.offset;
776 m_src = op->sym->m_src;
777 m_dst = op->sym->m_dst;
779 p_src = rte_pktmbuf_mtod(m_src, uint8_t *);
780 p_dst = rte_pktmbuf_mtod(m_dst, uint8_t *);
781 u_src = (uintptr_t)p_src;
782 u_dst = (uintptr_t)p_dst + op->sym->auth.data.offset;
785 * Copy the content between cipher offset and auth offset for generating
788 if (op->sym->cipher.data.offset > op->sym->auth.data.offset)
789 memcpy(p_dst + op->sym->auth.data.offset,
790 p_src + op->sym->auth.data.offset,
791 op->sym->cipher.data.offset -
792 op->sym->auth.data.offset);
795 * Copy the content between (cipher offset + length) and (auth offset +
796 * length) for generating correct digest
798 cipher_end = op->sym->cipher.data.offset + op->sym->cipher.data.length;
799 auth_end = op->sym->auth.data.offset + op->sym->auth.data.length;
800 if (cipher_end < auth_end)
801 memcpy(p_dst + cipher_end, p_src + cipher_end,
802 auth_end - cipher_end);
805 * Since intel-ipsec-mb only supports positive values,
806 * we need to deduct the correct offset between src and dst.
809 return u_src < u_dst ? (u_dst - u_src) :
810 (UINT64_MAX - u_src + u_dst + 1);
814 * Process a crypto operation and complete a JOB_AES_HMAC job structure for
815 * submission to the multi buffer library for processing.
817 * @param qp queue pair
818 * @param job JOB_AES_HMAC structure to fill
819 * @param m mbuf to process
822 * - Completed JOB_AES_HMAC structure pointer on success
823 * - NULL pointer if completion of JOB_AES_HMAC structure isn't possible
826 set_mb_job_params(JOB_AES_HMAC *job, struct aesni_mb_qp *qp,
827 struct rte_crypto_op *op, uint8_t *digest_idx)
829 struct rte_mbuf *m_src = op->sym->m_src, *m_dst;
830 struct aesni_mb_session *session;
831 uint32_t m_offset, oop;
833 session = get_session(qp, op);
834 if (session == NULL) {
835 op->status = RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
839 /* Set crypto operation */
840 job->chain_order = session->chain_order;
842 /* Set cipher parameters */
843 job->cipher_direction = session->cipher.direction;
844 job->cipher_mode = session->cipher.mode;
846 job->aes_key_len_in_bytes = session->cipher.key_length_in_bytes;
848 /* Set authentication parameters */
849 job->hash_alg = session->auth.algo;
851 switch (job->hash_alg) {
853 job->u.XCBC._k1_expanded = session->auth.xcbc.k1_expanded;
854 job->u.XCBC._k2 = session->auth.xcbc.k2;
855 job->u.XCBC._k3 = session->auth.xcbc.k3;
857 job->aes_enc_key_expanded =
858 session->cipher.expanded_aes_keys.encode;
859 job->aes_dec_key_expanded =
860 session->cipher.expanded_aes_keys.decode;
864 job->u.CCM.aad = op->sym->aead.aad.data + 18;
865 job->u.CCM.aad_len_in_bytes = session->aead.aad_len;
866 job->aes_enc_key_expanded =
867 session->cipher.expanded_aes_keys.encode;
868 job->aes_dec_key_expanded =
869 session->cipher.expanded_aes_keys.decode;
873 job->u.CMAC._key_expanded = session->auth.cmac.expkey;
874 job->u.CMAC._skey1 = session->auth.cmac.skey1;
875 job->u.CMAC._skey2 = session->auth.cmac.skey2;
876 job->aes_enc_key_expanded =
877 session->cipher.expanded_aes_keys.encode;
878 job->aes_dec_key_expanded =
879 session->cipher.expanded_aes_keys.decode;
883 if (session->cipher.mode == GCM) {
884 job->u.GCM.aad = op->sym->aead.aad.data;
885 job->u.GCM.aad_len_in_bytes = session->aead.aad_len;
888 job->u.GCM.aad = rte_pktmbuf_mtod_offset(m_src,
889 uint8_t *, op->sym->auth.data.offset);
890 job->u.GCM.aad_len_in_bytes = op->sym->auth.data.length;
891 job->cipher_mode = GCM;
893 job->aes_enc_key_expanded = &session->cipher.gcm_key;
894 job->aes_dec_key_expanded = &session->cipher.gcm_key;
898 job->u.HMAC._hashed_auth_key_xor_ipad = session->auth.pads.inner;
899 job->u.HMAC._hashed_auth_key_xor_opad = session->auth.pads.outer;
901 if (job->cipher_mode == DES3) {
902 job->aes_enc_key_expanded =
903 session->cipher.exp_3des_keys.ks_ptr;
904 job->aes_dec_key_expanded =
905 session->cipher.exp_3des_keys.ks_ptr;
907 job->aes_enc_key_expanded =
908 session->cipher.expanded_aes_keys.encode;
909 job->aes_dec_key_expanded =
910 session->cipher.expanded_aes_keys.decode;
914 if (!op->sym->m_dst) {
915 /* in-place operation */
918 } else if (op->sym->m_dst == op->sym->m_src) {
919 /* in-place operation */
923 /* out-of-place operation */
924 m_dst = op->sym->m_dst;
928 if (job->hash_alg == AES_CCM || (job->hash_alg == AES_GMAC &&
929 session->cipher.mode == GCM))
930 m_offset = op->sym->aead.data.offset;
932 m_offset = op->sym->cipher.data.offset;
934 /* Set digest output location */
935 if (job->hash_alg != NULL_HASH &&
936 session->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY) {
937 job->auth_tag_output = qp->temp_digests[*digest_idx];
938 *digest_idx = (*digest_idx + 1) % MAX_JOBS;
940 if (job->hash_alg == AES_CCM || (job->hash_alg == AES_GMAC &&
941 session->cipher.mode == GCM))
942 job->auth_tag_output = op->sym->aead.digest.data;
944 job->auth_tag_output = op->sym->auth.digest.data;
946 if (session->auth.req_digest_len != session->auth.gen_digest_len) {
947 job->auth_tag_output = qp->temp_digests[*digest_idx];
948 *digest_idx = (*digest_idx + 1) % MAX_JOBS;
952 * Multi-buffer library current only support returning a truncated
953 * digest length as specified in the relevant IPsec RFCs
956 /* Set digest length */
957 job->auth_tag_output_len_in_bytes = session->auth.gen_digest_len;
959 /* Set IV parameters */
960 job->iv_len_in_bytes = session->iv.length;
962 /* Data Parameters */
963 job->src = rte_pktmbuf_mtod(m_src, uint8_t *);
964 job->dst = rte_pktmbuf_mtod_offset(m_dst, uint8_t *, m_offset);
966 switch (job->hash_alg) {
968 job->cipher_start_src_offset_in_bytes =
969 op->sym->aead.data.offset;
970 job->msg_len_to_cipher_in_bytes = op->sym->aead.data.length;
971 job->hash_start_src_offset_in_bytes = op->sym->aead.data.offset;
972 job->msg_len_to_hash_in_bytes = op->sym->aead.data.length;
974 job->iv = rte_crypto_op_ctod_offset(op, uint8_t *,
975 session->iv.offset + 1);
979 if (session->cipher.mode == GCM) {
980 job->cipher_start_src_offset_in_bytes =
981 op->sym->aead.data.offset;
982 job->hash_start_src_offset_in_bytes =
983 op->sym->aead.data.offset;
984 job->msg_len_to_cipher_in_bytes =
985 op->sym->aead.data.length;
986 job->msg_len_to_hash_in_bytes =
987 op->sym->aead.data.length;
989 job->cipher_start_src_offset_in_bytes =
990 op->sym->auth.data.offset;
991 job->hash_start_src_offset_in_bytes =
992 op->sym->auth.data.offset;
993 job->msg_len_to_cipher_in_bytes = 0;
994 job->msg_len_to_hash_in_bytes = 0;
997 job->iv = rte_crypto_op_ctod_offset(op, uint8_t *,
1002 job->cipher_start_src_offset_in_bytes =
1003 op->sym->cipher.data.offset;
1004 job->msg_len_to_cipher_in_bytes = op->sym->cipher.data.length;
1006 job->hash_start_src_offset_in_bytes = auth_start_offset(op,
1008 job->msg_len_to_hash_in_bytes = op->sym->auth.data.length;
1010 job->iv = rte_crypto_op_ctod_offset(op, uint8_t *,
1011 session->iv.offset);
1014 /* Set user data to be crypto operation data struct */
1015 job->user_data = op;
1021 verify_digest(JOB_AES_HMAC *job, void *digest, uint16_t len, uint8_t *status)
1023 /* Verify digest if required */
1024 if (memcmp(job->auth_tag_output, digest, len) != 0)
1025 *status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
1029 generate_digest(JOB_AES_HMAC *job, struct rte_crypto_op *op,
1030 struct aesni_mb_session *sess)
1032 /* No extra copy needed */
1033 if (likely(sess->auth.req_digest_len == sess->auth.gen_digest_len))
1037 * This can only happen for HMAC, so only digest
1038 * for authentication algos is required
1040 memcpy(op->sym->auth.digest.data, job->auth_tag_output,
1041 sess->auth.req_digest_len);
1045 * Process a completed job and return rte_mbuf which job processed
1047 * @param qp Queue Pair to process
1048 * @param job JOB_AES_HMAC job to process
1051 * - Returns processed crypto operation.
1052 * - Returns NULL on invalid job
1054 static inline struct rte_crypto_op *
1055 post_process_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
1057 struct rte_crypto_op *op = (struct rte_crypto_op *)job->user_data;
1058 struct aesni_mb_session *sess = get_sym_session_private_data(
1060 cryptodev_driver_id);
1062 if (likely(op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)) {
1063 switch (job->status) {
1065 op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
1067 if (job->hash_alg == NULL_HASH)
1070 if (sess->auth.operation == RTE_CRYPTO_AUTH_OP_VERIFY) {
1071 if (job->hash_alg == AES_CCM ||
1072 (job->hash_alg == AES_GMAC &&
1073 sess->cipher.mode == GCM))
1075 op->sym->aead.digest.data,
1076 sess->auth.req_digest_len,
1080 op->sym->auth.digest.data,
1081 sess->auth.req_digest_len,
1084 generate_digest(job, op, sess);
1087 op->status = RTE_CRYPTO_OP_STATUS_ERROR;
1091 /* Free session if a session-less crypto op */
1092 if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
1093 memset(sess, 0, sizeof(struct aesni_mb_session));
1094 memset(op->sym->session, 0,
1095 rte_cryptodev_sym_get_existing_header_session_size(
1097 rte_mempool_put(qp->sess_mp_priv, sess);
1098 rte_mempool_put(qp->sess_mp, op->sym->session);
1099 op->sym->session = NULL;
1106 * Process a completed JOB_AES_HMAC job and keep processing jobs until
1107 * get_completed_job return NULL
1109 * @param qp Queue Pair to process
1110 * @param job JOB_AES_HMAC job
1113 * - Number of processed jobs
1116 handle_completed_jobs(struct aesni_mb_qp *qp, JOB_AES_HMAC *job,
1117 struct rte_crypto_op **ops, uint16_t nb_ops)
1119 struct rte_crypto_op *op = NULL;
1120 unsigned processed_jobs = 0;
1122 while (job != NULL) {
1123 op = post_process_mb_job(qp, job);
1126 ops[processed_jobs++] = op;
1127 qp->stats.dequeued_count++;
1129 qp->stats.dequeue_err_count++;
1132 if (processed_jobs == nb_ops)
1135 job = IMB_GET_COMPLETED_JOB(qp->mb_mgr);
1138 return processed_jobs;
1141 static inline uint16_t
1142 flush_mb_mgr(struct aesni_mb_qp *qp, struct rte_crypto_op **ops,
1145 int processed_ops = 0;
1147 /* Flush the remaining jobs */
1148 JOB_AES_HMAC *job = IMB_FLUSH_JOB(qp->mb_mgr);
1151 processed_ops += handle_completed_jobs(qp, job,
1152 &ops[processed_ops], nb_ops - processed_ops);
1154 return processed_ops;
1157 static inline JOB_AES_HMAC *
1158 set_job_null_op(JOB_AES_HMAC *job, struct rte_crypto_op *op)
1160 job->chain_order = HASH_CIPHER;
1161 job->cipher_mode = NULL_CIPHER;
1162 job->hash_alg = NULL_HASH;
1163 job->cipher_direction = DECRYPT;
1165 /* Set user data to be crypto operation data struct */
1166 job->user_data = op;
1172 aesni_mb_pmd_dequeue_burst(void *queue_pair, struct rte_crypto_op **ops,
1175 struct aesni_mb_qp *qp = queue_pair;
1177 struct rte_crypto_op *op;
1180 int retval, processed_jobs = 0;
1182 if (unlikely(nb_ops == 0))
1185 uint8_t digest_idx = qp->digest_idx;
1187 /* Get next free mb job struct from mb manager */
1188 job = IMB_GET_NEXT_JOB(qp->mb_mgr);
1189 if (unlikely(job == NULL)) {
1190 /* if no free mb job structs we need to flush mb_mgr */
1191 processed_jobs += flush_mb_mgr(qp,
1192 &ops[processed_jobs],
1193 nb_ops - processed_jobs);
1195 if (nb_ops == processed_jobs)
1198 job = IMB_GET_NEXT_JOB(qp->mb_mgr);
1202 * Get next operation to process from ingress queue.
1203 * There is no need to return the job to the MB_MGR
1204 * if there are no more operations to process, since the MB_MGR
1205 * can use that pointer again in next get_next calls.
1207 retval = rte_ring_dequeue(qp->ingress_queue, (void **)&op);
1211 retval = set_mb_job_params(job, qp, op, &digest_idx);
1212 if (unlikely(retval != 0)) {
1213 qp->stats.dequeue_err_count++;
1214 set_job_null_op(job, op);
1217 /* Submit job to multi-buffer for processing */
1218 #ifdef RTE_LIBRTE_PMD_AESNI_MB_DEBUG
1219 job = IMB_SUBMIT_JOB(qp->mb_mgr);
1221 job = IMB_SUBMIT_JOB_NOCHECK(qp->mb_mgr);
1224 * If submit returns a processed job then handle it,
1225 * before submitting subsequent jobs
1228 processed_jobs += handle_completed_jobs(qp, job,
1229 &ops[processed_jobs],
1230 nb_ops - processed_jobs);
1232 } while (processed_jobs < nb_ops);
1234 qp->digest_idx = digest_idx;
1236 if (processed_jobs < 1)
1237 processed_jobs += flush_mb_mgr(qp,
1238 &ops[processed_jobs],
1239 nb_ops - processed_jobs);
1241 return processed_jobs;
1244 static int cryptodev_aesni_mb_remove(struct rte_vdev_device *vdev);
1247 cryptodev_aesni_mb_create(const char *name,
1248 struct rte_vdev_device *vdev,
1249 struct rte_cryptodev_pmd_init_params *init_params)
1251 struct rte_cryptodev *dev;
1252 struct aesni_mb_private *internals;
1253 enum aesni_mb_vector_mode vector_mode;
1256 dev = rte_cryptodev_pmd_create(name, &vdev->device, init_params);
1258 AESNI_MB_LOG(ERR, "failed to create cryptodev vdev");
1262 /* Check CPU for supported vector instruction set */
1263 if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F))
1264 vector_mode = RTE_AESNI_MB_AVX512;
1265 else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
1266 vector_mode = RTE_AESNI_MB_AVX2;
1267 else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX))
1268 vector_mode = RTE_AESNI_MB_AVX;
1270 vector_mode = RTE_AESNI_MB_SSE;
1272 dev->driver_id = cryptodev_driver_id;
1273 dev->dev_ops = rte_aesni_mb_pmd_ops;
1275 /* register rx/tx burst functions for data path */
1276 dev->dequeue_burst = aesni_mb_pmd_dequeue_burst;
1277 dev->enqueue_burst = aesni_mb_pmd_enqueue_burst;
1279 dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
1280 RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING |
1281 RTE_CRYPTODEV_FF_OOP_LB_IN_LB_OUT;
1283 /* Check CPU for support for AES instruction set */
1284 if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AES))
1285 dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AESNI;
1287 AESNI_MB_LOG(WARNING, "AES instructions not supported by CPU");
1289 mb_mgr = alloc_mb_mgr(0);
1293 switch (vector_mode) {
1294 case RTE_AESNI_MB_SSE:
1295 dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_SSE;
1296 init_mb_mgr_sse(mb_mgr);
1298 case RTE_AESNI_MB_AVX:
1299 dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AVX;
1300 init_mb_mgr_avx(mb_mgr);
1302 case RTE_AESNI_MB_AVX2:
1303 dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AVX2;
1304 init_mb_mgr_avx2(mb_mgr);
1306 case RTE_AESNI_MB_AVX512:
1307 dev->feature_flags |= RTE_CRYPTODEV_FF_CPU_AVX512;
1308 init_mb_mgr_avx512(mb_mgr);
1311 AESNI_MB_LOG(ERR, "Unsupported vector mode %u\n", vector_mode);
1315 /* Set vector instructions mode supported */
1316 internals = dev->data->dev_private;
1318 internals->vector_mode = vector_mode;
1319 internals->max_nb_queue_pairs = init_params->max_nb_queue_pairs;
1320 internals->mb_mgr = mb_mgr;
1322 AESNI_MB_LOG(INFO, "IPSec Multi-buffer library version used: %s\n",
1323 imb_get_version_str());
1329 free_mb_mgr(mb_mgr);
1331 rte_cryptodev_pmd_destroy(dev);
1337 cryptodev_aesni_mb_probe(struct rte_vdev_device *vdev)
1339 struct rte_cryptodev_pmd_init_params init_params = {
1341 sizeof(struct aesni_mb_private),
1343 RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_QUEUE_PAIRS
1345 const char *name, *args;
1348 name = rte_vdev_device_name(vdev);
1352 args = rte_vdev_device_args(vdev);
1354 retval = rte_cryptodev_pmd_parse_input_args(&init_params, args);
1356 AESNI_MB_LOG(ERR, "Failed to parse initialisation arguments[%s]",
1361 return cryptodev_aesni_mb_create(name, vdev, &init_params);
1365 cryptodev_aesni_mb_remove(struct rte_vdev_device *vdev)
1367 struct rte_cryptodev *cryptodev;
1368 struct aesni_mb_private *internals;
1371 name = rte_vdev_device_name(vdev);
1375 cryptodev = rte_cryptodev_pmd_get_named_dev(name);
1376 if (cryptodev == NULL)
1379 internals = cryptodev->data->dev_private;
1381 free_mb_mgr(internals->mb_mgr);
1383 return rte_cryptodev_pmd_destroy(cryptodev);
1386 static struct rte_vdev_driver cryptodev_aesni_mb_pmd_drv = {
1387 .probe = cryptodev_aesni_mb_probe,
1388 .remove = cryptodev_aesni_mb_remove
1391 static struct cryptodev_driver aesni_mb_crypto_drv;
1393 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_AESNI_MB_PMD, cryptodev_aesni_mb_pmd_drv);
1394 RTE_PMD_REGISTER_ALIAS(CRYPTODEV_NAME_AESNI_MB_PMD, cryptodev_aesni_mb_pmd);
1395 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_AESNI_MB_PMD,
1396 "max_nb_queue_pairs=<int> "
1398 RTE_PMD_REGISTER_CRYPTO_DRIVER(aesni_mb_crypto_drv,
1399 cryptodev_aesni_mb_pmd_drv.driver,
1400 cryptodev_driver_id);
1402 RTE_INIT(aesni_mb_init_log)
1404 aesni_mb_logtype_driver = rte_log_register("pmd.crypto.aesni_mb");