From patchwork Mon Apr 25 09:18:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Ehrhardt X-Patchwork-Id: 12222 X-Patchwork-Delegate: yuanhan.liu@linux.intel.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id 338E22BD5; Mon, 25 Apr 2016 11:18:31 +0200 (CEST) Received: from youngberry.canonical.com (youngberry.canonical.com [91.189.89.112]) by dpdk.org (Postfix) with ESMTP id ED54C2946 for ; Mon, 25 Apr 2016 11:18:29 +0200 (CEST) Received: from 1.general.mandel.uk.vpn ([10.172.196.172] helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1aucez-0002VS-Aa; Mon, 25 Apr 2016 09:18:29 +0000 From: Christian Ehrhardt To: christian.ehrhardt@canonical.com, Aaron Conole , dev@dpdk.org Date: Mon, 25 Apr 2016 11:18:16 +0200 Message-Id: <1461575896-17409-1-git-send-email-christian.ehrhardt@canonical.com> X-Mailer: git-send-email 2.7.4 Subject: [dpdk-dev] [RFC] eal: provide option to set vhost_user socket owner/permissions X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The API doesn't hold a way to specify a owner/permission set for vhost_user created sockets. I don't even think an API change would make that much sense. Projects consuming DPDK start to do 'their own workarounds' like openvswitch https://patchwork.ozlabs.org/patch/559043/ https://patchwork.ozlabs.org/patch/559045/ But for this specific example they are blocked/stalled behind a bigger rework (https://patchwork.ozlabs.org/patch/604898/). Also one could ask why each project would need their own workaround. At the same time - as I want it for existing code linking against DPDK I wanted to avoid changing API/ABI. That way I want to provide something existing users could utilize. So I created a DPDK EAL commandline option based ideas in the former patches. For myself I consider this a nice interim solution for existing released Openvswitch+DPDK solution. And I intend to put it as delta into the DPDK 2.2 currently packaged in Ubuntu to get it working more smoothly with openvswitch 2.5. But I'd be interested if DPDK in general would be interested in: a) an approach like this? b) would prefer a change of the API? c) consider it an issue of consuming projects and let them take care? Signed-off-by: Christian Ehrhardt --- doc/guides/testpmd_app_ug/run_app.rst | 19 +++ lib/librte_eal/common/eal_common_options.c | 4 + lib/librte_eal/common/eal_internal_cfg.h | 2 + lib/librte_eal/common/eal_options.h | 4 + lib/librte_eal/common/include/rte_eal.h | 5 + lib/librte_eal/linuxapp/eal/eal.c | 182 +++++++++++++++++++++++++++ lib/librte_vhost/vhost_user/vhost-net-user.c | 4 + 7 files changed, 220 insertions(+) diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst index f605564..24c9c01 100644 --- a/doc/guides/testpmd_app_ug/run_app.rst +++ b/doc/guides/testpmd_app_ug/run_app.rst @@ -156,6 +156,25 @@ See the DPDK Getting Started Guides for more information on these options. Use malloc instead of hugetlbfs. +* ``--vhost-owner`` + + When creating vhost_user sockets change owner and group to the specified value. + This can be given as ``user:group``, but also only ``user`` or ``:group`` are supported. + + Examples:: + + --vhost-owner 'libvirt-qemu:kvm' + --vhost-owner 'libvirt-qemu' + --vhost-owner ':kvm' + +* ``--vhost-perm`` + + When creating vhost_user sockets set them up with these permissions. + + For example:: + + --vhost-perm '0664' + Testpmd Command-line Options ---------------------------- diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c index 2b418d5..073198b 100644 --- a/lib/librte_eal/common/eal_common_options.c +++ b/lib/librte_eal/common/eal_common_options.c @@ -95,6 +95,8 @@ eal_long_options[] = { {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM }, {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM }, {OPT_XEN_DOM0, 0, NULL, OPT_XEN_DOM0_NUM }, + {OPT_VHOST_OWNER, 1, NULL, OPT_VHOST_OWNER_NUM }, + {OPT_VHOST_PERM, 1, NULL, OPT_VHOST_PERM_NUM }, {0, 0, NULL, 0 } }; @@ -153,6 +155,8 @@ eal_reset_internal_config(struct internal_config *internal_cfg) #endif internal_cfg->vmware_tsc_map = 0; internal_cfg->create_uio_dev = 0; + internal_cfg->vhost_sock_owner = NULL; + internal_cfg->vhost_sock_perm = NULL; } static int diff --git a/lib/librte_eal/common/eal_internal_cfg.h b/lib/librte_eal/common/eal_internal_cfg.h index 5f1367e..bdf34e3 100644 --- a/lib/librte_eal/common/eal_internal_cfg.h +++ b/lib/librte_eal/common/eal_internal_cfg.h @@ -83,6 +83,8 @@ struct internal_config { volatile enum rte_intr_mode vfio_intr_mode; const char *hugefile_prefix; /**< the base filename of hugetlbfs files */ const char *hugepage_dir; /**< specific hugetlbfs directory to use */ + const char *vhost_sock_owner; /**< owner:group of vhost_user sockets */ + const char *vhost_sock_perm; /**< permissions of vhost_user sockets */ unsigned num_hugepage_sizes; /**< how many sizes on this system */ struct hugepage_info hugepage_info[MAX_HUGEPAGE_SIZES]; diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h index a881c62..1161083 100644 --- a/lib/librte_eal/common/eal_options.h +++ b/lib/librte_eal/common/eal_options.h @@ -83,6 +83,10 @@ enum { OPT_VMWARE_TSC_MAP_NUM, #define OPT_XEN_DOM0 "xen-dom0" OPT_XEN_DOM0_NUM, +#define OPT_VHOST_OWNER "vhost-owner" + OPT_VHOST_OWNER_NUM, +#define OPT_VHOST_PERM "vhost-perm" + OPT_VHOST_PERM_NUM, OPT_LONG_MAX_NUM }; diff --git a/lib/librte_eal/common/include/rte_eal.h b/lib/librte_eal/common/include/rte_eal.h index a71d6f5..506cf24 100644 --- a/lib/librte_eal/common/include/rte_eal.h +++ b/lib/librte_eal/common/include/rte_eal.h @@ -252,6 +252,11 @@ static inline int rte_gettid(void) return RTE_PER_LCORE(_thread_id); } +/** + * Set owner/permissions on sockets if requested on EAL commandline + */ +void rte_eal_set_socket_permissions(const char *); + #ifdef __cplusplus } #endif diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c index 8aafd51..3d0b709 100644 --- a/lib/librte_eal/linuxapp/eal/eal.c +++ b/lib/librte_eal/linuxapp/eal/eal.c @@ -53,6 +53,9 @@ #if defined(RTE_ARCH_X86) #include #endif +#include +#include +#include #include #include @@ -343,6 +346,8 @@ eal_usage(const char *prgname) " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n" " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n" " --"OPT_XEN_DOM0" Support running on Xen dom0 without hugetlbfs\n" + " --"OPT_VHOST_OWNER" Create vhost-user sockets with this owner:group\n" + " --"OPT_VHOST_PERM" Create vhost-user sockets with these permissions\n" "\n"); /* Allow the application to print its usage message too if hook is set */ if ( rte_application_usage_hook ) { @@ -618,6 +623,14 @@ eal_parse_args(int argc, char **argv) internal_config.create_uio_dev = 1; break; + case OPT_VHOST_OWNER_NUM: + internal_config.vhost_sock_owner = optarg; + break; + + case OPT_VHOST_PERM_NUM: + internal_config.vhost_sock_perm = optarg; + break; + default: if (opt < OPT_LONG_MIN_NUM && isprint(opt)) { RTE_LOG(ERR, EAL, "Option %c is not supported " @@ -934,3 +947,172 @@ rte_eal_check_module(const char *module_name) /* Module has been found */ return 1; } + +/* Try to double the size of '*buf', return true + * if successful, and '*sizep' will be updated with + * the new size. Otherwise, return false. */ +static int +enlarge_buffer(char **buf, size_t *sizep) +{ + size_t newsize = *sizep * 2; + + if (newsize > *sizep) { + *buf = realloc(*buf, newsize); + *sizep = newsize; + return 1; + } + + return 0; +} + +static int +get_owners_from_str(const char *user_spec, uid_t *uid, gid_t *gid) +{ + size_t bufsize = 4096; + + char *pos = strchr(user_spec, ':'); + user_spec += strspn(user_spec, " \t\r\n"); + size_t len = pos ? (size_t)(pos - user_spec) : strlen(user_spec); + + char *buf = NULL; + struct passwd pwd, *res; + int e; + + buf = malloc(bufsize); + char *user_search = NULL; + if (len) { + user_search = malloc(len + 1); + memcpy(user_search, user_spec, len); + user_search[len] = '\0'; + while ((e = getpwnam_r(user_search, &pwd, buf, bufsize, &res)) == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e != 0) { + RTE_LOG(ERR, EAL,"Failed to retrive user %s's uid (%s), aborting.", + user_search, strerror(e)); + goto release; + } + if (res == NULL) { + RTE_LOG(ERR, EAL,"user %s not found, aborting.", + user_search); + e = -1; + goto release; + } + } else { + /* User name is not specified, use current user. */ + while ((e = getpwuid_r(getuid(), &pwd, buf, bufsize, &res)) == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e != 0) { + RTE_LOG(ERR, EAL,"Failed to retrive current user's uid " + "(%s), aborting.", strerror(e)); + goto release; + } + user_search = strdup(pwd.pw_name); + } + + if (uid) + *uid = pwd.pw_uid; + + free(buf); + buf = NULL; + + if (pos) { + char *grpstr = pos + 1; + grpstr += strspn(grpstr, " \t\r\n"); + + if (*grpstr) { + struct group grp, *res; + + bufsize = 4096; + buf = malloc(bufsize); + while ((e = getgrnam_r(grpstr, &grp, buf, bufsize, &res)) + == ERANGE) { + if (!enlarge_buffer(&buf, &bufsize)) { + break; + } + } + + if (e) { + RTE_LOG(ERR, EAL,"Failed to get group entry for %s, " + "(%s), aborting.", grpstr, + strerror(e)); + goto release; + } + if (res == NULL) { + RTE_LOG(ERR, EAL,"Group %s not found, aborting.", + grpstr); + e = -1; + goto release; + } + + if (gid) + *gid = grp.gr_gid; + } + } + + release: + free(buf); + free(user_search); + return e; +} + +static void +vhost_set_permissions(const char *vhost_sock_location) +{ + unsigned long int mode = strtoul(internal_config.vhost_sock_perm, NULL, 0); + int err = chmod(vhost_sock_location, (mode_t)mode); + if (err) { + RTE_LOG(ERR, EAL,"vhost-user socket cannot set" + " permissions to %s (%s).\n", + internal_config.vhost_sock_perm, strerror(err)); + return; + } + RTE_LOG(INFO, EAL,"Socket %s changed permissions" + " to %s\n", vhost_sock_location, + internal_config.vhost_sock_perm); +} + +static void +vhost_set_ownership(const char *vhost_sock_location) +{ + uid_t vhuid=0; + gid_t vhgid=0; + + if (get_owners_from_str(internal_config.vhost_sock_owner, &vhuid, &vhgid)) { + RTE_LOG(ERR, EAL,"vhost-user socket unable to get" + " specified user/group: %s\n", + internal_config.vhost_sock_owner); + return; + } + + int err = chown(vhost_sock_location, vhuid, vhgid); + if (err) { + RTE_LOG(ERR, EAL,"vhost-user socket unable to set" + " ownership to %s (%s).\n", + internal_config.vhost_sock_owner, strerror(err)); + return; + } + + RTE_LOG(INFO, EAL,"Socket %s changed ownership" + " to %s.\n", vhost_sock_location, + internal_config.vhost_sock_owner); +} + +void +rte_eal_set_socket_permissions(const char *path) +{ + if (internal_config.vhost_sock_perm) { + vhost_set_permissions(path); + } + + if (internal_config.vhost_sock_owner) { + vhost_set_ownership(path); + } +} diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c index df2bd64..ea8dee9 100644 --- a/lib/librte_vhost/vhost_user/vhost-net-user.c +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c @@ -51,6 +51,8 @@ #include "vhost-net.h" #include "virtio-net-user.h" +#include + #define MAX_VIRTIO_BACKLOG 128 static void vserver_new_vq_conn(int fd, void *data, int *remove); @@ -476,6 +478,8 @@ rte_vhost_driver_register(const char *path) return -1; } + rte_eal_set_socket_permissions(path); + vserver->path = strdup(path); fdset_add(&g_vhost_server.fdset, vserver->listenfd,