fuel-plugin-ovs/ovs_build/dpdk_16.07.fuel/patches/fix-vhost-user-socket-permi...

372 lines
11 KiB
Diff

Description: eal: provide option to set vhost_user socket owner/permissions
The API doesn't hold a way to specify a owner/permission set for vhost_user
created sockets.
Projects consuming DPDK started 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/).
We need something now for existing code linking against DPDK. That implies to
avoid changing API/ABI. So I created a DPDK EAL commandline option based ideas
in the former patches.
Fixes LP: #1546565
*Update*
- with the split libs it now nees to be listed in
lib/librte_eal/linuxapp/eal/rte_eal_version.map to work on link steps
- please note that upstream gravitates towards not extending but creating a
new the API in DPDK as long term solution (will take a while)
- also as listed before most affected projects seem to create their own
workaround.
So over time we have to check when we can drop it at the price of a config
transition - likely OVS 2.6 won't need it anymore.
Forwarded: yes
Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Last-Update: 2016-09-28
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 7712bd2..28776b9 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 481c732..2126140 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 }
};
@@ -166,6 +168,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 3fb2188..dc84c5b 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 <sys/io.h>
#endif
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <rte_common.h>
#include <rte_debug.h>
@@ -344,6 +347,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 ) {
@@ -601,6 +606,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 "
@@ -943,3 +956,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_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index db8c984..bb92e57 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -139,6 +139,7 @@ DPDK_2.2 {
rte_keepalive_register_core;
rte_xen_dom0_supported;
rte_xen_mem_phy2mch;
+ rte_eal_set_socket_permissions;
} DPDK_2.1;
diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
index b35594d..dbdb8ad 100644
--- a/lib/librte_vhost/vhost_user/vhost-net-user.c
+++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
@@ -79,6 +79,8 @@ struct vhost_user {
pthread_mutex_t mutex;
};
+#include <rte_eal.h>
+
#define MAX_VIRTIO_BACKLOG 128
static void vhost_user_server_new_connection(int fd, void *data, int *remove);
@@ -699,6 +701,7 @@
vsocket->is_server = true;
ret = vhost_user_create_server(vsocket);
}
+ rte_eal_set_socket_permissions(path);
if (ret < 0) {
free(vsocket->path);
free(vsocket);