doc: add cryptodev sample code
authorPablo de Lara <pablo.de.lara.guarch@intel.com>
Fri, 28 Jul 2017 06:02:45 +0000 (07:02 +0100)
committerPablo de Lara <pablo.de.lara.guarch@intel.com>
Fri, 28 Jul 2017 16:49:02 +0000 (18:49 +0200)
In order to illustrate in a simple way how to use
the cryptodev API to perform a basic crypto operation,
sample code has been added in the Programmer's Guide.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
doc/guides/prog_guide/cryptodev_lib.rst

index 81a6b1f..75ae085 100644 (file)
@@ -573,6 +573,212 @@ chain.
         };
     };
 
+Sample code
+-----------
+
+There are various sample applications that show how to use the cryptodev library,
+such as the L2fwd with Crypto sample application (L2fwd-crypto) and
+the IPSec Security Gateway application (ipsec-secgw).
+
+While these applications demonstrate how an application can be created to perform
+generic crypto operation, the required complexity hides the basic steps of
+how to use the cryptodev APIs.
+
+The following sample code shows the basic steps to encrypt several buffers
+with AES-CBC (although performing other crypto operations is similar),
+using one of the crypto PMDs available in DPDK.
+
+.. code-block:: c
+
+    /*
+     * Simple example to encrypt several buffers with AES-CBC using
+     * the Cryptodev APIs.
+     */
+
+    #define MAX_SESSIONS         1024
+    #define NUM_MBUFS            1024
+    #define POOL_CACHE_SIZE      128
+    #define BURST_SIZE           32
+    #define BUFFER_SIZE          1024
+    #define AES_CBC_IV_LENGTH    16
+    #define AES_CBC_KEY_LENGTH   16
+    #define IV_OFFSET            (sizeof(struct rte_crypto_op) + \
+                                 sizeof(struct rte_crypto_sym_op))
+
+    struct rte_mempool *mbuf_pool, *crypto_op_pool, *session_pool;
+    unsigned int session_size;
+    int ret;
+
+    /* Initialize EAL. */
+    ret = rte_eal_init(argc, argv);
+    if (ret < 0)
+        rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
+
+    uint8_t socket_id = rte_socket_id();
+
+    /* Create the mbuf pool. */
+    mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
+                                    NUM_MBUFS,
+                                    POOL_CACHE_SIZE,
+                                    0,
+                                    RTE_MBUF_DEFAULT_BUF_SIZE,
+                                    socket_id);
+    if (mbuf_pool == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+    /*
+     * The IV is always placed after the crypto operation,
+     * so some private data is required to be reserved.
+     */
+    unsigned int crypto_op_private_data = AES_CBC_IV_LENGTH;
+
+    /* Create crypto operation pool. */
+    crypto_op_pool = rte_crypto_op_pool_create("crypto_op_pool",
+                                            RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                                            NUM_MBUFS,
+                                            POOL_CACHE_SIZE,
+                                            crypto_op_private_data,
+                                            socket_id);
+    if (crypto_op_pool == NULL)
+        rte_exit(EXIT_FAILURE, "Cannot create crypto op pool\n");
+
+    /* Create the virtual crypto device. */
+    char args[128];
+    const char *crypto_name = "crypto_aesni_mb0";
+    snprintf(args, sizeof(args), "socket_id=%d", socket_id);
+    ret = rte_vdev_init(crypto_name, args);
+    if (ret != 0)
+        rte_exit(EXIT_FAILURE, "Cannot create virtual device");
+
+    uint8_t cdev_id = rte_cryptodev_get_dev_id(crypto_name);
+
+    /* Get private session data size. */
+    session_size = rte_cryptodev_get_private_session_size(cdev_id);
+
+    /*
+     * Create session mempool, with two objects per session,
+     * one for the session header and another one for the
+     * private session data for the crypto device.
+     */
+    session_pool = rte_mempool_create("session_pool",
+                                    MAX_SESSIONS * 2,
+                                    session_size,
+                                    POOL_CACHE_SIZE,
+                                    0, NULL, NULL, NULL,
+                                    NULL, socket_id,
+                                    0);
+
+    /* Configure the crypto device. */
+    struct rte_cryptodev_config conf = {
+        .nb_queue_pairs = 1,
+        .socket_id = socket_id
+    };
+    struct rte_cryptodev_qp_conf qp_conf = {
+        .nb_descriptors = 2048
+    };
+
+    if (rte_cryptodev_configure(cdev_id, &conf) < 0)
+        rte_exit(EXIT_FAILURE, "Failed to configure cryptodev %u", cdev_id);
+
+    if (rte_cryptodev_queue_pair_setup(cdev_id, 0, &qp_conf,
+                            socket_id, session_pool) < 0)
+        rte_exit(EXIT_FAILURE, "Failed to setup queue pair\n");
+
+    if (rte_cryptodev_start(cdev_id) < 0)
+        rte_exit(EXIT_FAILURE, "Failed to start device\n");
+
+    /* Create the crypto transform. */
+    uint8_t cipher_key[16] = {0};
+    struct rte_crypto_sym_xform cipher_xform = {
+        .next = NULL,
+        .type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+        .cipher = {
+            .op = RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+            .algo = RTE_CRYPTO_CIPHER_AES_CBC,
+            .key = {
+                .data = cipher_key,
+                .length = AES_CBC_KEY_LENGTH
+            },
+            .iv = {
+                .offset = IV_OFFSET,
+                .length = AES_CBC_IV_LENGTH
+            }
+        }
+    };
+
+    /* Create crypto session and initialize it for the crypto device. */
+    struct rte_cryptodev_sym_session *session;
+    session = rte_cryptodev_sym_session_create(session_pool);
+    if (session == NULL)
+        rte_exit(EXIT_FAILURE, "Session could not be created\n");
+
+    if (rte_cryptodev_sym_session_init(cdev_id, session,
+                    &cipher_xform, session_pool) < 0)
+        rte_exit(EXIT_FAILURE, "Session could not be initialized "
+                    "for the crypto device\n");
+
+    /* Get a burst of crypto operations. */
+    struct rte_crypto_op *crypto_ops[BURST_SIZE];
+    if (rte_crypto_op_bulk_alloc(crypto_op_pool,
+                            RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+                            crypto_ops, BURST_SIZE) == 0)
+        rte_exit(EXIT_FAILURE, "Not enough crypto operations available\n");
+
+    /* Get a burst of mbufs. */
+    struct rte_mbuf *mbufs[BURST_SIZE];
+    if (rte_pktmbuf_alloc_bulk(mbuf_pool, mbufs, BURST_SIZE) < 0)
+        rte_exit(EXIT_FAILURE, "Not enough mbufs available");
+
+    /* Initialize the mbufs and append them to the crypto operations. */
+    unsigned int i;
+    for (i = 0; i < BURST_SIZE; i++) {
+        if (rte_pktmbuf_append(mbufs[i], BUFFER_SIZE) == NULL)
+            rte_exit(EXIT_FAILURE, "Not enough room in the mbuf\n");
+        crypto_ops[i]->sym->m_src = mbufs[i];
+    }
+
+    /* Set up the crypto operations. */
+    for (i = 0; i < BURST_SIZE; i++) {
+        struct rte_crypto_op *op = crypto_ops[i];
+        /* Modify bytes of the IV at the end of the crypto operation */
+        uint8_t *iv_ptr = rte_crypto_op_ctod_offset(op, uint8_t *,
+                                                IV_OFFSET);
+
+        generate_random_bytes(iv_ptr, AES_CBC_IV_LENGTH);
+
+        op->sym->cipher.data.offset = 0;
+        op->sym->cipher.data.length = BUFFER_SIZE;
+
+        /* Attach the crypto session to the operation */
+        rte_crypto_op_attach_sym_session(op, session);
+    }
+
+    /* Enqueue the crypto operations in the crypto device. */
+    uint16_t num_enqueued_ops = rte_cryptodev_enqueue_burst(cdev_id, 0,
+                                            crypto_ops, BURST_SIZE);
+
+    /*
+     * Dequeue the crypto operations until all the operations
+     * are proccessed in the crypto device.
+     */
+    uint16_t num_dequeued_ops, total_num_dequeued_ops = 0;
+    do {
+        struct rte_crypto_op *dequeued_ops[BURST_SIZE];
+        num_dequeued_ops = rte_cryptodev_dequeue_burst(cdev_id, 0,
+                                        dequeued_ops, BURST_SIZE);
+        total_num_dequeued_ops += num_dequeued_ops;
+
+        /* Check if operation was processed successfully */
+        for (i = 0; i < num_dequeued_ops; i++) {
+            if (dequeued_ops[i]->status != RTE_CRYPTO_OP_STATUS_SUCCESS)
+                rte_exit(EXIT_FAILURE,
+                        "Some operations were not processed correctly");
+        }
+
+        rte_mempool_put_bulk(crypto_op_pool, (void **)dequeued_ops,
+                                            num_dequeued_ops);
+    } while (total_num_dequeued_ops < num_enqueued_ops);
+
 
 Asymmetric Cryptography
 -----------------------