cryptodev: add auth IV
[dpdk.git] / examples / l2fwd-crypto / main.c
index 35171d1..8da8dbd 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,8 @@
 #include <ctype.h>
 #include <errno.h>
 #include <getopt.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include <rte_atomic.h>
 #include <rte_branch_prediction.h>
@@ -70,7 +72,6 @@
 #include <rte_per_lcore.h>
 #include <rte_prefetch.h>
 #include <rte_random.h>
-#include <rte_ring.h>
 #include <rte_hexdump.h>
 
 enum cdev_type {
@@ -88,6 +89,10 @@ enum cdev_type {
 #define MAX_PKT_BURST 32
 #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
 
+#define MAXIMUM_IV_LENGTH      16
+#define IV_OFFSET              (sizeof(struct rte_crypto_op) + \
+                               sizeof(struct rte_crypto_sym_op))
+
 /*
  * Configurable number of RX/TX ring descriptors
  */
@@ -134,8 +139,10 @@ struct l2fwd_key {
        phys_addr_t phys_addr;
 };
 
-char supported_auth_algo[RTE_CRYPTO_AUTH_LIST_END][MAX_STR_LEN];
-char supported_cipher_algo[RTE_CRYPTO_CIPHER_LIST_END][MAX_STR_LEN];
+struct l2fwd_iv {
+       uint8_t *data;
+       uint16_t length;
+};
 
 /** l2fwd crypto application command line options */
 struct l2fwd_crypto_options {
@@ -153,14 +160,18 @@ struct l2fwd_crypto_options {
        unsigned ckey_param;
        int ckey_random_size;
 
-       struct l2fwd_key iv;
-       unsigned iv_param;
-       int iv_random_size;
+       struct l2fwd_iv cipher_iv;
+       unsigned int cipher_iv_param;
+       int cipher_iv_random_size;
 
        struct rte_crypto_sym_xform auth_xform;
        uint8_t akey_param;
        int akey_random_size;
 
+       struct l2fwd_iv auth_iv;
+       unsigned int auth_iv_param;
+       int auth_iv_random_size;
+
        struct l2fwd_key aad;
        unsigned aad_param;
        int aad_random_size;
@@ -169,6 +180,8 @@ struct l2fwd_crypto_options {
 
        uint16_t block_size;
        char string_type[MAX_STR_LEN];
+
+       uint64_t cryptodev_mask;
 };
 
 /** l2fwd crypto lcore params */
@@ -179,7 +192,8 @@ struct l2fwd_crypto_params {
        unsigned digest_length;
        unsigned block_size;
 
-       struct l2fwd_key iv;
+       struct l2fwd_iv cipher_iv;
+       struct l2fwd_iv auth_iv;
        struct l2fwd_key aad;
        struct rte_cryptodev_sym_session *session;
 
@@ -199,7 +213,7 @@ struct lcore_queue_conf {
        unsigned nb_crypto_devs;
        unsigned cryptodev_list[MAX_RX_QUEUE_PER_LCORE];
 
-       struct op_buffer op_buf[RTE_MAX_ETHPORTS];
+       struct op_buffer op_buf[RTE_CRYPTO_MAX_DEVS];
        struct pkt_buffer pkt_buf[RTE_MAX_ETHPORTS];
 } __rte_cache_aligned;
 
@@ -214,7 +228,7 @@ static const struct rte_eth_conf port_conf = {
                .hw_ip_checksum = 0, /**< IP checksum offload disabled */
                .hw_vlan_filter = 0, /**< VLAN filtering disabled */
                .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
-               .hw_strip_crc   = 0, /**< CRC stripped by hardware */
+               .hw_strip_crc   = 1, /**< CRC stripped by hardware */
        },
        .txmode = {
                .mq_mode = ETH_MQ_TX_NONE,
@@ -243,7 +257,7 @@ struct l2fwd_crypto_statistics {
 } __rte_cache_aligned;
 
 struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS];
-struct l2fwd_crypto_statistics crypto_statistics[RTE_MAX_ETHPORTS];
+struct l2fwd_crypto_statistics crypto_statistics[RTE_CRYPTO_MAX_DEVS];
 
 /* A tsc-based timer responsible for triggering statistics printout */
 #define TIMER_MILLISECOND 2000000ULL /* around 1ms at 2 Ghz */
@@ -298,7 +312,7 @@ print_stats(void)
 
        for (cdevid = 0; cdevid < RTE_CRYPTO_MAX_DEVS; cdevid++) {
                /* skip disabled ports */
-               if ((l2fwd_enabled_crypto_mask & (1lu << cdevid)) == 0)
+               if ((l2fwd_enabled_crypto_mask & (((uint64_t)1) << cdevid)) == 0)
                        continue;
                printf("\nStatistics for cryptodev %"PRIu64
                                " -------------------------"
@@ -330,34 +344,6 @@ print_stats(void)
        printf("\n====================================================\n");
 }
 
-static void
-fill_supported_algorithm_tables(void)
-{
-       unsigned i;
-
-       for (i = 0; i < RTE_CRYPTO_AUTH_LIST_END; i++)
-               strcpy(supported_auth_algo[i], "NOT_SUPPORTED");
-
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_AES_GCM], "AES_GCM");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_MD5_HMAC], "MD5_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_NULL], "NULL");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SHA1_HMAC], "SHA1_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SHA224_HMAC], "SHA224_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SHA256_HMAC], "SHA256_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SHA384_HMAC], "SHA384_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SHA512_HMAC], "SHA512_HMAC");
-       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_SNOW3G_UIA2], "SNOW3G_UIA2");
-
-       for (i = 0; i < RTE_CRYPTO_CIPHER_LIST_END; i++)
-               strcpy(supported_cipher_algo[i], "NOT_SUPPORTED");
-
-       strcpy(supported_cipher_algo[RTE_CRYPTO_CIPHER_AES_CBC], "AES_CBC");
-       strcpy(supported_cipher_algo[RTE_CRYPTO_CIPHER_AES_GCM], "AES_GCM");
-       strcpy(supported_cipher_algo[RTE_CRYPTO_CIPHER_NULL], "NULL");
-       strcpy(supported_cipher_algo[RTE_CRYPTO_CIPHER_SNOW3G_UEA2], "SNOW3G_UEA2");
-}
-
-
 static int
 l2fwd_crypto_send_burst(struct lcore_queue_conf *qconf, unsigned n,
                struct l2fwd_crypto_params *cparams)
@@ -415,7 +401,8 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
        struct ether_hdr *eth_hdr;
        struct ipv4_hdr *ip_hdr;
 
-       unsigned ipdata_offset, pad_len, data_len;
+       uint32_t ipdata_offset, data_len;
+       uint32_t pad_len = 0;
        char *padding;
 
        eth_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
@@ -434,37 +421,72 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
 
        /* Zero pad data to be crypto'd so it is block aligned */
        data_len  = rte_pktmbuf_data_len(m) - ipdata_offset;
-       pad_len = data_len % cparams->block_size ? cparams->block_size -
-                       (data_len % cparams->block_size) : 0;
 
-       if (pad_len) {
-               padding = rte_pktmbuf_append(m, pad_len);
-               if (unlikely(!padding))
-                       return -1;
+       if (cparams->do_hash && cparams->hash_verify)
+               data_len -= cparams->digest_length;
+
+       if (cparams->do_cipher) {
+               /*
+                * Following algorithms are block cipher algorithms,
+                * and might need padding
+                */
+               switch (cparams->cipher_algo) {
+               case RTE_CRYPTO_CIPHER_AES_CBC:
+               case RTE_CRYPTO_CIPHER_AES_ECB:
+               case RTE_CRYPTO_CIPHER_DES_CBC:
+               case RTE_CRYPTO_CIPHER_3DES_CBC:
+               case RTE_CRYPTO_CIPHER_3DES_ECB:
+                       if (data_len % cparams->block_size)
+                               pad_len = cparams->block_size -
+                                       (data_len % cparams->block_size);
+                       break;
+               default:
+                       pad_len = 0;
+               }
+
+               if (pad_len) {
+                       padding = rte_pktmbuf_append(m, pad_len);
+                       if (unlikely(!padding))
+                               return -1;
 
-               data_len += pad_len;
-               memset(padding, 0, pad_len);
+                       data_len += pad_len;
+                       memset(padding, 0, pad_len);
+               }
        }
 
        /* Set crypto operation data parameters */
        rte_crypto_op_attach_sym_session(op, cparams->session);
 
        if (cparams->do_hash) {
+               if (cparams->auth_iv.length) {
+                       uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op,
+                                               uint8_t *,
+                                               IV_OFFSET +
+                                               cparams->cipher_iv.length);
+                       /*
+                        * Copy IV at the end of the crypto operation,
+                        * after the cipher IV, if added
+                        */
+                       rte_memcpy(iv_ptr, cparams->auth_iv.data,
+                                       cparams->auth_iv.length);
+               }
                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.digest.data = rte_pktmbuf_mtod(m,
+                               uint8_t *) + ipdata_offset + 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) {
+               /* For wireless algorithms, offset/length must be in bits */
+               if (cparams->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2 ||
+                               cparams->auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9 ||
+                               cparams->auth_algo == RTE_CRYPTO_AUTH_ZUC_EIA3) {
                        op->sym->auth.data.offset = ipdata_offset << 3;
                        op->sym->auth.data.length = data_len << 3;
                } else {
@@ -476,32 +498,29 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
                        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;
+               } else {
+                       op->sym->auth.aad.data = NULL;
+                       op->sym->auth.aad.phys_addr = 0;
+                       op->sym->auth.aad.length = 0;
                }
        }
 
        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) {
+               uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
+                                                       IV_OFFSET);
+               /* Copy IV at the end of the crypto operation */
+               rte_memcpy(iv_ptr, cparams->cipher_iv.data,
+                               cparams->cipher_iv.length);
+
+               /* For wireless algorithms, offset/length must be in bits */
+               if (cparams->cipher_algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2 ||
+                               cparams->cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8 ||
+                               cparams->cipher_algo == RTE_CRYPTO_CIPHER_ZUC_EEA3) {
                        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;
-
+                       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->cipher.data.length = data_len;
                }
        }
 
@@ -581,10 +600,18 @@ l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid)
 static void
 generate_random_key(uint8_t *key, unsigned length)
 {
-       unsigned i;
+       int fd;
+       int ret;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd < 0)
+               rte_exit(EXIT_FAILURE, "Failed to generate random key\n");
 
-       for (i = 0; i < length; i++)
-               key[i] = rand() % 0xff;
+       ret = read(fd, key, length);
+       close(fd);
+
+       if (ret != (signed)length)
+               rte_exit(EXIT_FAILURE, "Failed to generate random key\n");
 }
 
 static struct rte_cryptodev_sym_session *
@@ -621,7 +648,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 
        unsigned lcore_id = rte_lcore_id();
        uint64_t prev_tsc = 0, diff_tsc, cur_tsc, timer_tsc = 0;
-       unsigned i, j, portid, nb_rx;
+       unsigned i, j, portid, nb_rx, len;
        struct lcore_queue_conf *qconf = &lcore_queue_conf[lcore_id];
        const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
                        US_PER_S * BURST_TX_DRAIN_US;
@@ -666,6 +693,18 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                port_cparams[i].block_size = options->block_size;
 
                if (port_cparams[i].do_hash) {
+                       port_cparams[i].auth_iv.data = options->auth_iv.data;
+                       port_cparams[i].auth_iv.length = options->auth_iv.length;
+                       if (!options->auth_iv_param)
+                               generate_random_key(port_cparams[i].auth_iv.data,
+                                               port_cparams[i].auth_iv.length);
+                       /* Set IV parameters */
+                       if (options->auth_iv.length) {
+                               options->auth_xform.auth.iv.offset =
+                                       IV_OFFSET + options->cipher_iv.length;
+                               options->auth_xform.auth.iv.length =
+                                       options->auth_iv.length;
+                       }
                        port_cparams[i].digest_length =
                                        options->auth_xform.auth.digest_length;
                        if (options->auth_xform.auth.add_auth_data_length) {
@@ -677,7 +716,8 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                                        generate_random_key(port_cparams[i].aad.data,
                                                port_cparams[i].aad.length);
 
-                       }
+                       } else
+                               port_cparams[i].aad.length = 0;
 
                        if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_VERIFY)
                                port_cparams[i].hash_verify = 1;
@@ -688,14 +728,17 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                }
 
                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_iv.data = options->cipher_iv.data;
+                       port_cparams[i].cipher_iv.length = options->cipher_iv.length;
+                       if (!options->cipher_iv_param)
+                               generate_random_key(port_cparams[i].cipher_iv.data,
+                                               port_cparams[i].cipher_iv.length);
 
                        port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
+                       /* Set IV parameters */
+                       options->cipher_xform.cipher.iv.offset = IV_OFFSET;
+                       options->cipher_xform.cipher.iv.length =
+                                               options->cipher_iv.length;
                }
 
                port_cparams[i].session = initialize_crypto_session(options,
@@ -720,10 +763,18 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                cur_tsc = rte_rdtsc();
 
                /*
-                * TX burst queue drain
+                * Crypto device/TX burst queue drain
                 */
                diff_tsc = cur_tsc - prev_tsc;
                if (unlikely(diff_tsc > drain_tsc)) {
+                       /* Enqueue all crypto ops remaining in buffers */
+                       for (i = 0; i < qconf->nb_crypto_devs; i++) {
+                               cparams = &port_cparams[i];
+                               len = qconf->op_buf[cparams->dev_id].len;
+                               l2fwd_crypto_send_burst(qconf, len, cparams);
+                               qconf->op_buf[cparams->dev_id].len = 0;
+                       }
+                       /* Transmit all packets remaining in buffers */
                        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) {
                                if (qconf->pkt_buf[portid].len == 0)
                                        continue;
@@ -780,7 +831,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                                                ops_burst, nb_rx) !=
                                                                nb_rx) {
                                        for (j = 0; j < nb_rx; j++)
-                                               rte_pktmbuf_free(pkts_burst[i]);
+                                               rte_pktmbuf_free(pkts_burst[j]);
 
                                        nb_rx = 0;
                                }
@@ -834,24 +885,28 @@ l2fwd_crypto_usage(const char *prgname)
                " (0 to disable, 10 default, 86400 maximum)\n"
 
                "  --cdev_type HW / SW / ANY\n"
-               "  --chain HASH_CIPHER / CIPHER_HASH\n"
+               "  --chain HASH_CIPHER / CIPHER_HASH / CIPHER_ONLY /"
+               " HASH_ONLY\n"
 
                "  --cipher_algo ALGO\n"
                "  --cipher_op ENCRYPT / DECRYPT\n"
                "  --cipher_key KEY (bytes separated with \":\")\n"
                "  --cipher_key_random_size SIZE: size of cipher key when generated randomly\n"
-               "  --iv IV (bytes separated with \":\")\n"
-               "  --iv_random_size SIZE: size of IV when generated randomly\n"
+               "  --cipher_iv IV (bytes separated with \":\")\n"
+               "  --cipher_iv_random_size SIZE: size of cipher IV when generated randomly\n"
 
                "  --auth_algo ALGO\n"
                "  --auth_op GENERATE / VERIFY\n"
                "  --auth_key KEY (bytes separated with \":\")\n"
                "  --auth_key_random_size SIZE: size of auth key when generated randomly\n"
+               "  --auth_iv IV (bytes separated with \":\")\n"
+               "  --auth_iv_random_size SIZE: size of auth IV when generated randomly\n"
                "  --aad AAD (bytes separated with \":\")\n"
                "  --aad_random_size SIZE: size of AAD when generated randomly\n"
                "  --digest_size SIZE: size of digest to be generated/verified\n"
 
-               "  --sessionless\n",
+               "  --sessionless\n"
+               "  --cryptodev_mask MASK: hexadecimal bitmask of crypto devices to configure\n",
               prgname);
 }
 
@@ -898,17 +953,14 @@ parse_crypto_opt_chain(struct l2fwd_crypto_options *options, char *optarg)
 static int
 parse_cipher_algo(enum rte_crypto_cipher_algorithm *algo, char *optarg)
 {
-       unsigned i;
 
-       for (i = 0; i < RTE_CRYPTO_CIPHER_LIST_END; i++) {
-               if (!strcmp(supported_cipher_algo[i], optarg)) {
-                       *algo = i;
-                       return 0;
-               }
+       if (rte_cryptodev_get_cipher_algo_enum(algo, optarg) < 0) {
+               RTE_LOG(ERR, USER1, "Cipher algorithm specified "
+                               "not supported!\n");
+               return -1;
        }
 
-       printf("Cipher algorithm  not supported!\n");
-       return -1;
+       return 0;
 }
 
 /** Parse crypto cipher operation command line argument */
@@ -974,17 +1026,13 @@ parse_size(int *size, const char *q_arg)
 static int
 parse_auth_algo(enum rte_crypto_auth_algorithm *algo, char *optarg)
 {
-       unsigned i;
-
-       for (i = 0; i < RTE_CRYPTO_AUTH_LIST_END; i++) {
-               if (!strcmp(supported_auth_algo[i], optarg)) {
-                       *algo = i;
-                       return 0;
-               }
+       if (rte_cryptodev_get_auth_algo_enum(algo, optarg) < 0) {
+               RTE_LOG(ERR, USER1, "Authentication algorithm specified "
+                               "not supported!\n");
+               return -1;
        }
 
-       printf("Authentication algorithm specified not supported!\n");
-       return -1;
+       return 0;
 }
 
 static int
@@ -1002,6 +1050,27 @@ parse_auth_op(enum rte_crypto_auth_operation *op, char *optarg)
        return -1;
 }
 
+static int
+parse_cryptodev_mask(struct l2fwd_crypto_options *options,
+               const char *q_arg)
+{
+       char *end = NULL;
+       uint64_t pm;
+
+       /* parse hexadecimal string */
+       pm = strtoul(q_arg, &end, 16);
+       if ((pm == '\0') || (end == NULL) || (*end != '\0'))
+               pm = 0;
+
+       options->cryptodev_mask = pm;
+       if (options->cryptodev_mask == 0) {
+               printf("invalid cryptodev_mask specified\n");
+               return -1;
+       }
+
+       return 0;
+}
+
 /** Parse long options */
 static int
 l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
@@ -1012,7 +1081,8 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
        if (strcmp(lgopts[option_index].name, "cdev_type") == 0) {
                retval = parse_cryptodev_type(&options->type, optarg);
                if (retval == 0)
-                       strcpy(options->string_type, optarg);
+                       snprintf(options->string_type, MAX_STR_LEN,
+                               "%s", optarg);
                return retval;
        }
 
@@ -1041,18 +1111,18 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
        else if (strcmp(lgopts[option_index].name, "cipher_key_random_size") == 0)
                return parse_size(&options->ckey_random_size, optarg);
 
-       else if (strcmp(lgopts[option_index].name, "iv") == 0) {
-               options->iv_param = 1;
-               options->iv.length =
-                       parse_key(options->iv.data, optarg);
-               if (options->iv.length > 0)
+       else if (strcmp(lgopts[option_index].name, "cipher_iv") == 0) {
+               options->cipher_iv_param = 1;
+               options->cipher_iv.length =
+                       parse_key(options->cipher_iv.data, optarg);
+               if (options->cipher_iv.length > 0)
                        return 0;
                else
                        return -1;
        }
 
-       else if (strcmp(lgopts[option_index].name, "iv_random_size") == 0)
-               return parse_size(&options->iv_random_size, optarg);
+       else if (strcmp(lgopts[option_index].name, "cipher_iv_random_size") == 0)
+               return parse_size(&options->cipher_iv_random_size, optarg);
 
        /* Authentication options */
        else if (strcmp(lgopts[option_index].name, "auth_algo") == 0) {
@@ -1078,6 +1148,20 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
                return parse_size(&options->akey_random_size, optarg);
        }
 
+
+       else if (strcmp(lgopts[option_index].name, "auth_iv") == 0) {
+               options->auth_iv_param = 1;
+               options->auth_iv.length =
+                       parse_key(options->auth_iv.data, optarg);
+               if (options->auth_iv.length > 0)
+                       return 0;
+               else
+                       return -1;
+       }
+
+       else if (strcmp(lgopts[option_index].name, "auth_iv_random_size") == 0)
+               return parse_size(&options->auth_iv_random_size, optarg);
+
        else if (strcmp(lgopts[option_index].name, "aad") == 0) {
                options->aad_param = 1;
                options->aad.length =
@@ -1101,6 +1185,9 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
                return 0;
        }
 
+       else if (strcmp(lgopts[option_index].name, "cryptodev_mask") == 0)
+               return parse_cryptodev_mask(options, optarg);
+
        return -1;
 }
 
@@ -1179,8 +1266,6 @@ l2fwd_crypto_parse_timer_period(struct l2fwd_crypto_options *options,
 static void
 l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
 {
-       srand(time(NULL));
-
        options->portmask = 0xffffffff;
        options->nb_ports_per_lcore = 1;
        options->refresh_period = 10000;
@@ -1195,9 +1280,9 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->ckey_param = 0;
        options->ckey_random_size = -1;
        options->cipher_xform.cipher.key.length = 0;
-       options->iv_param = 0;
-       options->iv_random_size = -1;
-       options->iv.length = 0;
+       options->cipher_iv_param = 0;
+       options->cipher_iv_random_size = -1;
+       options->cipher_iv.length = 0;
 
        options->cipher_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
        options->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
@@ -1208,6 +1293,9 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->akey_param = 0;
        options->akey_random_size = -1;
        options->auth_xform.auth.key.length = 0;
+       options->auth_iv_param = 0;
+       options->auth_iv_random_size = -1;
+       options->auth_iv.length = 0;
        options->aad_param = 0;
        options->aad_random_size = -1;
        options->aad.length = 0;
@@ -1217,6 +1305,7 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
 
        options->type = CDEV_TYPE_ANY;
+       options->cryptodev_mask = UINT64_MAX;
 }
 
 static void
@@ -1224,11 +1313,11 @@ display_cipher_info(struct l2fwd_crypto_options *options)
 {
        printf("\n---- Cipher information ---\n");
        printf("Algorithm: %s\n",
-               supported_cipher_algo[options->cipher_xform.cipher.algo]);
+               rte_crypto_cipher_algorithm_strings[options->cipher_xform.cipher.algo]);
        rte_hexdump(stdout, "Cipher key:",
                        options->cipher_xform.cipher.key.data,
                        options->cipher_xform.cipher.key.length);
-       rte_hexdump(stdout, "IV:", options->iv.data, options->iv.length);
+       rte_hexdump(stdout, "IV:", options->cipher_iv.data, options->cipher_iv.length);
 }
 
 static void
@@ -1236,10 +1325,11 @@ display_auth_info(struct l2fwd_crypto_options *options)
 {
        printf("\n---- Authentication information ---\n");
        printf("Algorithm: %s\n",
-               supported_auth_algo[options->auth_xform.auth.algo]);
+               rte_crypto_auth_algorithm_strings[options->auth_xform.auth.algo]);
        rte_hexdump(stdout, "Auth key:",
                        options->auth_xform.auth.key.data,
                        options->auth_xform.auth.key.length);
+       rte_hexdump(stdout, "IV:", options->auth_iv.data, options->auth_iv.length);
        rte_hexdump(stdout, "AAD:", options->aad.data, options->aad.length);
 }
 
@@ -1277,8 +1367,11 @@ l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
        if (options->akey_param && (options->akey_random_size != -1))
                printf("Auth key already parsed, ignoring size of random key\n");
 
-       if (options->iv_param && (options->iv_random_size != -1))
-               printf("IV already parsed, ignoring size of random IV\n");
+       if (options->cipher_iv_param && (options->cipher_iv_random_size != -1))
+               printf("Cipher IV already parsed, ignoring size of random IV\n");
+
+       if (options->auth_iv_param && (options->auth_iv_random_size != -1))
+               printf("Auth IV already parsed, ignoring size of random IV\n");
 
        if (options->aad_param && (options->aad_random_size != -1))
                printf("AAD already parsed, ignoring size of random AAD\n");
@@ -1326,26 +1419,29 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                        { "cipher_op", required_argument, 0, 0 },
                        { "cipher_key", required_argument, 0, 0 },
                        { "cipher_key_random_size", required_argument, 0, 0 },
+                       { "cipher_iv", required_argument, 0, 0 },
+                       { "cipher_iv_random_size", required_argument, 0, 0 },
 
                        { "auth_algo", required_argument, 0, 0 },
                        { "auth_op", required_argument, 0, 0 },
                        { "auth_key", required_argument, 0, 0 },
                        { "auth_key_random_size", required_argument, 0, 0 },
+                       { "auth_iv", required_argument, 0, 0 },
+                       { "auth_iv_random_size", required_argument, 0, 0 },
 
-                       { "iv", required_argument, 0, 0 },
-                       { "iv_random_size", required_argument, 0, 0 },
                        { "aad", required_argument, 0, 0 },
                        { "aad_random_size", required_argument, 0, 0 },
                        { "digest_size", required_argument, 0, 0 },
 
                        { "sessionless", no_argument, 0, 0 },
+                       { "cryptodev_mask", required_argument, 0, 0},
 
                        { NULL, 0, 0, 0 }
        };
 
        l2fwd_crypto_default_options(options);
 
-       while ((opt = getopt_long(argc, argvopt, "p:q:st:", lgopts,
+       while ((opt = getopt_long(argc, argvopt, "p:q:sT:", lgopts,
                        &option_index)) != EOF) {
                switch (opt) {
                /* long options */
@@ -1403,7 +1499,7 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                argv[optind-1] = prgname;
 
        retval = optind-1;
-       optind = 0; /* reset getopt lib */
+       optind = 1; /* reset getopt lib */
 
        return retval;
 }
@@ -1479,12 +1575,32 @@ check_type(struct l2fwd_crypto_options *options, struct rte_cryptodev_info *dev_
        return -1;
 }
 
+/* Check if the device is enabled by cryptodev_mask */
+static int
+check_cryptodev_mask(struct l2fwd_crypto_options *options,
+               uint8_t cdev_id)
+{
+       if (options->cryptodev_mask & (1 << cdev_id))
+               return 0;
+
+       return -1;
+}
+
 static inline int
 check_supported_size(uint16_t length, uint16_t min, uint16_t max,
                uint16_t increment)
 {
        uint16_t supp_size;
 
+       /* Single value */
+       if (increment == 0) {
+               if (length == min)
+                       return 0;
+               else
+                       return -1;
+       }
+
+       /* Range of values */
        for (supp_size = min; supp_size <= max; supp_size += increment) {
                if (length == supp_size)
                        return 0;
@@ -1492,6 +1608,46 @@ check_supported_size(uint16_t length, uint16_t min, uint16_t max,
 
        return -1;
 }
+
+static int
+check_iv_param(const struct rte_crypto_param_range *iv_range_size,
+               unsigned int iv_param, int iv_random_size,
+               uint16_t *iv_length)
+{
+       /*
+        * Check if length of provided IV is supported
+        * by the algorithm chosen.
+        */
+       if (iv_param) {
+               if (check_supported_size(*iv_length,
+                               iv_range_size->min,
+                               iv_range_size->max,
+                               iv_range_size->increment)
+                                       != 0) {
+                       printf("Unsupported IV length\n");
+                       return -1;
+               }
+       /*
+        * Check if length of IV to be randomly generated
+        * is supported by the algorithm chosen.
+        */
+       } else if (iv_random_size != -1) {
+               if (check_supported_size(iv_random_size,
+                               iv_range_size->min,
+                               iv_range_size->max,
+                               iv_range_size->increment)
+                                       != 0) {
+                       printf("Unsupported IV length\n");
+                       return -1;
+               }
+               *iv_length = iv_random_size;
+       /* No size provided, use minimum size. */
+       } else
+               *iv_length = iv_range_size->min;
+
+       return 0;
+}
+
 static int
 initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                uint8_t *enabled_cdevs)
@@ -1524,6 +1680,9 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        }
                };
 
+               if (check_cryptodev_mask(options, (uint8_t)cdev_id))
+                       continue;
+
                rte_cryptodev_info_get(cdev_id, &dev_info);
 
                /* Set cipher parameters */
@@ -1549,43 +1708,18 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
                                printf("Algorithm %s not supported by cryptodev %u"
                                        " or device not of preferred type (%s)\n",
-                                       supported_cipher_algo[opt_cipher_algo],
+                                       rte_crypto_cipher_algorithm_strings[opt_cipher_algo],
                                        cdev_id,
                                        options->string_type);
                                continue;
                        }
 
                        options->block_size = cap->sym.cipher.block_size;
-                       /*
-                        * Check if length of provided IV is supported
-                        * by the algorithm chosen.
-                        */
-                       if (options->iv_param) {
-                               if (check_supported_size(options->iv.length,
-                                               cap->sym.cipher.iv_size.min,
-                                               cap->sym.cipher.iv_size.max,
-                                               cap->sym.cipher.iv_size.increment)
-                                                       != 0) {
-                                       printf("Unsupported IV length\n");
-                                       return -1;
-                               }
-                       /*
-                        * Check if length of IV to be randomly generated
-                        * is supported by the algorithm chosen.
-                        */
-                       } else if (options->iv_random_size != -1) {
-                               if (check_supported_size(options->iv_random_size,
-                                               cap->sym.cipher.iv_size.min,
-                                               cap->sym.cipher.iv_size.max,
-                                               cap->sym.cipher.iv_size.increment)
-                                                       != 0) {
-                                       printf("Unsupported IV length\n");
-                                       return -1;
-                               }
-                               options->iv.length = options->iv_random_size;
-                       /* No size provided, use minimum size. */
-                       } else
-                               options->iv.length = cap->sym.cipher.iv_size.min;
+
+                       check_iv_param(&cap->sym.cipher.iv_size,
+                                       options->cipher_iv_param,
+                                       options->cipher_iv_random_size,
+                                       &options->cipher_iv.length);
 
                        /*
                         * Check if length of provided cipher key is supported
@@ -1649,13 +1783,16 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        if (cap->op == RTE_CRYPTO_OP_TYPE_UNDEFINED) {
                                printf("Algorithm %s not supported by cryptodev %u"
                                        " or device not of preferred type (%s)\n",
-                                       supported_auth_algo[opt_auth_algo],
+                                       rte_crypto_auth_algorithm_strings[opt_auth_algo],
                                        cdev_id,
                                        options->string_type);
                                continue;
                        }
 
-                       options->block_size = cap->sym.auth.block_size;
+                       check_iv_param(&cap->sym.auth.iv_size,
+                                       options->auth_iv_param,
+                                       options->auth_iv_random_size,
+                                       &options->auth_iv.length);
                        /*
                         * Check if length of provided AAD is supported
                         * by the algorithm chosen.
@@ -1763,7 +1900,14 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        return -1;
                }
 
-               l2fwd_enabled_crypto_mask |= (1 << cdev_id);
+               retval = rte_cryptodev_start(cdev_id);
+               if (retval < 0) {
+                       printf("Failed to start device %u: error %d\n",
+                                       cdev_id, retval);
+                       return -1;
+               }
+
+               l2fwd_enabled_crypto_mask |= (((uint64_t)1) << cdev_id);
 
                enabled_cdevs[cdev_id] = 1;
                enabled_cdev_count++;
@@ -1784,9 +1928,6 @@ initialize_ports(struct l2fwd_crypto_options *options)
                return -1;
        }
 
-       if (nb_ports > RTE_MAX_ETHPORTS)
-               nb_ports = RTE_MAX_ETHPORTS;
-
        /* Reset l2fwd_dst_ports */
        for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++)
                l2fwd_dst_ports[portid] = 0;
@@ -1893,10 +2034,13 @@ reserve_key_memory(struct l2fwd_crypto_options *options)
        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->cipher_iv.data = rte_malloc("cipher iv", MAX_KEY_SIZE, 0);
+       if (options->cipher_iv.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for cipher IV");
+
+       options->auth_iv.data = rte_malloc("auth iv", MAX_KEY_SIZE, 0);
+       if (options->auth_iv.data == NULL)
+               rte_exit(EXIT_FAILURE, "Failed to allocate memory for auth IV");
 
        options->aad.data = rte_malloc("aad", MAX_KEY_SIZE, 0);
        if (options->aad.data == NULL)
@@ -1925,9 +2069,6 @@ main(int argc, char **argv)
        /* reserve memory for Cipher/Auth key and IV */
        reserve_key_memory(&options);
 
-       /* fill out the supported algorithm tables */
-       fill_supported_algorithm_tables();
-
        /* parse application arguments (after the EAL ones) */
        ret = l2fwd_crypto_parse_args(&options, argc, argv);
        if (ret < 0)
@@ -1942,7 +2083,7 @@ main(int argc, char **argv)
 
        /* create crypto op pool */
        l2fwd_crypto_op_pool = rte_crypto_op_pool_create("crypto_op_pool",
-                       RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MBUF, 128, 0,
+                       RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MBUF, 128, MAXIMUM_IV_LENGTH,
                        rte_socket_id());
        if (l2fwd_crypto_op_pool == NULL)
                rte_exit(EXIT_FAILURE, "Cannot create crypto op pool\n");