remove unused ring includes
[dpdk.git] / examples / l2fwd-crypto / main.c
index 5fd4ff1..ffce5f3 100644 (file)
@@ -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,7 @@
 #include <rte_per_lcore.h>
 #include <rte_prefetch.h>
 #include <rte_random.h>
-#include <rte_ring.h>
+#include <rte_hexdump.h>
 
 enum cdev_type {
        CDEV_TYPE_ANY,
@@ -133,6 +135,9 @@ 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];
+
 /** l2fwd crypto application command line options */
 struct l2fwd_crypto_options {
        unsigned portmask;
@@ -147,19 +152,23 @@ struct l2fwd_crypto_options {
 
        struct rte_crypto_sym_xform cipher_xform;
        unsigned ckey_param;
+       int ckey_random_size;
 
        struct l2fwd_key iv;
        unsigned iv_param;
+       int iv_random_size;
 
        struct rte_crypto_sym_xform auth_xform;
        uint8_t akey_param;
+       int akey_random_size;
 
        struct l2fwd_key aad;
        unsigned aad_param;
+       int aad_random_size;
+
+       int digest_size;
 
        uint16_t block_size;
-       char string_auth_algo[MAX_STR_LEN];
-       char string_cipher_algo[MAX_STR_LEN];
        char string_type[MAX_STR_LEN];
 };
 
@@ -235,7 +244,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 */
@@ -322,6 +331,37 @@ 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_AES_XCBC_MAC],
+               "AES_XCBC_MAC");
+       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");
+       strcpy(supported_auth_algo[RTE_CRYPTO_AUTH_KASUMI_F9], "KASUMI_F9");
+
+       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_CTR], "AES_CTR");
+       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");
+       strcpy(supported_cipher_algo[RTE_CRYPTO_CIPHER_KASUMI_F8], "KASUMI_F8");
+}
 
 
 static int
@@ -429,8 +469,9 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *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 SNOW3G/KASUMI algorithms, offset/length must be in bits */
+               if (cparams->auth_algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2 ||
+                               cparams->auth_algo == RTE_CRYPTO_AUTH_KASUMI_F9) {
                        op->sym->auth.data.offset = ipdata_offset << 3;
                        op->sym->auth.data.length = data_len << 3;
                } else {
@@ -451,7 +492,8 @@ l2fwd_simple_crypto_enqueue(struct rte_mbuf *m,
                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) {
+               if (cparams->cipher_algo == RTE_CRYPTO_CIPHER_SNOW3G_UEA2 ||
+                               cparams->cipher_algo == RTE_CRYPTO_CIPHER_KASUMI_F8) {
                        op->sym->cipher.data.offset = ipdata_offset << 3;
                        if (cparams->do_hash && cparams->hash_verify)
                                /* Do not cipher the hash tag */
@@ -547,10 +589,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 *
@@ -587,7 +637,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;
@@ -601,8 +651,6 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
 
        RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id);
 
-       l2fwd_crypto_options_print(options);
-
        for (i = 0; i < qconf->nb_rx_ports; i++) {
 
                portid = qconf->rx_port_list[i];
@@ -643,7 +691,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                                port_cparams[i].aad.phys_addr = options->aad.phys_addr;
                                if (!options->aad_param)
                                        generate_random_key(port_cparams[i].aad.data,
-                                               sizeof(port_cparams[i].aad.length));
+                                               port_cparams[i].aad.length);
 
                        }
 
@@ -661,7 +709,7 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                        port_cparams[i].iv.phys_addr = options->iv.phys_addr;
                        if (!options->iv_param)
                                generate_random_key(port_cparams[i].iv.data,
-                                               sizeof(port_cparams[i].iv.length));
+                                               port_cparams[i].iv.length);
 
                        port_cparams[i].cipher_algo = options->cipher_xform.cipher.algo;
                }
@@ -675,15 +723,31 @@ l2fwd_main_loop(struct l2fwd_crypto_options *options)
                                port_cparams[i].dev_id);
        }
 
+       l2fwd_crypto_options_print(options);
+
+       /*
+        * Initialize previous tsc timestamp before the loop,
+        * to avoid showing the port statistics immediately,
+        * so user can see the crypto information.
+        */
+       prev_tsc = rte_rdtsc();
        while (1) {
 
                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;
@@ -789,8 +853,8 @@ l2fwd_crypto_usage(const char *prgname)
        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_type HW / SW / ANY\n"
@@ -798,13 +862,18 @@ l2fwd_crypto_usage(const char *prgname)
 
                "  --cipher_algo ALGO\n"
                "  --cipher_op ENCRYPT / DECRYPT\n"
-               "  --cipher_key KEY\n"
-               "  --iv IV\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"
 
                "  --auth_algo ALGO\n"
                "  --auth_op GENERATE / VERIFY\n"
-               "  --auth_key KEY\n"
-               "  --aad AAD\n"
+               "  --auth_key KEY (bytes separated with \":\")\n"
+               "  --auth_key_random_size SIZE: size of auth key 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",
               prgname);
@@ -853,18 +922,13 @@ parse_crypto_opt_chain(struct l2fwd_crypto_options *options, char *optarg)
 static int
 parse_cipher_algo(enum rte_crypto_cipher_algorithm *algo, char *optarg)
 {
-       if (strcmp("AES_CBC", optarg) == 0) {
-               *algo = RTE_CRYPTO_CIPHER_AES_CBC;
-               return 0;
-       } 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;
+       unsigned i;
+
+       for (i = 0; i < RTE_CRYPTO_CIPHER_LIST_END; i++) {
+               if (!strcmp(supported_cipher_algo[i], optarg)) {
+                       *algo = (enum rte_crypto_cipher_algorithm)i;
+                       return 0;
+               }
        }
 
        printf("Cipher algorithm  not supported!\n");
@@ -906,6 +970,27 @@ parse_key(uint8_t *data, char *input_arg)
                data[byte_count++] = (uint8_t)number;
        }
 
+       return byte_count;
+}
+
+/** Parse size param*/
+static int
+parse_size(int *size, const char *q_arg)
+{
+       char *end = NULL;
+       unsigned long n;
+
+       /* parse hexadecimal string */
+       n = strtoul(q_arg, &end, 10);
+       if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
+               n = 0;
+
+       if (n == 0) {
+               printf("invalid size\n");
+               return -1;
+       }
+
+       *size = n;
        return 0;
 }
 
@@ -913,33 +998,13 @@ parse_key(uint8_t *data, char *input_arg)
 static int
 parse_auth_algo(enum rte_crypto_auth_algorithm *algo, char *optarg)
 {
-       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;
-       } else if (strcmp("SHA224_HMAC", optarg) == 0) {
-               *algo = RTE_CRYPTO_AUTH_SHA224_HMAC;
-               return 0;
-       } else if (strcmp("SHA256_HMAC", optarg) == 0) {
-               *algo = RTE_CRYPTO_AUTH_SHA256_HMAC;
-               return 0;
-       }  else if (strcmp("SHA384_HMAC", optarg) == 0) {
-               *algo = RTE_CRYPTO_AUTH_SHA384_HMAC;
-               return 0;
-       } 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;
+       unsigned i;
+
+       for (i = 0; i < RTE_CRYPTO_AUTH_LIST_END; i++) {
+               if (!strcmp(supported_auth_algo[i], optarg)) {
+                       *algo = (enum rte_crypto_auth_algorithm)i;
+                       return 0;
+               }
        }
 
        printf("Authentication algorithm specified not supported!\n");
@@ -968,20 +1033,21 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
 {
        int retval;
 
-       if (strcmp(lgopts[option_index].name, "cdev_type") == 0)
-               return parse_cryptodev_type(&options->type, optarg);
+       if (strcmp(lgopts[option_index].name, "cdev_type") == 0) {
+               retval = parse_cryptodev_type(&options->type, optarg);
+               if (retval == 0)
+                       snprintf(options->string_type, MAX_STR_LEN,
+                               "%s", 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) {
-               retval = parse_cipher_algo(&options->cipher_xform.cipher.algo,
+       else if (strcmp(lgopts[option_index].name, "cipher_algo") == 0)
+               return 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,
@@ -989,21 +1055,34 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
 
        else if (strcmp(lgopts[option_index].name, "cipher_key") == 0) {
                options->ckey_param = 1;
-               return parse_key(options->cipher_xform.cipher.key.data, optarg);
+               options->cipher_xform.cipher.key.length =
+                       parse_key(options->cipher_xform.cipher.key.data, optarg);
+               if (options->cipher_xform.cipher.key.length > 0)
+                       return 0;
+               else
+                       return -1;
        }
 
+       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;
-               return parse_key(options->iv.data, optarg);
+               options->iv.length =
+                       parse_key(options->iv.data, optarg);
+               if (options->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);
+
        /* Authentication options */
        else if (strcmp(lgopts[option_index].name, "auth_algo") == 0) {
-               retval = parse_auth_algo(&options->auth_xform.auth.algo,
+               return 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)
@@ -1012,12 +1091,34 @@ l2fwd_crypto_parse_args_long_options(struct l2fwd_crypto_options *options,
 
        else if (strcmp(lgopts[option_index].name, "auth_key") == 0) {
                options->akey_param = 1;
-               return parse_key(options->auth_xform.auth.key.data, optarg);
+               options->auth_xform.auth.key.length =
+                       parse_key(options->auth_xform.auth.key.data, optarg);
+               if (options->auth_xform.auth.key.length > 0)
+                       return 0;
+               else
+                       return -1;
+       }
+
+       else if (strcmp(lgopts[option_index].name, "auth_key_random_size") == 0) {
+               return parse_size(&options->akey_random_size, optarg);
        }
 
        else if (strcmp(lgopts[option_index].name, "aad") == 0) {
                options->aad_param = 1;
-               return parse_key(options->aad.data, optarg);
+               options->aad.length =
+                       parse_key(options->aad.data, optarg);
+               if (options->aad.length > 0)
+                       return 0;
+               else
+                       return -1;
+       }
+
+       else if (strcmp(lgopts[option_index].name, "aad_random_size") == 0) {
+               return parse_size(&options->aad_random_size, optarg);
+       }
+
+       else if (strcmp(lgopts[option_index].name, "digest_size") == 0) {
+               return parse_size(&options->digest_size, optarg);
        }
 
        else if (strcmp(lgopts[option_index].name, "sessionless") == 0) {
@@ -1103,8 +1204,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;
@@ -1117,7 +1216,11 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->cipher_xform.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
        options->cipher_xform.next = NULL;
        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_xform.cipher.algo = RTE_CRYPTO_CIPHER_AES_CBC;
        options->cipher_xform.cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
@@ -1126,7 +1229,12 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->auth_xform.type = RTE_CRYPTO_SYM_XFORM_AUTH;
        options->auth_xform.next = NULL;
        options->akey_param = 0;
+       options->akey_random_size = -1;
+       options->auth_xform.auth.key.length = 0;
        options->aad_param = 0;
+       options->aad_random_size = -1;
+       options->aad.length = 0;
+       options->digest_size = -1;
 
        options->auth_xform.auth.algo = RTE_CRYPTO_AUTH_SHA1_HMAC;
        options->auth_xform.auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
@@ -1134,9 +1242,46 @@ l2fwd_crypto_default_options(struct l2fwd_crypto_options *options)
        options->type = CDEV_TYPE_ANY;
 }
 
+static void
+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_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);
+}
+
+static void
+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_hexdump(stdout, "Auth key:",
+                       options->auth_xform.auth.key.data,
+                       options->auth_xform.auth.key.length);
+       rte_hexdump(stdout, "AAD:", options->aad.data, options->aad.length);
+}
+
 static void
 l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
 {
+       char string_cipher_op[MAX_STR_LEN];
+       char string_auth_op[MAX_STR_LEN];
+
+       if (options->cipher_xform.cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
+               strcpy(string_cipher_op, "Encrypt");
+       else
+               strcpy(string_cipher_op, "Decrypt");
+
+       if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_GENERATE)
+               strcpy(string_auth_op, "Auth generate");
+       else
+               strcpy(string_auth_op, "Auth verify");
+
        printf("Options:-\nn");
        printf("portmask: %x\n", options->portmask);
        printf("ports per lcore: %u\n", options->nb_ports_per_lcore);
@@ -1148,6 +1293,42 @@ l2fwd_crypto_options_print(struct l2fwd_crypto_options *options)
 
        printf("sessionless crypto: %s\n",
                        options->sessionless ? "enabled" : "disabled");
+
+       if (options->ckey_param && (options->ckey_random_size != -1))
+               printf("Cipher key already parsed, ignoring size of random key\n");
+
+       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->aad_param && (options->aad_random_size != -1))
+               printf("AAD already parsed, ignoring size of random AAD\n");
+
+       printf("\nCrypto chain: ");
+       switch (options->xform_chain) {
+       case L2FWD_CRYPTO_CIPHER_HASH:
+               printf("Input --> %s --> %s --> Output\n",
+                       string_cipher_op, string_auth_op);
+               display_cipher_info(options);
+               display_auth_info(options);
+               break;
+       case L2FWD_CRYPTO_HASH_CIPHER:
+               printf("Input --> %s --> %s --> Output\n",
+                       string_auth_op, string_cipher_op);
+               display_cipher_info(options);
+               display_auth_info(options);
+               break;
+       case L2FWD_CRYPTO_HASH_ONLY:
+               printf("Input --> %s --> Output\n", string_auth_op);
+               display_auth_info(options);
+               break;
+       case L2FWD_CRYPTO_CIPHER_ONLY:
+               printf("Input --> %s --> Output\n", string_cipher_op);
+               display_cipher_info(options);
+               break;
+       }
 }
 
 /* Parse the argument given in the command line of the application */
@@ -1167,13 +1348,18 @@ l2fwd_crypto_parse_args(struct l2fwd_crypto_options *options,
                        { "cipher_algo", required_argument, 0, 0 },
                        { "cipher_op", required_argument, 0, 0 },
                        { "cipher_key", required_argument, 0, 0 },
+                       { "cipher_key_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 },
 
                        { "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 },
 
@@ -1220,7 +1406,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) {
@@ -1277,7 +1463,7 @@ check_all_ports_link_status(uint8_t port_num, uint32_t port_mask)
                                continue;
                        }
                        /* clear all_ports_up flag if any link down */
-                       if (link.link_status == 0) {
+                       if (link.link_status == ETH_LINK_DOWN) {
                                all_ports_up = 0;
                                break;
                        }
@@ -1316,6 +1502,28 @@ check_type(struct l2fwd_crypto_options *options, struct rte_cryptodev_info *dev_
        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;
+       }
+
+       return -1;
+}
 static int
 initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                uint8_t *enabled_cdevs)
@@ -1373,15 +1581,78 @@ 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",
-                                       options->string_cipher_algo, cdev_id,
+                                       supported_cipher_algo[opt_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 =
+                       /*
+                        * 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 if length of provided cipher key is supported
+                        * by the algorithm chosen.
+                        */
+                       if (options->ckey_param) {
+                               if (check_supported_size(
+                                               options->cipher_xform.cipher.key.length,
+                                               cap->sym.cipher.key_size.min,
+                                               cap->sym.cipher.key_size.max,
+                                               cap->sym.cipher.key_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported cipher key length\n");
+                                       return -1;
+                               }
+                       /*
+                        * Check if length of the cipher key to be randomly generated
+                        * is supported by the algorithm chosen.
+                        */
+                       } else if (options->ckey_random_size != -1) {
+                               if (check_supported_size(options->ckey_random_size,
+                                               cap->sym.cipher.key_size.min,
+                                               cap->sym.cipher.key_size.max,
+                                               cap->sym.cipher.key_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported cipher key length\n");
+                                       return -1;
+                               }
+                               options->cipher_xform.cipher.key.length =
+                                                       options->ckey_random_size;
+                       /* No size provided, use minimum size. */
+                       } else
+                               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,
@@ -1410,23 +1681,102 @@ 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",
-                                       options->string_auth_algo, cdev_id,
+                                       supported_auth_algo[opt_auth_algo],
+                                       cdev_id,
                                        options->string_type);
                                continue;
                        }
 
                        options->block_size = cap->sym.auth.block_size;
+                       /*
+                        * Check if length of provided AAD is supported
+                        * by the algorithm chosen.
+                        */
+                       if (options->aad_param) {
+                               if (check_supported_size(options->aad.length,
+                                               cap->sym.auth.aad_size.min,
+                                               cap->sym.auth.aad_size.max,
+                                               cap->sym.auth.aad_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported AAD length\n");
+                                       return -1;
+                               }
+                       /*
+                        * Check if length of AAD to be randomly generated
+                        * is supported by the algorithm chosen.
+                        */
+                       } else if (options->aad_random_size != -1) {
+                               if (check_supported_size(options->aad_random_size,
+                                               cap->sym.auth.aad_size.min,
+                                               cap->sym.auth.aad_size.max,
+                                               cap->sym.auth.aad_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported AAD length\n");
+                                       return -1;
+                               }
+                               options->aad.length = options->aad_random_size;
+                       /* No size provided, use minimum size. */
+                       } else
+                               options->aad.length = cap->sym.auth.aad_size.min;
+
                        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 =
+                                               options->aad.length;
+
+                       /*
+                        * Check if length of provided auth key is supported
+                        * by the algorithm chosen.
+                        */
+                       if (options->akey_param) {
+                               if (check_supported_size(
+                                               options->auth_xform.auth.key.length,
+                                               cap->sym.auth.key_size.min,
+                                               cap->sym.auth.key_size.max,
+                                               cap->sym.auth.key_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported auth key length\n");
+                                       return -1;
+                               }
+                       /*
+                        * Check if length of the auth key to be randomly generated
+                        * is supported by the algorithm chosen.
+                        */
+                       } else if (options->akey_random_size != -1) {
+                               if (check_supported_size(options->akey_random_size,
+                                               cap->sym.auth.key_size.min,
+                                               cap->sym.auth.key_size.max,
+                                               cap->sym.auth.key_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported auth key length\n");
+                                       return -1;
+                               }
+                               options->auth_xform.auth.key.length =
+                                                       options->akey_random_size;
+                       /* No size provided, use minimum size. */
+                       } else
+                               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);
+
+                       /* Check if digest size is supported by the algorithm. */
+                       if (options->digest_size != -1) {
+                               if (check_supported_size(options->digest_size,
+                                               cap->sym.auth.digest_size.min,
+                                               cap->sym.auth.digest_size.max,
+                                               cap->sym.auth.digest_size.increment)
+                                                       != 0) {
+                                       printf("Unsupported digest length\n");
+                                       return -1;
+                               }
+                               options->auth_xform.auth.digest_length =
+                                                       options->digest_size;
+                       /* No size provided, use minimum size. */
+                       } else
+                               options->auth_xform.auth.digest_length =
+                                               cap->sym.auth.digest_size.min;
                }
 
                retval = rte_cryptodev_configure(cdev_id, &conf);
@@ -1445,6 +1795,13 @@ initialize_cryptodevs(struct l2fwd_crypto_options *options, unsigned nb_ports,
                        return -1;
                }
 
+               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 |= (1 << cdev_id);
 
                enabled_cdevs[cdev_id] = 1;
@@ -1466,9 +1823,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;
@@ -1607,6 +1961,9 @@ 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)