From patchwork Tue Feb 27 16:29:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fan Zhang X-Patchwork-Id: 35507 X-Patchwork-Delegate: maxime.coquelin@redhat.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id EE5015F0F; Tue, 27 Feb 2018 17:33:23 +0100 (CET) Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by dpdk.org (Postfix) with ESMTP id D8EE35B28 for ; Tue, 27 Feb 2018 17:33:19 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Feb 2018 08:33:19 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,401,1515484800"; d="scan'208";a="204150854" Received: from silpixa00398673.ir.intel.com (HELO silpixa00398673.ger.corp.intel.com) ([10.237.223.54]) by orsmga005.jf.intel.com with ESMTP; 27 Feb 2018 08:33:18 -0800 From: Fan Zhang To: dev@dpdk.org Cc: jianjay.zhou@huawei.com, roy.fan.zhang@intel.com, yliu@fridaylinux.org Date: Tue, 27 Feb 2018 16:29:16 +0000 Message-Id: <20180227162917.35125-10-roy.fan.zhang@intel.com> X-Mailer: git-send-email 2.13.6 In-Reply-To: <20180227162917.35125-1-roy.fan.zhang@intel.com> References: <20180227162917.35125-1-roy.fan.zhang@intel.com> Subject: [dpdk-dev] [PATCH v2 09/10] examples/vhost_crypto: add vhost crypto sample application X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" This patch adds vhost_crypto sample application to DPDK. Signed-off-by: Fan Zhang --- examples/vhost_crypto/Makefile | 59 +++++ examples/vhost_crypto/main.c | 537 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 596 insertions(+) create mode 100644 examples/vhost_crypto/Makefile create mode 100644 examples/vhost_crypto/main.c diff --git a/examples/vhost_crypto/Makefile b/examples/vhost_crypto/Makefile new file mode 100644 index 000000000..e45752453 --- /dev/null +++ b/examples/vhost_crypto/Makefile @@ -0,0 +1,59 @@ +# BSD LICENSE +# +# Copyright(c) 2010-2017 Intel Corporation. All rights reserved. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ifeq ($(RTE_SDK),) +$(error "Please define RTE_SDK environment variable") +endif + +# Default target, can be overridden by command line or environment +RTE_TARGET ?= x86_64-native-linuxapp-gcc + +include $(RTE_SDK)/mk/rte.vars.mk + +ifneq ($(CONFIG_RTE_EXEC_ENV),"linuxapp") +$(info This application can only operate in a linuxapp environment, \ +please change the definition of the RTE_TARGET environment variable) +all: +else + +# binary name +APP = vhost-crypto + +# all source are stored in SRCS-y +SRCS-y := main.c + +CFLAGS += -O2 -D_FILE_OFFSET_BITS=64 +CFLAGS += $(WERROR_FLAGS) +CFLAGS += -D_GNU_SOURCE + +include $(RTE_SDK)/mk/rte.extapp.mk + +endif diff --git a/examples/vhost_crypto/main.c b/examples/vhost_crypto/main.c new file mode 100644 index 000000000..3dae84948 --- /dev/null +++ b/examples/vhost_crypto/main.c @@ -0,0 +1,537 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define NB_VIRTIO_QUEUES (1) +#define MAX_PKT_BURST (64) +#define MAX_IV_LEN (32) +#define NB_MEMPOOL_OBJS (8192) +#define NB_CRYPTO_DESCRIPTORS (4096) +#define NB_CACHE_OBJS (128) +#define SESSION_MAP_ENTRIES (1024) +#define REFRESH_TIME_SEC (3) + +#define MAX_NB_SOCKETS (32) +#define DEF_SOCKET_FILE "/tmp/vhost_crypto1.socket" + +struct vhost_crypto_options { + char *socket_files[MAX_NB_SOCKETS]; + uint32_t nb_sockets; + uint8_t cid; + uint16_t qid; + uint32_t zero_copy; + uint32_t guest_polling; +} options; + +struct vhost_crypto_info { + int vids[MAX_NB_SOCKETS]; + struct rte_mempool *sess_pool; + struct rte_mempool *cop_pool; + uint32_t lcore_id; + uint8_t cid; + uint32_t qid; + uint32_t nb_vids; + volatile uint32_t initialized[MAX_NB_SOCKETS]; + +} info; + +#define SOCKET_FILE_KEYWORD "socket-file" +#define CRYPTODEV_ID_KEYWORD "cdev-id" +#define CRYPTODEV_QUEUE_KEYWORD "cdev-queue-id" +#define ZERO_COPY_KEYWORD "zero-copy" +#define POLLING_KEYWORD "guest-polling" + +/** support *SOCKET_FILE_PATH:CRYPTODEV_ID* format */ +static int +parse_socket_arg(char *arg) +{ + uint32_t nb_sockets = options.nb_sockets; + size_t len = strlen(arg); + + if (nb_sockets >= MAX_NB_SOCKETS) { + RTE_LOG(ERR, USER1, "Too many socket files!\n"); + return -ENOMEM; + } + + options.socket_files[nb_sockets] = rte_malloc(NULL, len, 0); + if (!options.socket_files[nb_sockets]) { + RTE_LOG(ERR, USER1, "Insufficient memory\n"); + return -ENOMEM; + } + + rte_memcpy(options.socket_files[nb_sockets], arg, len); + + options.nb_sockets++; + + return 0; +} + +static int +parse_cryptodev_id(const char *q_arg) +{ + char *end = NULL; + uint64_t pm; + + /* parse decimal string */ + pm = strtoul(q_arg, &end, 10); + if ((pm == '\0') || (end == NULL) || (*end != '\0')) { + RTE_LOG(ERR, USER1, "Invalid Cryptodev ID %s\n", q_arg); + return -1; + } + + if (pm > rte_cryptodev_count()) { + RTE_LOG(ERR, USER1, "Invalid Cryptodev ID %s\n", q_arg); + return -1; + } + + options.cid = (uint8_t)pm; + + return 0; +} + +static int +parse_cdev_queue_id(const char *q_arg) +{ + char *end = NULL; + uint64_t pm; + + /* parse decimal string */ + pm = strtoul(q_arg, &end, 10); + if (pm == UINT64_MAX) { + RTE_LOG(ERR, USER1, "Invalid Cryptodev Queue ID %s\n", q_arg); + return -1; + } + + options.qid = (uint16_t)pm; + + return 0; +} + +static void +vhost_crypto_usage(const char *prgname) +{ + printf("%s [EAL options] --\n" + " --%s SOCKET-FILE-PATH\n" + " --%s CRYPTODEV_ID: crypto device id\n" + " --%s CDEV_QUEUE_ID: crypto device queue id\n" + " --%s: zero copy\n" + " --%s: guest polling\n", + prgname, SOCKET_FILE_KEYWORD, CRYPTODEV_ID_KEYWORD, + CRYPTODEV_QUEUE_KEYWORD, ZERO_COPY_KEYWORD, POLLING_KEYWORD); +} + +static int +vhost_crypto_parse_args(int argc, char **argv) +{ + int opt, ret; + char *prgname = argv[0]; + char **argvopt; + int option_index; + struct option lgopts[] = { + {SOCKET_FILE_KEYWORD, required_argument, 0, 0}, + {CRYPTODEV_ID_KEYWORD, required_argument, 0, 0}, + {CRYPTODEV_QUEUE_KEYWORD, required_argument, 0, 0}, + {ZERO_COPY_KEYWORD, no_argument, 0, 0}, + {POLLING_KEYWORD, no_argument, 0, 0}, + {NULL, 0, 0, 0} + }; + + argvopt = argv; + + while ((opt = getopt_long(argc, argvopt, "s:", + lgopts, &option_index)) != EOF) { + + switch (opt) { + case 0: + if (strcmp(lgopts[option_index].name, + SOCKET_FILE_KEYWORD) == 0) { + ret = parse_socket_arg(optarg); + if (ret < 0) { + vhost_crypto_usage(prgname); + return ret; + } + } else if (strcmp(lgopts[option_index].name, + CRYPTODEV_ID_KEYWORD) == 0) { + ret = parse_cryptodev_id(optarg); + if (ret < 0) { + vhost_crypto_usage(prgname); + return ret; + } + } else if (strcmp(lgopts[option_index].name, + CRYPTODEV_QUEUE_KEYWORD) == 0) { + ret = parse_cdev_queue_id(optarg); + if (ret < 0) { + vhost_crypto_usage(prgname); + return ret; + } + } else if (strcmp(lgopts[option_index].name, + ZERO_COPY_KEYWORD) == 0) { + options.zero_copy = 1; + } else if (strcmp(lgopts[option_index].name, + POLLING_KEYWORD) == 0) { + options.guest_polling = 1; + } else { + vhost_crypto_usage(prgname); + return -EINVAL; + } + break; + default: + return -1; + } + } + + if (options.nb_sockets == 0) { + options.socket_files[0] = strdup(DEF_SOCKET_FILE); + options.nb_sockets = 1; + RTE_LOG(INFO, USER1, + "VHOST-CRYPTO: use default socket file %s\n", + DEF_SOCKET_FILE); + } + + return 0; +} + +static int +new_device(int vid) +{ + char path[PATH_MAX]; + uint32_t idx; + int ret; + + ret = rte_vhost_get_ifname(vid, path, PATH_MAX); + if (ret) { + RTE_LOG(ERR, USER1, "Cannot find matched socket\n"); + return ret; + } + + for (idx = 0; idx < options.nb_sockets; idx++) { + if (strcmp(path, options.socket_files[idx]) == 0) + break; + } + + if (idx == options.nb_sockets) { + RTE_LOG(ERR, USER1, "Cannot find recorded socket\n"); + return -ENOENT; + } + + ret = rte_vhost_crypto_create(vid, info.cid, info.sess_pool, + rte_lcore_to_socket_id(info.lcore_id)); + if (ret) { + RTE_LOG(ERR, USER1, "Cannot create vhost crypto\n"); + return ret; + } + + ret = rte_vhost_crypto_set_zero_copy(vid, options.zero_copy); + if (ret) { + RTE_LOG(ERR, USER1, "Cannot %s zero copy feature\n", + options.zero_copy == 1 ? "enable" : "disable"); + return ret; + } + + info.vids[idx] = vid; + info.initialized[idx] = 1; + + rte_wmb(); + + RTE_LOG(INFO, USER1, "New Vhost-crypto Device %s, Device ID %d\n", path, + vid); + return 0; +} + +static void +destroy_device(int vid) +{ + uint32_t i; + + for (i = 0; i < info.nb_vids; i++) { + if (vid == info.vids[i]) + break; + } + + if (i == info.nb_vids) { + RTE_LOG(ERR, USER1, "Cannot find socket file from list\n"); + return; + } + + info.initialized[i] = 0; + + rte_wmb(); + + rte_vhost_crypto_free(vid); + + RTE_LOG(INFO, USER1, "Vhost Crypto Device %i Removed\n", vid); +} + +static const struct vhost_device_ops virtio_crypto_device_ops = { + .new_device = new_device, + .destroy_device = destroy_device, +}; + +static int +vhost_crypto_worker(__rte_unused void *arg) +{ + struct rte_crypto_op *ops[NB_VIRTIO_QUEUES][MAX_PKT_BURST + 1]; + struct rte_crypto_op *ops_deq[NB_VIRTIO_QUEUES][MAX_PKT_BURST + 1]; + uint32_t nb_inflight_ops = 0; + uint16_t nb_callfds; + int callfds[VIRTIO_CRYPTO_MAX_NUM_BURST_VQS]; + uint32_t lcore_id = rte_lcore_id(); + uint32_t burst_size = MAX_PKT_BURST; + uint32_t i, j, k; + uint32_t to_fetch, fetched; + + int ret = 0; + + RTE_LOG(INFO, USER1, "Processing on Core %u started\n", lcore_id); + + for (i = 0; i < NB_VIRTIO_QUEUES; i++) { + if (rte_crypto_op_bulk_alloc(info.cop_pool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, ops[i], + burst_size) < burst_size) { + RTE_LOG(ERR, USER1, "Failed to alloc cops\n"); + ret = -1; + goto exit; + } + } + + while (1) { + for (i = 0; i < info.nb_vids; i++) { + if (unlikely(info.initialized[i] == 0)) + continue; + + for (j = 0; j < NB_VIRTIO_QUEUES; j++) { + to_fetch = RTE_MIN(burst_size, + (NB_CRYPTO_DESCRIPTORS - + nb_inflight_ops)); + fetched = rte_vhost_crypto_fetch_requests( + info.vids[i], j, ops[j], + to_fetch); + nb_inflight_ops += rte_cryptodev_enqueue_burst( + info.cid, info.qid, ops[j], + fetched); + if (unlikely(rte_crypto_op_bulk_alloc( + info.cop_pool, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, + ops[j], fetched) < fetched)) { + RTE_LOG(ERR, USER1, "Failed realloc\n"); + return -1; + } + + fetched = rte_cryptodev_dequeue_burst( + info.cid, info.qid, + ops_deq[j], RTE_MIN(burst_size, + nb_inflight_ops)); + fetched = rte_vhost_crypto_finalize_requests( + ops_deq[j], fetched, callfds, + &nb_callfds); + + nb_inflight_ops -= fetched; + + if (!options.guest_polling) { + for (k = 0; k < nb_callfds; k++) + eventfd_write(callfds[k], + (eventfd_t)1); + } + + rte_mempool_put_bulk(info.cop_pool, + (void **)ops_deq[j], fetched); + } + } + } +exit: + return ret; +} + + +static void +unregister_drivers(int socket_num) +{ + int ret; + + ret = rte_vhost_driver_unregister(options.socket_files[socket_num]); + if (ret != 0) + RTE_LOG(ERR, USER1, + "Fail to unregister vhost driver for %s.\n", + options.socket_files[socket_num]); +} + +int +main(int argc, char *argv[]) +{ + struct rte_cryptodev_qp_conf qp_conf = {NB_CRYPTO_DESCRIPTORS}; + struct rte_cryptodev_config config; + struct rte_cryptodev_info dev_info; + uint32_t cryptodev_id; + uint32_t worker_lcore; + char name[128]; + uint32_t i = 0; + int ret; + + ret = rte_eal_init(argc, argv); + if (ret < 0) + return -1; + argc -= ret; + argv += ret; + + ret = vhost_crypto_parse_args(argc, argv); + if (ret < 0) + rte_exit(EXIT_FAILURE, "Failed to parse arguments!\n"); + + info.cid = options.cid; + info.qid = options.qid; + + worker_lcore = rte_get_next_lcore(0, 1, 0); + if (worker_lcore == RTE_MAX_LCORE) + rte_exit(EXIT_FAILURE, "Not enough lcore\n"); + + cryptodev_id = info.cid; + rte_cryptodev_info_get(cryptodev_id, &dev_info); + if (dev_info.max_nb_queue_pairs < info.qid + 1) { + RTE_LOG(ERR, USER1, "Number of queues cannot over %u", + dev_info.max_nb_queue_pairs); + goto error_exit; + } + + config.nb_queue_pairs = dev_info.max_nb_queue_pairs; + config.socket_id = rte_lcore_to_socket_id(worker_lcore); + + ret = rte_cryptodev_configure(cryptodev_id, &config); + if (ret < 0) { + RTE_LOG(ERR, USER1, "Failed to configure cryptodev %u", + cryptodev_id); + goto error_exit; + } + + snprintf(name, 127, "SESS_POOL_%u", worker_lcore); + info.sess_pool = rte_mempool_create(name, SESSION_MAP_ENTRIES, + rte_cryptodev_get_private_session_size( + cryptodev_id), 64, 0, NULL, NULL, NULL, NULL, + rte_lcore_to_socket_id(worker_lcore), 0); + if (!info.sess_pool) { + RTE_LOG(ERR, USER1, "Failed to create mempool"); + goto error_exit; + } + + snprintf(name, 127, "COPPOOL_%u", worker_lcore); + info.cop_pool = rte_crypto_op_pool_create(name, + RTE_CRYPTO_OP_TYPE_SYMMETRIC, NB_MEMPOOL_OBJS, + NB_CACHE_OBJS, 0, rte_lcore_to_socket_id(worker_lcore)); + + if (!info.cop_pool) { + RTE_LOG(ERR, USER1, "Lcore %u failed to create crypto pool", + worker_lcore); + ret = -1; + goto error_exit; + } + + info.nb_vids = options.nb_sockets; + for (i = 0; i < MAX_NB_SOCKETS; i++) + info.vids[i] = -1; + + for (i = 0; i < dev_info.max_nb_queue_pairs; i++) { + ret = rte_cryptodev_queue_pair_setup(cryptodev_id, i, + &qp_conf, rte_lcore_to_socket_id(worker_lcore), + info.sess_pool); + if (ret < 0) { + RTE_LOG(ERR, USER1, "Failed to configure qp %u\n", + info.cid); + goto error_exit; + } + } + + ret = rte_cryptodev_start(cryptodev_id); + if (ret < 0) { + RTE_LOG(ERR, USER1, "Failed to start cryptodev %u\n", info.cid); + goto error_exit; + } + + info.cid = cryptodev_id; + info.lcore_id = worker_lcore; + + if (rte_eal_remote_launch(vhost_crypto_worker, NULL, worker_lcore) + < 0) { + RTE_LOG(ERR, USER1, "Failed to start worker lcore"); + goto error_exit; + } + + for (i = 0; i < options.nb_sockets; i++) { + if (rte_vhost_driver_register(options.socket_files[i], + RTE_VHOST_USER_DEQUEUE_ZERO_COPY) < 0) { + RTE_LOG(ERR, USER1, "socket %s already exists\n", + options.socket_files[i]); + goto error_exit; + } + + rte_vhost_driver_callback_register(options.socket_files[i], + &virtio_crypto_device_ops); + + if (rte_vhost_driver_start(options.socket_files[i]) < 0) { + RTE_LOG(ERR, USER1, "failed to start vhost driver.\n"); + goto error_exit; + } + } + + RTE_LCORE_FOREACH(worker_lcore) + rte_eal_wait_lcore(worker_lcore); + + rte_mempool_free(info.sess_pool); + rte_mempool_free(info.cop_pool); + + return 0; + +error_exit: + for (i = 0; i < options.nb_sockets; i++) + unregister_drivers(i); + + rte_mempool_free(info.cop_pool); + rte_mempool_free(info.sess_pool); + + return -1; +}