examples/l2fwd-crypto: fix length of random IV/AAD
[dpdk.git] / examples / l2fwd-crypto / main.c
index d1e05d9..c323b55 100644 (file)
 #include <rte_random.h>
 #include <rte_ring.h>
 
+enum cdev_type {
+       CDEV_TYPE_ANY,
+       CDEV_TYPE_HW,
+       CDEV_TYPE_SW
+};
+
 #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1
 
 #define NB_MBUF   8192
 
+#define MAX_STR_LEN 32
+#define MAX_KEY_SIZE 128
 #define MAX_PKT_BURST 32
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
 
@@ -114,7 +122,9 @@ struct op_buffer {
 
 enum l2fwd_crypto_xform_chain {
        L2FWD_CRYPTO_CIPHER_HASH,
-       L2FWD_CRYPTO_HASH_CIPHER
+       L2FWD_CRYPTO_HASH_CIPHER,
+       L2FWD_CRYPTO_CIPHER_ONLY,
+       L2FWD_CRYPTO_HASH_ONLY
 };
 
 struct l2fwd_key {
@@ -130,19 +140,27 @@ struct l2fwd_crypto_options {
        unsigned refresh_period;
        unsigned single_lcore:1;
 
-       enum rte_cryptodev_type cdev_type;
+       enum cdev_type type;
        unsigned sessionless:1;
 
        enum l2fwd_crypto_xform_chain xform_chain;
 
        struct rte_crypto_sym_xform cipher_xform;
-       uint8_t ckey_data[32];
+       unsigned ckey_param;
 
-       struct l2fwd_key iv_key;
-       uint8_t ivkey_data[16];
+       struct l2fwd_key iv;
+       unsigned iv_param;
 
        struct rte_crypto_sym_xform auth_xform;
-       uint8_t akey_data[128];
+       uint8_t akey_param;
+
+       struct l2fwd_key aad;
+       unsigned aad_param;
+
+       uint16_t block_size;
+       char string_auth_algo[MAX_STR_LEN];
+       char string_cipher_algo[MAX_STR_LEN];
+       char string_type[MAX_STR_LEN];
 };
 
 /** l2fwd crypto lcore params */
@@ -152,8 +170,17 @@ struct l2fwd_crypto_params {
 
        unsigned digest_length;
        unsigned block_size;
-       struct l2fwd_key iv_key;
+
+       struct l2fwd_key iv;
+       struct l2fwd_key aad;
        struct rte_cryptodev_sym_session *session;
+
+       uint8_t do_cipher;
+       uint8_t do_hash;
+       uint8_t hash_verify;
+
+       enum rte_crypto_cipher_algorithm cipher_algo;
+       enum rte_crypto_auth_algorithm auth_algo;
 };
 
 /** lcore configuration */
@@ -172,6 +199,8 @@ struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE];
 
 static const struct rte_eth_conf port_conf = {
        .rxmode = {
+               .mq_mode = ETH_MQ_RX_NONE,
+               .max_rx_pkt_len = ETHER_MAX_LEN,
                .split_hdr_size = 0,
                .header_split   = 0, /**< Header Split disabled */
                .hw_ip_checksum = 0, /**< IP checksum offload disabled */
@@ -386,23 +415,61 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
        /* Set crypto operation data parameters */
        rte_crypto_op_attach_sym_session(op, cparams->session);
 
-       /* Append space for digest to end of packet */
-       op->sym->auth.digest.data = (uint8_t *)rte_pktmbuf_append(m,
-                       cparams->digest_length);
-       op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
-                       rte_pktmbuf_pkt_len(m) - cparams->digest_length);
-       op->sym->auth.digest.length = cparams->digest_length;
+       if (cparams->do_hash) {
+               if (!cparams->hash_verify) {
+                       /* Append space for digest to end of packet */
+                       op->sym->auth.digest.data = (uint8_t *)rte_pktmbuf_append(m,
+                               cparams->digest_length);
+               } else {
+                       op->sym->auth.digest.data = (uint8_t *)rte_pktmbuf_append(m,
+                               cparams->digest_length);
+               }
 
-       op->sym->auth.data.offset = ipdata_offset;
-       op->sym->auth.data.length = data_len;
+               op->sym->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
+                               rte_pktmbuf_pkt_len(m) - cparams->digest_length);
+               op->sym->auth.digest.length = cparams->digest_length;
 
+               /* For SNOW3G algorithms, offset/length must be in bits */
+               if (cparams->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2) {
+                       op->sym->auth.data.offset = ipdata_offset << 3;
+                       op->sym->auth.data.length = data_len << 3;
+               } else {
+                       op->sym->auth.data.offset = ipdata_offset;
+                       op->sym->auth.data.length = data_len;
+               }
 
-       op->sym->cipher.iv.data = cparams->iv_key.data;
-       op->sym->cipher.iv.phys_addr = cparams->iv_key.phys_addr;
-       op->sym->cipher.iv.length = cparams->iv_key.length;
+               if (cparams->aad.length) {
+                       op->sym->auth.aad.data = cparams->aad.data;
+                       op->sym->auth.aad.phys_addr = cparams->aad.phys_addr;
+                       op->sym->auth.aad.length = cparams->aad.length;
+               }
+       }
 
-       op->sym->cipher.data.offset = ipdata_offset;
-       op->sym->cipher.data.length = data_len;
+       if (cparams->do_cipher) {
+               op->sym->cipher.iv.data = cparams->iv.data;
+               op->sym->cipher.iv.phys_addr = cparams->iv.phys_addr;
+               op->sym->cipher.iv.length = cparams->iv.length;
+
+               /* For SNOW3G algorithms, offset/length must be in bits */
+               if (cparams->cipher_algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2) {
+                       op->sym->cipher.data.offset = ipdata_offset << 3;
+                       if (cparams->do_hash && cparams->hash_verify)
+                               /* Do not cipher the hash tag */
+                               op->sym->cipher.data.length = (data_len -
+                                       cparams->digest_length) << 3;
+                       else
+                               op->sym->cipher.data.length = data_len << 3;
+
+               } else {
+                       op->sym->cipher.data.offset = ipdata_offset;
+                       if (cparams->do_hash && cparams->hash_verify)
+                               /* Do not cipher the hash tag */
+                               op->sym->cipher.data.length = data_len -
+                                       cparams->digest_length;
+                       else
+                               op->sym->cipher.data.length = data_len;
+               }
+       }
 
        op->sym->m_src = m;
 
@@ -495,9 +562,13 @@ initialize_crypto_session(struct l2fwd_crypto_options *options,
        if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH) {
                first_xform = &options->cipher_xform;
                first_xform->next = &options->auth_xform;
-       } else {
+       } else if (options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER) {
                first_xform = &options->auth_xform;
                first_xform->next = &options->cipher_xform;
+       } else if (options->xform_chain == L2FWD_CRYPTO_CIPHER_ONLY) {
+               first_xform = &options->cipher_xform;
+       } else {
+               first_xform = &options->auth_xform;
        }
 
        /* Setup Cipher Parameters */
@@ -540,19 +611,60 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
        }
 
        for (i = 0; i < qconf->nb_crypto_devs; i++) {
+               port_cparams[i].do_cipher = 0;
+               port_cparams[i].do_hash = 0;
+
+               switch (options->xform_chain) {
+               case L2FWD_CRYPTO_CIPHER_HASH:
+               case L2FWD_CRYPTO_HASH_CIPHER:
+                       port_cparams[i].do_cipher = 1;
+                       port_cparams[i].do_hash = 1;
+                       break;
+               case L2FWD_CRYPTO_HASH_ONLY:
+                       port_cparams[i].do_hash = 1;
+                       break;
+               case L2FWD_CRYPTO_CIPHER_ONLY:
+                       port_cparams[i].do_cipher = 1;
+                       break;
+               }
+
                port_cparams[i].dev_id = qconf->cryptodev_list[i];
                port_cparams[i].qp_id = 0;
 
-               port_cparams[i].block_size = 64;
-               port_cparams[i].digest_length = 20;
+               port_cparams[i].block_size = options->block_size;
 
-               port_cparams[i].iv_key.data =
-                               (uint8_t *)rte_malloc(NULL, 16, 8);
-               port_cparams[i].iv_key.length = 16;
-               port_cparams[i].iv_key.phys_addr = rte_malloc_virt2phy(
-                               (void *)port_cparams[i].iv_key.data);
-               generate_random_key(port_cparams[i].iv_key.data,
-                               sizeof(cparams[i].iv_key.length));
+               if (port_cparams[i].do_hash) {
+                       port_cparams[i].digest_length =
+                                       options->auth_xform.auth.digest_length;
+                       if (options->auth_xform.auth.add_auth_data_length) {
+                               port_cparams[i].aad.data = options->aad.data;
+                               port_cparams[i].aad.length =
+                                       options->auth_xform.auth.add_auth_data_length;
+                               port_cparams[i].aad.phys_addr = options->aad.phys_addr;
+                               if (!options->aad_param)
+                                       generate_random_key(port_cparams[i].aad.data,
+                                               port_cparams[i].aad.length);
+
+                       }
+
+                       if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_VERIFY)
+                               port_cparams[i].hash_verify = 1;
+                       else
+                               port_cparams[i].hash_verify = 0;
+
+                       port_cparams[i].auth_algo = options->auth_xform.auth.algo;
+               }
+
+               if (port_cparams[i].do_cipher) {
+                       port_cparams[i].iv.data = options->iv.data;
+                       port_cparams[i].iv.length = options->iv.length;
+                       port_cparams[i].iv.phys_addr = options->iv.phys_addr;
+                       if (!options->iv_param)
+                               generate_random_key(port_cparams[i].iv.data,
+                                               port_cparams[i].iv.length);
+
+                       port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
+               }
 
                port_cparams[i].session = initialize_crypto_session(options,
                                port_cparams[i].dev_id);
@@ -572,7 +684,6 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                 */
                diff_tsc = cur_tsc - prev_tsc;
                if (unlikely(diff_tsc > drain_tsc)) {
-
                        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
                                if (qconf->pkt_buf[portid].len == 0)
                                        continue;
@@ -675,14 +786,14 @@ l2fwd_launch_one_lcore(void *arg)
 static void
 l2fwd_crypto_usage(const char *prgname)
 {
-       printf("%s [EAL options] -- --cdev TYPE [optional parameters]\n"
+       printf("%s [EAL options] --\n"
                "  -p PORTMASK: hexadecimal bitmask of ports to configure\n"
                "  -q NQ: number of queue (=ports) per lcore (default is 1)\n"
-               "  -s manage all ports from single lcore"
-               "  -t PERIOD: statistics will be refreshed each PERIOD seconds"
+               "  -s manage all ports from single lcore\n"
+               "  -T PERIOD: statistics will be refreshed each PERIOD seconds"
                " (0 to disable, 10 default, 86400 maximum)\n"
 
-               "  --cdev AESNI_MB / QAT\n"
+               "  --cdev_type HW / SW / ANY\n"
                "  --chain HASH_CIPHER / CIPHER_HASH\n"
 
                "  --cipher_algo ALGO\n"
@@ -693,6 +804,7 @@ l2fwd_crypto_usage(const char *prgname)
                "  --auth_algo ALGO\n"
                "  --auth_op GENERATE / VERIFY\n"
                "  --auth_key KEY\n"
+               "  --aad AAD\n"
 
                "  --sessionless\n",
               prgname);
@@ -700,13 +812,16 @@ l2fwd_crypto_usage(const char *prgname)
 
 /** Parse crypto device type command line argument */
 static int
-parse_cryptodev_type(enum rte_cryptodev_type *type, char *optarg)
+parse_cryptodev_type(enum cdev_type *type, char *optarg)
 {
-       if (strcmp("AESNI_MB", optarg) == 0) {
-               *type = RTE_CRYPTODEV_AESNI_MB_PMD;
+       if (strcmp("HW", optarg) == 0) {
+               *type = CDEV_TYPE_HW;
                return 0;
-       } else if (strcmp("QAT", optarg) == 0) {
-               *type = RTE_CRYPTODEV_QAT_SYM_PMD;
+       } else if (strcmp("SW", optarg) == 0) {
+               *type = CDEV_TYPE_SW;
+               return 0;
+       } else if (strcmp("ANY", optarg) == 0) {
+               *type = CDEV_TYPE_ANY;
                return 0;
        }
 
@@ -723,6 +838,12 @@ parse_crypto_opt_chain(struct l2fwd_crypto_options *options, char *optarg)
        } else if (strcmp("HASH_CIPHER", optarg) == 0) {
                options->xform_chain = L2FWD_CRYPTO_HASH_CIPHER;
                return 0;
+       } else if (strcmp("CIPHER_ONLY", optarg) == 0) {
+               options->xform_chain = L2FWD_CRYPTO_CIPHER_ONLY;
+               return 0;
+       } else if (strcmp("HASH_ONLY", optarg) == 0) {
+               options->xform_chain = L2FWD_CRYPTO_HASH_ONLY;
+               return 0;
        }
 
        return -1;
@@ -738,6 +859,12 @@ parse_cipher_algo(enum rte_crypto_cipher_algorithm *algo, char *optarg)
        } else if (strcmp("AES_GCM", optarg) == 0) {
                *algo = RTE_CRYPTO_CIPHER_AES_GCM;
                return 0;
+       } else if (strcmp("NULL", optarg) == 0) {
+               *algo = RTE_CRYPTO_CIPHER_NULL;
+               return 0;
+       } else if (strcmp("SNOW3G_UEA2", optarg) == 0) {
+               *algo = RTE_CRYPTO_CIPHER_SNOW3G_UEA2;
+               return 0;
        }
 
        printf("Cipher algorithm  not supported!\n");
@@ -762,20 +889,39 @@ parse_cipher_op(enum rte_crypto_cipher_operation *op, char *optarg)
 
 /** Parse crypto key command line argument */
 static int
-parse_key(struct l2fwd_key *key __rte_unused,
-               unsigned length __rte_unused, char *arg __rte_unused)
+parse_key(uint8_t *data, char *input_arg)
 {
-       printf("Currently an unsupported argument!\n");
-       return -1;
+       unsigned byte_count;
+       char *token;
+
+       for (byte_count = 0, token = strtok(input_arg, ":");
+                       (byte_count < MAX_KEY_SIZE) && (token != NULL);
+                       token = strtok(NULL, ":")) {
+
+               int number = (int)strtol(token, NULL, 16);
+
+               if (errno == EINVAL || errno == ERANGE || number > 0xFF)
+                       return -1;
+
+               data[byte_count++] = (uint8_t)number;
+       }
+
+       return 0;
 }
 
 /** Parse crypto cipher operation command line argument */
 static int
 parse_auth_algo(enum rte_crypto_auth_algorithm *algo, char *optarg)
 {
-       if (strcmp("MD5_HMAC", optarg) == 0) {
+       if (strcmp("AES_GCM", optarg) == 0) {
+               *algo = RTE_CRYPTO_AUTH_AES_GCM;
+               return 0;
+       } else if (strcmp("MD5_HMAC", optarg) == 0) {
                *algo = RTE_CRYPTO_AUTH_MD5_HMAC;
                return 0;
+       } else if (strcmp("NULL", optarg) == 0) {
+               *algo = RTE_CRYPTO_AUTH_NULL;
+               return 0;
        } else if (strcmp("SHA1_HMAC", optarg) == 0) {
                *algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
                return 0;
@@ -791,6 +937,9 @@ parse_auth_algo(enum rte_crypto_auth_algorithm *algo, char *optarg)
        } else if (strcmp("SHA512_HMAC", optarg) == 0) {
                *algo = RTE_CRYPTO_AUTH_SHA512_HMAC;
                return 0;
+       } else if (strcmp("SNOW3G_UIA2", optarg) == 0) {
+               *algo = RTE_CRYPTO_AUTH_SNOW3G_UIA2;
+               return 0;
        }
 
        printf("Authentication algorithm specified not supported!\n");
@@ -817,55 +966,65 @@ static int
 l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
                struct option *lgopts, int option_index)
 {
-       if (strcmp(lgopts[option_index].name, "cdev_type") == 0)
-               return parse_cryptodev_type(&options->cdev_type, optarg);
+       int retval;
+
+       if (strcmp(lgopts[option_index].name, "cdev_type") == 0) {
+               retval = parse_cryptodev_type(&options->type, optarg);
+               if (retval == 0)
+                       strcpy(options->string_type, optarg);
+               return retval;
+       }
 
        else if (strcmp(lgopts[option_index].name, "chain") == 0)
                return parse_crypto_opt_chain(options, optarg);
 
        /* Cipher options */
-       else if (strcmp(lgopts[option_index].name, "cipher_algo") == 0)
-               return parse_cipher_algo(&options->cipher_xform.cipher.algo,
+       else if (strcmp(lgopts[option_index].name, "cipher_algo") == 0) {
+               retval = parse_cipher_algo(&options->cipher_xform.cipher.algo,
                                optarg);
+               if (retval == 0)
+                       strcpy(options->string_cipher_algo, optarg);
+               return retval;
+       }
 
        else if (strcmp(lgopts[option_index].name, "cipher_op") == 0)
                return parse_cipher_op(&options->cipher_xform.cipher.op,
                                optarg);
 
        else if (strcmp(lgopts[option_index].name, "cipher_key") == 0) {
-               struct l2fwd_key key = { 0 };
-               int retval = 0;
-
-               retval = parse_key(&key, sizeof(options->ckey_data), optarg);
-
-               options->cipher_xform.cipher.key.data = key.data;
-               options->cipher_xform.cipher.key.length = key.length;
+               options->ckey_param = 1;
+               return parse_key(options->cipher_xform.cipher.key.data, optarg);
+       }
 
-               return retval;
-       } else if (strcmp(lgopts[option_index].name, "iv") == 0)
-               return parse_key(&options->iv_key, sizeof(options->ivkey_data),
-                               optarg);
+       else if (strcmp(lgopts[option_index].name, "iv") == 0) {
+               options->iv_param = 1;
+               return parse_key(options->iv.data, optarg);
+       }
 
        /* Authentication options */
-       else if (strcmp(lgopts[option_index].name, "auth_algo") == 0)
-               return parse_auth_algo(&options->auth_xform.auth.algo,
+       else if (strcmp(lgopts[option_index].name, "auth_algo") == 0) {
+               retval = parse_auth_algo(&options->auth_xform.auth.algo,
                                optarg);
+               if (retval == 0)
+                       strcpy(options->string_auth_algo, optarg);
+               return retval;
+       }
 
        else if (strcmp(lgopts[option_index].name, "auth_op") == 0)
                return parse_auth_op(&options->auth_xform.auth.op,
                                optarg);
 
        else if (strcmp(lgopts[option_index].name, "auth_key") == 0) {
-               struct l2fwd_key key = { 0 };
-               int retval = 0;
-
-               retval = parse_key(&key, sizeof(options->akey_data), optarg);
+               options->akey_param = 1;
+               return parse_key(options->auth_xform.auth.key.data, optarg);
+       }
 
-               options->auth_xform.auth.key.data = key.data;
-               options->auth_xform.auth.key.length = key.length;
+       else if (strcmp(lgopts[option_index].name, "aad") == 0) {
+               options->aad_param = 1;
+               return parse_key(options->aad.data, optarg);
+       }
 
-               return retval;
-       } else if (strcmp(lgopts[option_index].name, "sessionless") == 0) {
+       else if (strcmp(lgopts[option_index].name, "sessionless") == 0) {
                options->sessionless = 1;
                return 0;
        }
@@ -956,36 +1115,27 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->single_lcore = 0;
        options->sessionless = 0;
 
-       options->cdev_type = RTE_CRYPTODEV_AESNI_MB_PMD;
        options->xform_chain = L2FWD_CRYPTO_CIPHER_HASH;
 
        /* Cipher Data */
        options->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
        options->cipher_xform.next = NULL;
+       options->ckey_param = 0;
+       options->iv_param = 0;
 
        options->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
        options->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
 
-       generate_random_key(options->ckey_data, sizeof(options->ckey_data));
-
-       options->cipher_xform.cipher.key.data = options->ckey_data;
-       options->cipher_xform.cipher.key.length = 16;
-
-
        /* Authentication Data */
        options->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
        options->auth_xform.next = NULL;
+       options->akey_param = 0;
+       options->aad_param = 0;
 
        options->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
-       options->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+       options->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
-       options->auth_xform.auth.add_auth_data_length = 0;
-       options->auth_xform.auth.digest_length = 20;
-
-       generate_random_key(options->akey_data, sizeof(options->akey_data));
-
-       options->auth_xform.auth.key.data = options->akey_data;
-       options->auth_xform.auth.key.length = 20;
+       options->type = CDEV_TYPE_ANY;
 }
 
 static void
@@ -1000,15 +1150,6 @@ l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
        printf("stats_printing: %s\n",
                        options->refresh_period == 0 ? "disabled" : "enabled");
 
-       switch (options->cdev_type) {
-       case RTE_CRYPTODEV_AESNI_MB_PMD:
-               printf("cryptodev type: AES-NI MB PMD\n"); break;
-       case RTE_CRYPTODEV_QAT_SYM_PMD:
-               printf("cryptodev type: QAT PMD\n"); break;
-       default:
-               break;
-       }
-
        printf("sessionless crypto: %s\n",
                        options->sessionless ? "enabled" : "disabled");
 }
@@ -1036,6 +1177,7 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                        { "auth_key", required_argument, 0, 0 },
 
                        { "iv", required_argument, 0, 0 },
+                       { "aad", required_argument, 0, 0 },
 
                        { "sessionless", no_argument, 0, 0 },
 
@@ -1082,7 +1224,7 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                        break;
 
                /* timer period */
-               case 't':
+               case 'T':
                        retval = l2fwd_crypto_parse_timer_period(options,
                                        optarg);
                        if (retval < 0) {
@@ -1162,27 +1304,41 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
        }
 }
 
+/* Check if device has to be HW/SW or any */
 static int
-initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports)
+check_type(struct l2fwd_crypto_options *options, struct rte_cryptodev_info *dev_info)
+{
+       if (options->type == CDEV_TYPE_HW &&
+                       (dev_info->feature_flags & RTE_CRYPTODEV_FF_HW_ACCELERATED))
+               return 0;
+       if (options->type == CDEV_TYPE_SW &&
+                       !(dev_info->feature_flags & RTE_CRYPTODEV_FF_HW_ACCELERATED))
+               return 0;
+       if (options->type == CDEV_TYPE_ANY)
+               return 0;
+
+       return -1;
+}
+
+static int
+initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
+               uint8_t *enabled_cdevs)
 {
        unsigned i, cdev_id, cdev_count, enabled_cdev_count = 0;
+       const struct rte_cryptodev_capabilities *cap;
+       enum rte_crypto_auth_algorithm cap_auth_algo;
+       enum rte_crypto_auth_algorithm opt_auth_algo;
+       enum rte_crypto_cipher_algorithm cap_cipher_algo;
+       enum rte_crypto_cipher_algorithm opt_cipher_algo;
        int retval;
 
-       if (options->cdev_type == RTE_CRYPTODEV_QAT_SYM_PMD) {
-               if (rte_cryptodev_count() < nb_ports)
-                       return -1;
-       } else if (options->cdev_type == RTE_CRYPTODEV_AESNI_MB_PMD) {
-               for (i = 0; i < nb_ports; i++) {
-                       int retval = rte_eal_vdev_init(CRYPTODEV_NAME_AESNI_MB_PMD,
-                                       NULL);
-                       if (retval < 0)
-                               return -1;
-               }
+       cdev_count = rte_cryptodev_count();
+       if (cdev_count == 0) {
+               printf("No crypto devices available\n");
+               return -1;
        }
 
-       cdev_count = rte_cryptodev_count();
-       for (cdev_id = 0;
-                       cdev_id < cdev_count && enabled_cdev_count < nb_ports;
+       for (cdev_id = 0; cdev_id < cdev_count && enabled_cdev_count < nb_ports;
                        cdev_id++) {
                struct rte_cryptodev_qp_conf qp_conf;
                struct rte_cryptodev_info dev_info;
@@ -1198,9 +1354,84 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports)
 
                rte_cryptodev_info_get(cdev_id, &dev_info);
 
-               if (dev_info.dev_type != options->cdev_type)
-                       continue;
+               /* Set cipher parameters */
+               if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH ||
+                               options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER ||
+                               options->xform_chain == L2FWD_CRYPTO_CIPHER_ONLY) {
+                       /* Check if device supports cipher algo */
+                       i = 0;
+                       opt_cipher_algo = options->cipher_xform.cipher.algo;
+                       cap = &dev_info.capabilities[i];
+                       while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
+                               cap_cipher_algo = cap->sym.cipher.algo;
+                               if (cap->sym.xform_type ==
+                                               RTE_CRYPTO_SYM_XFORM_CIPHER) {
+                                       if (cap_cipher_algo == opt_cipher_algo) {
+                                               if (check_type(options, &dev_info) == 0)
+                                                       break;
+                                       }
+                               }
+                               cap = &dev_info.capabilities[++i];
+                       }
+
+                       if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
+                               printf("Algorithm %s not supported by cryptodev %u"
+                                       " or device not of preferred type (%s)\n",
+                                       options->string_cipher_algo, cdev_id,
+                                       options->string_type);
+                               continue;
+                       }
+
+                       options->block_size = cap->sym.cipher.block_size;
+                       options->iv.length = cap->sym.cipher.iv_size.min;
+                       options->cipher_xform.cipher.key.length =
+                                               cap->sym.cipher.key_size.min;
+                       if (!options->ckey_param)
+                               generate_random_key(
+                                       options->cipher_xform.cipher.key.data,
+                                       options->cipher_xform.cipher.key.length);
+
+               }
+
+               /* Set auth parameters */
+               if (options->xform_chain == L2FWD_CRYPTO_CIPHER_HASH ||
+                               options->xform_chain == L2FWD_CRYPTO_HASH_CIPHER ||
+                               options->xform_chain == L2FWD_CRYPTO_HASH_ONLY) {
+                       /* Check if device supports auth algo */
+                       i = 0;
+                       opt_auth_algo = options->auth_xform.auth.algo;
+                       cap = &dev_info.capabilities[i];
+                       while (cap->op != RTE_CRYPTO_OP_TYPE_UNDEFINED) {
+                               cap_auth_algo = cap->sym.auth.algo;
+                               if ((cap->sym.xform_type == RTE_CRYPTO_SYM_XFORM_AUTH) &&
+                                               (cap_auth_algo == opt_auth_algo) &&
+                                               (check_type(options, &dev_info) == 0)) {
+                                       break;
+                               }
+                               cap = &dev_info.capabilities[++i];
+                       }
+
+                       if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
+                               printf("Algorithm %s not supported by cryptodev %u"
+                                       " or device not of preferred type (%s)\n",
+                                       options->string_auth_algo, cdev_id,
+                                       options->string_type);
+                               continue;
+                       }
 
+                       options->block_size = cap->sym.auth.block_size;
+                       options->auth_xform.auth.add_auth_data_length =
+                                               cap->sym.auth.aad_size.min;
+                       options->auth_xform.auth.digest_length =
+                                               cap->sym.auth.digest_size.min;
+                       options->auth_xform.auth.key.length =
+                                               cap->sym.auth.key_size.min;
+
+                       if (!options->akey_param)
+                               generate_random_key(
+                                       options->auth_xform.auth.key.data,
+                                       options->auth_xform.auth.key.length);
+               }
 
                retval = rte_cryptodev_configure(cdev_id, &conf);
                if (retval < 0) {
@@ -1220,6 +1451,7 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports)
 
                l2fwd_enabled_crypto_mask |= (1 << cdev_id);
 
+               enabled_cdevs[cdev_id] = 1;
                enabled_cdev_count++;
        }
 
@@ -1333,6 +1565,31 @@ initialize_ports(struct l2fwd_crypto_options *options)
        return enabled_portcount;
 }
 
+static void
+reserve_key_memory(struct l2fwd_crypto_options *options)
+{
+       options->cipher_xform.cipher.key.data = rte_malloc("crypto key",
+                                               MAX_KEY_SIZE, 0);
+       if (options->cipher_xform.cipher.key.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for cipher key");
+
+
+       options->auth_xform.auth.key.data = rte_malloc("auth key",
+                                               MAX_KEY_SIZE, 0);
+       if (options->auth_xform.auth.key.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth key");
+
+       options->iv.data = rte_malloc("iv", MAX_KEY_SIZE, 0);
+       if (options->iv.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for IV");
+       options->iv.phys_addr = rte_malloc_virt2phy(options->iv.data);
+
+       options->aad.data = rte_malloc("aad", MAX_KEY_SIZE, 0);
+       if (options->aad.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for AAD");
+       options->aad.phys_addr = rte_malloc_virt2phy(options->aad.data);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1342,6 +1599,7 @@ main(int argc, char **argv)
        uint8_t nb_ports, nb_cryptodevs, portid, cdev_id;
        unsigned lcore_id, rx_lcore_id;
        int ret, enabled_cdevcount, enabled_portcount;
+       uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = {0};
 
        /* init EAL */
        ret = rte_eal_init(argc, argv);
@@ -1350,6 +1608,9 @@ main(int argc, char **argv)
        argc -= ret;
        argv += ret;
 
+       /* reserve memory for Cipher/Auth key and IV */
+       reserve_key_memory(&options);
+
        /* parse application arguments (after the EAL ones) */
        ret = l2fwd_crypto_parse_args(&options, argc, argv);
        if (ret < 0)
@@ -1412,23 +1673,25 @@ main(int argc, char **argv)
                printf("Lcore %u: RX port %u\n", rx_lcore_id, (unsigned)portid);
        }
 
-
        /* Enable Crypto devices */
-       enabled_cdevcount = initialize_cryptodevs(&options, enabled_portcount);
-       if (enabled_cdevcount < 1)
-               rte_exit(EXIT_FAILURE, "Failed to initial crypto devices\n");
+       enabled_cdevcount = initialize_cryptodevs(&options, enabled_portcount,
+                       enabled_cdevs);
+       if (enabled_cdevcount < 0)
+               rte_exit(EXIT_FAILURE, "Failed to initialize crypto devices\n");
+
+       if (enabled_cdevcount < enabled_portcount)
+               rte_exit(EXIT_FAILURE, "Number of capable crypto devices (%d) "
+                               "has to be more or equal to number of ports (%d)\n",
+                               enabled_cdevcount, enabled_portcount);
 
        nb_cryptodevs = rte_cryptodev_count();
-       /* Initialize the port/queue configuration of each logical core */
+
+       /* Initialize the port/cryptodev configuration of each logical core */
        for (rx_lcore_id = 0, qconf = NULL, cdev_id = 0;
                        cdev_id < nb_cryptodevs && enabled_cdevcount;
                        cdev_id++) {
-               struct rte_cryptodev_info info;
-
-               rte_cryptodev_info_get(cdev_id, &info);
-
-               /* skip devices of the wrong type */
-               if (options.cdev_type != info.dev_type)
+               /* Crypto op not supported by crypto device */
+               if (!enabled_cdevs[cdev_id])
                        continue;
 
                if (options.single_lcore && qconf == NULL) {
@@ -1463,8 +1726,6 @@ main(int argc, char **argv)
                                (unsigned)cdev_id);
        }
 
-
-
        /* launch per-lcore init on every lcore */
        rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, (void *)&options,
                        CALL_MASTER);