1 Description: eal: provide option to set vhost_user socket owner/permissions
3 The API doesn't hold a way to specify a owner/permission set for vhost_user
6 Projects consuming DPDK started to do 'their own workarounds' like openvswitch
7 https://patchwork.ozlabs.org/patch/559043/
8 https://patchwork.ozlabs.org/patch/559045/
9 But for this specific example they are blocked/stalled behind a bigger
10 rework (https://patchwork.ozlabs.org/patch/604898/).
12 We need something now for existing code linking against DPDK. That implies to
13 avoid changing API/ABI. So I created a DPDK EAL commandline option based ideas
14 in the former patches.
19 - with the split libs it now nees to be listed in
20 lib/librte_eal/linuxapp/eal/rte_eal_version.map to work on link steps
21 - please note that upstream gravitates towards not extending but creating a
22 new the API in DPDK as long term solution (will take a while)
23 - also as listed before most affected projects seem to create their own
25 So over time we have to check when we can drop it at the price of a config
26 transition - likely OVS 2.6 won't need it anymore.
29 - the handling and lifecycle of this changed in Openvswitch 2.7 so we can no
30 more use internal_config.
31 - Also the upstreaming was aborted as that now clearly goes towards client
32 mode vhost sockets for this (and other issues).
33 - But until that is fully working we have to carry the workaround.
34 - Updated to work with Openvswitch 2.7 (and backward compatible to 2.6)
37 Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
38 Last-Update: 2017-05-23
40 --- a/doc/guides/testpmd_app_ug/run_app.rst
41 +++ b/doc/guides/testpmd_app_ug/run_app.rst
42 @@ -156,6 +156,25 @@ See the DPDK Getting Started Guides for
44 Use malloc instead of hugetlbfs.
48 + When creating vhost_user sockets change owner and group to the specified value.
49 + This can be given as ``user:group``, but also only ``user`` or ``:group`` are supported.
53 + --vhost-owner 'libvirt-qemu:kvm'
54 + --vhost-owner 'libvirt-qemu'
55 + --vhost-owner ':kvm'
59 + When creating vhost_user sockets set them up with these permissions.
66 Testpmd Command-line Options
67 ----------------------------
68 --- a/lib/librte_eal/common/eal_common_options.c
69 +++ b/lib/librte_eal/common/eal_common_options.c
70 @@ -95,6 +95,8 @@ eal_long_options[] = {
71 {OPT_VFIO_INTR, 1, NULL, OPT_VFIO_INTR_NUM },
72 {OPT_VMWARE_TSC_MAP, 0, NULL, OPT_VMWARE_TSC_MAP_NUM },
73 {OPT_XEN_DOM0, 0, NULL, OPT_XEN_DOM0_NUM },
74 + {OPT_VHOST_OWNER, 1, NULL, OPT_VHOST_OWNER_NUM },
75 + {OPT_VHOST_PERM, 1, NULL, OPT_VHOST_PERM_NUM },
79 --- a/lib/librte_eal/common/eal_options.h
80 +++ b/lib/librte_eal/common/eal_options.h
81 @@ -83,6 +83,10 @@ enum {
82 OPT_VMWARE_TSC_MAP_NUM,
83 #define OPT_XEN_DOM0 "xen-dom0"
85 +#define OPT_VHOST_OWNER "vhost-owner"
86 + OPT_VHOST_OWNER_NUM,
87 +#define OPT_VHOST_PERM "vhost-perm"
92 --- a/lib/librte_eal/common/include/rte_eal.h
93 +++ b/lib/librte_eal/common/include/rte_eal.h
94 @@ -286,6 +286,11 @@ static inline int rte_gettid(void)
95 #define RTE_INIT(func) \
96 static void __attribute__((constructor, used)) func(void)
99 + * Set owner/permissions on sockets if requested on EAL commandline
101 +void rte_eal_set_socket_permissions(const char *);
106 --- a/lib/librte_eal/linuxapp/eal/eal.c
107 +++ b/lib/librte_eal/linuxapp/eal/eal.c
109 #if defined(RTE_ARCH_X86)
112 +#include <sys/types.h>
116 #include <rte_common.h>
117 #include <rte_debug.h>
118 @@ -119,6 +122,12 @@ struct lcore_config lcore_config[RTE_MAX
119 /* internal configuration */
120 struct internal_config internal_config;
122 +/* workaround to be able to create the sockets under a certain set of
123 + * owner/permissions as specified to EAL until solved upstream */
124 +static uid_t debian_vhost_sock_uid = (uid_t)-1;
125 +static gid_t debian_vhost_sock_gid = (gid_t)-1;
126 +static mode_t debian_vhost_sock_perm = 0;
128 /* used by rte_rdtsc() */
129 int rte_cycles_vmware_tsc_map;
131 @@ -356,6 +365,8 @@ eal_usage(const char *prgname)
132 " --"OPT_CREATE_UIO_DEV" Create /dev/uioX (usually done by hotplug)\n"
133 " --"OPT_VFIO_INTR" Interrupt mode for VFIO (legacy|msi|msix)\n"
134 " --"OPT_XEN_DOM0" Support running on Xen dom0 without hugetlbfs\n"
135 + " --"OPT_VHOST_OWNER" Create vhost-user sockets with this owner:group\n"
136 + " --"OPT_VHOST_PERM" Create vhost-user sockets with these permissions\n"
138 /* Allow the application to print its usage message too if hook is set */
139 if ( rte_application_usage_hook ) {
140 @@ -515,6 +526,121 @@ eal_log_level_parse(int argc, char **arg
144 +/* Try to double the size of '*buf', return true
145 + * if successful, and '*sizep' will be updated with
146 + * the new size. Otherwise, return false. */
148 +enlarge_buffer(char **buf, size_t *sizep)
150 + size_t newsize = *sizep * 2;
152 + if (newsize > *sizep) {
153 + *buf = realloc(*buf, newsize);
162 +get_owners_from_str(const char *user_spec, uid_t *uid, gid_t *gid)
164 + size_t bufsize = 4096;
166 + char *pos = strchr(user_spec, ':');
167 + user_spec += strspn(user_spec, " \t\r\n");
168 + size_t len = pos ? (size_t)(pos - user_spec) : strlen(user_spec);
171 + struct passwd pwd, *res;
174 + buf = malloc(bufsize);
175 + char *user_search = NULL;
177 + user_search = malloc(len + 1);
178 + memcpy(user_search, user_spec, len);
179 + user_search[len] = '\0';
180 + while ((e = getpwnam_r(user_search, &pwd, buf, bufsize, &res)) == ERANGE) {
181 + if (!enlarge_buffer(&buf, &bufsize)) {
187 + RTE_LOG(ERR, EAL,"Failed to retrive user %s's uid (%s), aborting.",
188 + user_search, strerror(e));
192 + RTE_LOG(ERR, EAL,"user %s not found, aborting.",
198 + /* User name is not specified, use current user. */
199 + while ((e = getpwuid_r(getuid(), &pwd, buf, bufsize, &res)) == ERANGE) {
200 + if (!enlarge_buffer(&buf, &bufsize)) {
206 + RTE_LOG(ERR, EAL,"Failed to retrive current user's uid "
207 + "(%s), aborting.", strerror(e));
210 + user_search = strdup(pwd.pw_name);
220 + char *grpstr = pos + 1;
221 + grpstr += strspn(grpstr, " \t\r\n");
224 + struct group grp, *res;
227 + buf = malloc(bufsize);
228 + while ((e = getgrnam_r(grpstr, &grp, buf, bufsize, &res))
230 + if (!enlarge_buffer(&buf, &bufsize)) {
236 + RTE_LOG(ERR, EAL,"Failed to get group entry for %s, "
237 + "(%s), aborting.", grpstr,
242 + RTE_LOG(ERR, EAL,"Group %s not found, aborting.",
259 /* Parse the argument given in the command line of the application */
261 eal_parse_args(int argc, char **argv)
262 @@ -611,6 +737,26 @@ eal_parse_args(int argc, char **argv)
263 internal_config.create_uio_dev = 1;
266 + case OPT_VHOST_OWNER_NUM:
267 + if (get_owners_from_str(optarg, &debian_vhost_sock_uid,
268 + &debian_vhost_sock_gid)) {
269 + RTE_LOG(ERR, EAL,"vhost-user socket unable to get"
270 + " specified user/group: %s\n", optarg);
271 + debian_vhost_sock_uid = (uid_t)-1;
272 + debian_vhost_sock_gid = (gid_t)-1;
275 + RTE_LOG(INFO, EAL,"socket owner specified as %s (%d:%d)\n",
276 + optarg, debian_vhost_sock_uid, debian_vhost_sock_gid);
280 + case OPT_VHOST_PERM_NUM:
281 + debian_vhost_sock_perm = (mode_t)strtoul(optarg, NULL, 0);
282 + RTE_LOG(INFO, EAL,"socket perm specified as '%#o' from '%s'\n",
283 + debian_vhost_sock_perm, optarg);
287 if (opt < OPT_LONG_MIN_NUM && isprint(opt)) {
288 RTE_LOG(ERR, EAL, "Option %c is not supported "
289 @@ -995,3 +1141,47 @@ rte_eal_check_module(const char *module_
290 /* Module has been found */
295 +vhost_set_permissions(const char *vhost_sock_location)
297 + int err = chmod(vhost_sock_location, debian_vhost_sock_perm);
299 + RTE_LOG(ERR, EAL,"vhost-user socket cannot set"
300 + " permissions to %#o (%s).\n",
301 + debian_vhost_sock_perm, strerror(err));
304 + RTE_LOG(INFO, EAL,"Socket %s changed permissions"
305 + " to %#o\n", vhost_sock_location,
306 + debian_vhost_sock_perm);
310 +vhost_set_ownership(const char *vhost_sock_location)
312 + int err = chown(vhost_sock_location, debian_vhost_sock_uid, debian_vhost_sock_gid);
314 + RTE_LOG(ERR, EAL,"vhost-user socket unable to set"
315 + " ownership to %d:%d (%s).\n",
316 + debian_vhost_sock_uid, debian_vhost_sock_gid,
321 + RTE_LOG(INFO, EAL,"Socket %s changed ownership"
322 + " to %d:%d.\n", vhost_sock_location,
323 + debian_vhost_sock_uid, debian_vhost_sock_gid);
327 +rte_eal_set_socket_permissions(const char *path)
329 + if (debian_vhost_sock_perm != 0) {
330 + vhost_set_permissions(path);
333 + if (debian_vhost_sock_uid != (uid_t)-1 || debian_vhost_sock_gid != (gid_t)-1) {
334 + vhost_set_ownership(path);
337 --- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
338 +++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
339 @@ -120,6 +120,7 @@ DPDK_2.2 {
340 rte_keepalive_register_core;
341 rte_xen_dom0_supported;
343 + rte_eal_set_socket_permissions;
347 --- a/lib/librte_vhost/socket.c
348 +++ b/lib/librte_vhost/socket.c
349 @@ -98,6 +98,8 @@ struct vhost_user {
350 pthread_mutex_t mutex;
353 +#include <rte_eal.h>
355 #define MAX_VIRTIO_BACKLOG 128
357 static void vhost_user_server_new_connection(int fd, void *data, int *remove);
358 @@ -644,7 +646,7 @@ rte_vhost_driver_register(const char *pa
360 vsocket->is_server = true;
362 - ret = create_unix_socket(vsocket);
363 + rte_eal_set_socket_permissions(path);