diff mbox

[ovs-dev,5/5] netdev-dpdk: Support user cfg vhost socket perms

Message ID 1450463278-7931-6-git-send-email-aconole@redhat.com
State Changes Requested
Headers show

Commit Message

Aaron Conole Dec. 18, 2015, 6:27 p.m. UTC
The current DPDK vhost socket user and group permissions are derived
during creation from the DPDK library. This patch adds an action, post
socket creation, to change the socket permissions and ownership to
support multi-user systems.

This is especially useful when using vhost-user sockets from qemu, which
currently requires manual intervention to change the vhost-user sockets
allowing the qemu user access.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 INSTALL.DPDK.md   | 17 +++++++++++++++
 lib/netdev-dpdk.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 2 deletions(-)

Comments

Christian Ehrhardt Jan. 27, 2016, 3:32 p.m. UTC | #1
Aaron Conole <aconole@...> writes:

> 
> The current DPDK vhost socket user and group permissions are derived
> during creation from the DPDK library. This patch adds an action, post
> socket creation, to change the socket permissions and ownership to
> support multi-user systems.
> 
> This is especially useful when using vhost-user sockets from qemu, which
> currently requires manual intervention to change the vhost-user sockets
> allowing the qemu user access.

Hi Aaron,
as I said I gave your patches a try, here the summarized review.

I have seen that your old patches were based on your modifications to move 
dpdk config into the DB.
So I rebased the two patches to set the socket ownership to the last master 
and on top of your most recent (v6) patches for that work.

Overall I have these applied now:
patches/ovs-dev-v6-1-4-netdev-dpdk-Restore-thread-affinity-after-DPDK-
init.patch
patches/ovs-dev-v6-2-4-netdev-dpdk-Convert-initialization-from-cmdline-to-
db.patch
patches/ovs-dev-v6-3-4-netdev-dpdk-Autofill-lcore-coremask-if-absent.patch
patches/ovs-dev-v6-4-4-netdev-dpdk-Allow-arbitrary-eal-arguments.patch
patches/ovs-dev-4-5-lib-daemon-Move-the-user-group-code-up-one-level.patch
patches/ovs-dev-5-5-netdev-dpdk-Support-user-cfg-vhost-socket-perms.patch

Testing followed more or less INSTALL.dpdk.md, trying to recreate my old 
setup with your code for the new dpdk config applied.

On my first init with DPDK it failed at
"EAL: Options -m and --socket-mem cannot be specified at the same time"
But there is no socket-mem set
ovs-vsctl --no-wait get Open_vSwitch . other_config
{dpdk-alloc-mem="4096", dpdk-init="true"}

This seems to conflict with the defaults set in get_dpdk_args.
I haven't found a way to overwrite the default value for dpdk_socket_mem 
(tried setting NULL and 0).
But it always ends up having either the value I set or the default one, and 
whatever it has it conflicts with alloc-mem.

I think your patch series should have neither socket-mem nor alloc-mem as 
default, bail out if "no kind" of memory is specifed.
Actually I think DPDK would bail out, just as it does now with both being 
set.

So I went on with clearing and using socket-mem for now.
ovs-vsctl --no-wait clear Open_vSwitch . other_config
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-
init=trueroot@horsea:/home/ubuntu/ovs-review-aaron-dpdkchanges# #ovs-vsctl 
--no-wait set Open_vSwitch . other_config:dpdk_socket_mem=4096,0
ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk_socket_mem=4096,0
With that it initilizes DPDK properly.

This is the simple dpdk based config that I wanted to see if it brings up 
the socket for vhost-user-1 correctly:
    Bridge "ovsdpdkbr0"
        Port "ovsdpdkbr0"
            Interface "ovsdpdkbr0"
                type: internal
        Port "dpdk0"
            Interface "dpdk0"
                type: dpdk
        Port "vhost-user-1"
            Interface "vhost-user-1"
                type: dpdkvhostuser

Note: I like the list in the log about what was specified/missing and what 
it defaulted to:
dpdk|INFO|DPDK Enabled, initializing
dpdk|INFO|No cuse-dev-name provided - defaulting to vhost-net
dpdk|INFO|No vhost-sock-dir provided - defaulting to 
/usr/local/var/run/openvswitch
dpdk|INFO|No vhost_sock_owners provided - defaulting to (null)
dpdk|INFO|No vhost_sock_permissions provided - defaulting to 0600

Further down was the first glimpse of the control of socket permissions 
dpdk|INFO|Socket /usr/local/var/run/openvswitch/vhost-user-1 created for 
vhost-user port vhost-user-1
dpdk|INFO|Socket /usr/local/var/run/openvswitch/vhost-user-1 changed 
permissions to 0600

Here you changed the default, which formerly would have been 640.
IMHO your patch should keep the old behavior until the user specified some 
value.

Now I wanted to test path, owner and permission setting - so I set
mkdir -p /usr/local/var/run/openvswitch-vhost
ovs-vsctl --no-wait set Open_vSwitch . other_config:vhost-sock-
dir=/usr/local/var/run/openvswitch-vhost
ovs-vsctl --no-wait set Open_vSwitch . other_config:vhost_sock_owners=:kvm
ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=660
So overall I was running with
ovs-vsctl --no-wait get Open_vSwitch . other_config
{dpdk-init="true", dpdk_socket_mem="4096,0", vhost-sock-
dir="/usr/local/var/run/openvswitch-vhost", vhost_sock_owners=":kvm", 
vhost_sock_permissions="660"}

Log looks good:
dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 created 
for vhost-user port vhost-user-1
dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 changed 
permissions to 660
dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 changed 
ownership to :kvm.

But the actual socket was not 100% correct.
It was in the right path and the kvm group was set, but permissions:
s-w--w-r-T 1 root kvm     0 Jan 27 15:00 vhost-user-1=
That is mode 224, which seemed very odd at first.
But then I realized that we are passing that more or less directly to chmod 
(just through strtoul).

So I set the four digit permissions and it worked fine:
ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=0660

Still I think we should either reject the three digit config when setting 
it or at least verify the string.
- <3 digits, bail out
- 3 digits, add leading zero
- >4 digits bail out
and only then go on
Also I think on that part 
+    unsigned long int mode = strtoul(vhost_sock_perms, NULL, 0);
+    int err = chmod(vhost_sock_location, (mode_t)mode);
We should set errno=0; and check after the strtoul.


TL;DR
- we need to make alloc-mem operable again
- default permissions should be 640 as they were before
- we should add some range checks and auto-extension to the socket 
permission

Overall I like both patch series a lot!
Once you create a new version of both series based on this and other 
feedback I'm eager to test it again if that helps you.
Aaron Conole Jan. 27, 2016, 4:03 p.m. UTC | #2
Christian Ehrhardt <christian.ehrhardt@canonical.com> writes:
> Aaron Conole <aconole@...> writes:
>
>> 
>> The current DPDK vhost socket user and group permissions are derived
>> during creation from the DPDK library. This patch adds an action, post
>> socket creation, to change the socket permissions and ownership to
>> support multi-user systems.
>> 
>> This is especially useful when using vhost-user sockets from qemu, which
>> currently requires manual intervention to change the vhost-user sockets
>> allowing the qemu user access.
>
> Hi Aaron,
> as I said I gave your patches a try, here the summarized review.
>
> I have seen that your old patches were based on your modifications to move 
> dpdk config into the DB.
> So I rebased the two patches to set the socket ownership to the last master 
> and on top of your most recent (v6) patches for that work.
>
> Overall I have these applied now:
> patches/ovs-dev-v6-1-4-netdev-dpdk-Restore-thread-affinity-after-DPDK-
> init.patch
> patches/ovs-dev-v6-2-4-netdev-dpdk-Convert-initialization-from-cmdline-to-
> db.patch
> patches/ovs-dev-v6-3-4-netdev-dpdk-Autofill-lcore-coremask-if-absent.patch
> patches/ovs-dev-v6-4-4-netdev-dpdk-Allow-arbitrary-eal-arguments.patch
> patches/ovs-dev-4-5-lib-daemon-Move-the-user-group-code-up-one-level.patch
> patches/ovs-dev-5-5-netdev-dpdk-Support-user-cfg-vhost-socket-perms.patch
>
> Testing followed more or less INSTALL.dpdk.md, trying to recreate my old 
> setup with your code for the new dpdk config applied.
>
> On my first init with DPDK it failed at
> "EAL: Options -m and --socket-mem cannot be specified at the same time"
> But there is no socket-mem set
> ovs-vsctl --no-wait get Open_vSwitch . other_config
> {dpdk-alloc-mem="4096", dpdk-init="true"}
>
> This seems to conflict with the defaults set in get_dpdk_args.
> I haven't found a way to overwrite the default value for dpdk_socket_mem 
> (tried setting NULL and 0).
> But it always ends up having either the value I set or the default one, and 
> whatever it has it conflicts with alloc-mem.
>
> I think your patch series should have neither socket-mem nor alloc-mem as 
> default, bail out if "no kind" of memory is specifed.
> Actually I think DPDK would bail out, just as it does now with both being 
> set.
>
> So I went on with clearing and using socket-mem for now.
> ovs-vsctl --no-wait clear Open_vSwitch . other_config
> ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-
> init=trueroot@horsea:/home/ubuntu/ovs-review-aaron-dpdkchanges# #ovs-vsctl 
> --no-wait set Open_vSwitch . other_config:dpdk_socket_mem=4096,0
> ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk_socket_mem=4096,0
> With that it initilizes DPDK properly.
>
> This is the simple dpdk based config that I wanted to see if it brings up 
> the socket for vhost-user-1 correctly:
>     Bridge "ovsdpdkbr0"
>         Port "ovsdpdkbr0"
>             Interface "ovsdpdkbr0"
>                 type: internal
>         Port "dpdk0"
>             Interface "dpdk0"
>                 type: dpdk
>         Port "vhost-user-1"
>             Interface "vhost-user-1"
>                 type: dpdkvhostuser
>
> Note: I like the list in the log about what was specified/missing and what 
> it defaulted to:
> dpdk|INFO|DPDK Enabled, initializing
> dpdk|INFO|No cuse-dev-name provided - defaulting to vhost-net
> dpdk|INFO|No vhost-sock-dir provided - defaulting to 
> /usr/local/var/run/openvswitch
> dpdk|INFO|No vhost_sock_owners provided - defaulting to (null)
> dpdk|INFO|No vhost_sock_permissions provided - defaulting to 0600
>
> Further down was the first glimpse of the control of socket permissions 
> dpdk|INFO|Socket /usr/local/var/run/openvswitch/vhost-user-1 created for 
> vhost-user port vhost-user-1
> dpdk|INFO|Socket /usr/local/var/run/openvswitch/vhost-user-1 changed 
> permissions to 0600
>
> Here you changed the default, which formerly would have been 640.
> IMHO your patch should keep the old behavior until the user specified some 
> value.
>
> Now I wanted to test path, owner and permission setting - so I set
> mkdir -p /usr/local/var/run/openvswitch-vhost
> ovs-vsctl --no-wait set Open_vSwitch . other_config:vhost-sock-
> dir=/usr/local/var/run/openvswitch-vhost
> ovs-vsctl --no-wait set Open_vSwitch . other_config:vhost_sock_owners=:kvm
> ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=660
> So overall I was running with
> ovs-vsctl --no-wait get Open_vSwitch . other_config
> {dpdk-init="true", dpdk_socket_mem="4096,0", vhost-sock-
> dir="/usr/local/var/run/openvswitch-vhost", vhost_sock_owners=":kvm", 
> vhost_sock_permissions="660"}
>
> Log looks good:
> dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 created 
> for vhost-user port vhost-user-1
> dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 changed 
> permissions to 660
> dpdk|INFO|Socket /usr/local/var/run/openvswitch-vhost/vhost-user-1 changed 
> ownership to :kvm.
>
> But the actual socket was not 100% correct.
> It was in the right path and the kvm group was set, but permissions:
> s-w--w-r-T 1 root kvm     0 Jan 27 15:00 vhost-user-1=
> That is mode 224, which seemed very odd at first.
> But then I realized that we are passing that more or less directly to chmod 
> (just through strtoul).
>
> So I set the four digit permissions and it worked fine:
> ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=0660
>
> Still I think we should either reject the three digit config when setting 
> it or at least verify the string.
> - <3 digits, bail out
> - 3 digits, add leading zero
> - >4 digits bail out
> and only then go on
> Also I think on that part 
> +    unsigned long int mode = strtoul(vhost_sock_perms, NULL, 0);
> +    int err = chmod(vhost_sock_location, (mode_t)mode);
> We should set errno=0; and check after the strtoul.
>
>
> TL;DR
> - we need to make alloc-mem operable again
> - default permissions should be 640 as they were before
> - we should add some range checks and auto-extension to the socket 
> permission
>
> Overall I like both patch series a lot!
> Once you create a new version of both series based on this and other 
> feedback I'm eager to test it again if that helps you.

Thanks for this feedback, Christian! I'll integrate and spin a series
asap.
Ansis Atteka Jan. 30, 2016, 12:37 a.m. UTC | #3
On Fri, Dec 18, 2015 at 10:27 AM, Aaron Conole <aconole@redhat.com> wrote:
> The current DPDK vhost socket user and group permissions are derived
> during creation from the DPDK library. This patch adds an action, post
> socket creation, to change the socket permissions and ownership to
> support multi-user systems.
>
> This is especially useful when using vhost-user sockets from qemu, which
> currently requires manual intervention to change the vhost-user sockets
> allowing the qemu user access.
>
> Signed-off-by: Aaron Conole <aconole@redhat.com>
> ---
>  INSTALL.DPDK.md   | 17 +++++++++++++++
>  lib/netdev-dpdk.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 78 insertions(+), 2 deletions(-)
>
> diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
> index b9d92d0..86f934c 100644
> --- a/INSTALL.DPDK.md
> +++ b/INSTALL.DPDK.md
> @@ -554,6 +554,23 @@ have arbitrary names.
>
>      `./vswitchd/ovs-vsctl set Open_vSwitch . other_config:vhost_sock_dir=path`
>
> +  - You may specify optional user:group and permissions for the vhost-user
> +    sockets. If these are not present, the default ownership is the executing
> +    user and group for ovs-vswitchd, and the default permissions are `0600`.
> +
> +    To change the vhost-user ownership, you may modify the `vhost_sock_owners`
> +    entry in the ovsdb like:
> +
> +    `./vswitchd/ovs-vsctl set Open_vSwitch . \
> +                          other_config:vhost_sock_owners=[user][:group]`
> +
> +    To change the vhost-user permissions, you may modify the octal value
> +    `vhost_sock_permissions` entry in the ovsdb like:
> +
> +    `./vswitchd/ovs-vsctl set Open_vSwitch . \
> +                          other_config:vhost_sock_permissions=permissions`
> +
> +
>  DPDK vhost-user VM configuration:
>  ---------------------------------
>  Follow the steps below to attach vhost-user port(s) to a VM.
> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
> index 696430f..ee59250 100644
> --- a/lib/netdev-dpdk.c
> +++ b/lib/netdev-dpdk.c
> @@ -52,6 +52,7 @@
>  #include "openvswitch/vlog.h"
>  #include "smap.h"
>  #include "vswitch-idl.h"
> +#include "daemon.h"

I would try to keep #includes in alphabetical order. The reason for
this is that it reduces possibility of GIT conflicts if someone else
pushed patch after you sent yours for review, but before revewer
applied your patch in his repository.

>
>  #include "rte_config.h"
>  #include "rte_mbuf.h"
> @@ -106,6 +107,9 @@ BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
>
>  static char *cuse_dev_name = NULL;    /* Character device cuse_dev_name. */
>  static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
> +static char *vhost_sock_owner = NULL; /* user:group notation for ownership
> +                                         of vhost-user sockets */
> +static char *vhost_sock_perms = NULL; /* OCTAL string of permission bits */
>
>  /*
>   * Maximum amount of time in micro seconds to try and enqueue to vhost.
> @@ -682,6 +686,43 @@ netdev_dpdk_vhost_cuse_construct(struct netdev *netdev_)
>      return err;
>  }
>
> +static void
> +vhost_set_permissions(const char *vhost_sock_location)
> +{
> +    unsigned long int mode = strtoul(vhost_sock_perms, NULL, 0);
> +    int err = chmod(vhost_sock_location, (mode_t)mode);
> +    if (err) {
> +        VLOG_ERR("vhost-user socket cannot set permissions to %s (%s).\n",
> +                 vhost_sock_perms, ovs_strerror(err));
> +        return;
> +    }
> +    VLOG_INFO("Socket %s changed permissions to %s\n", vhost_sock_location,
> +              vhost_sock_perms);
> +}
> +
> +static void
> +vhost_set_ownership(const char *vhost_sock_location)
> +{
> +    uid_t vhuid;
> +    gid_t vhgid;
> +
> +    if (get_owners_from_str(vhost_sock_owner, &vhuid, NULL, &vhgid, false)) {
> +        VLOG_ERR("vhost-user socket unable to set ownership: %s\n",
> +                 vhost_sock_owner);
> +        return;
> +    }
> +
> +    int err = chown(vhost_sock_location, vhuid, vhgid);
FYI:

chown and chmod need to be white listed in openvswitch SELinux policy
- https://github.com/TresysTechnology/refpolicy-contrib.git.
Otherwise, SELinux for OVS must be disabled on default Fedora, CentOS
and RHEL distributions for this to work in the first place.

However, ball for this is in my hands here, because I am working on a
patch where tailored SELinux policy will be distributed from our own
packages.




> +    if (err) {
> +        VLOG_ERR("vhost-user socket unable to set ownership to %s (%s).\n",
> +                 vhost_sock_owner, ovs_strerror(err));
> +        return;
> +    }
> +
> +    VLOG_INFO("Socket %s changed ownership to %s.\n", vhost_sock_location,
> +              vhost_sock_owner);
> +}
> +
>  static int
>  netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
>  {
> @@ -700,6 +741,15 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
>                   netdev->vhost_id);
>      }
>      VLOG_INFO("Socket %s created for vhost-user port %s\n", netdev->vhost_id, netdev_->name);
> +


Try:
ovs-vsctl set Open_vSwitch . other_config:vhost_sock_owners=:nobody
<--- The first bug is that if group did not exist, then your code
picks up the last group (ssh in my case)
ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=0777

root@prmh-nsx-perf-server118:~/ovs# echo "I want this file to stay
under root:root" > /r
root@prmh-nsx-perf-server118:~/ovs# ls -la /r
-rw-r--r-- 1 root root 10 Jan 29 13:29 /r
root@prmh-nsx-perf-server118:~/ovs# ovs-vsctl add-port br0
"../../../../r" -- set interface "../../../../r" type=dpdkvhostuser
root@prmh-nsx-perf-server118:~/ovs# ls -la /r
-rwxrwxrwx 1 root ssh 10 Jan 29 13:29 /r   <---- The second bug is
that you just gave away this file to ssh group.


Note, that running Open vSwitch under confined user does not fully
solve this issue, because you could still change user:group of
/etc/openvswitch/conf.db.


Here is log snippet:

2016-01-29T21:30:36.837Z|00078|dpdk|ERR|vhost-user socket device setup
failure for socket //../../../../r
2016-01-29T21:30:36.837Z|00079|dpdk|INFO|Socket //../../../../r
created for vhost-user port ../../../../r
2016-01-29T21:30:36.837Z|00080|dpdk|INFO|Socket //../../../../r
changed permissions to 0777
2016-01-29T21:30:36.837Z|00081|dpdk|INFO|Socket //../../../../r
changed ownership to :nobody.

In your patch I would change owner:group and permissions of a file
only and only if you are 100% sure that you were the one who just
created it.




> +    if (vhost_sock_perms) {
> +        vhost_set_permissions(netdev->vhost_id);
> +    }
> +
> +    if (vhost_sock_owner) {
> +        vhost_set_ownership(netdev->vhost_id);
> +    }
> +
>      err = vhost_construct_helper(netdev_);
>      ovs_mutex_unlock(&dpdk_mutex);
>      return err;
> @@ -2217,12 +2267,16 @@ __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
>
>      VLOG_INFO("DPDK Enabled, initializing");
>
> -#ifdef VHOST_CUSE
>      if (process_vhost_flags("cuse_dev_name", strdup("vhost-net"),
>                              PATH_MAX, ovs_cfg, &cuse_dev_name)) {
> -#else
> +        /**
> +         * This is ignored when vhost_user anyway...
> +         */
> +    }
> +
>      if (process_vhost_flags("vhost_sock_dir", strdup(ovs_rundir()),
>                              NAME_MAX, ovs_cfg, &vhost_sock_dir)) {
> +#ifndef VHOST_CUSE
>          struct stat s;
>
>          err = stat(vhost_sock_dir, &s);
> @@ -2233,6 +2287,11 @@ __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
>  #endif
>      }
>
> +    (void)process_vhost_flags("vhost_sock_owners", NULL, NAME_MAX, ovs_cfg,
> +                              &vhost_sock_owner);
> +    (void)process_vhost_flags("vhost_sock_permissions", "0600", NAME_MAX,
> +                              ovs_cfg, &vhost_sock_perms);
> +
>      /* Get the main thread affinity */
>      CPU_ZERO(&cpuset);
>      err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
> --
> 2.6.1.133.gf5b6079
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
Aaron Conole Jan. 30, 2016, 5:32 p.m. UTC | #4
Thanks so much for the review, Ansis!

Ansis Atteka <aatteka@nicira.com> writes:
> On Fri, Dec 18, 2015 at 10:27 AM, Aaron Conole <aconole@redhat.com> wrote:
>> The current DPDK vhost socket user and group permissions are derived
>> during creation from the DPDK library. This patch adds an action, post
>> socket creation, to change the socket permissions and ownership to
>> support multi-user systems.
>>
>> This is especially useful when using vhost-user sockets from qemu, which
>> currently requires manual intervention to change the vhost-user sockets
>> allowing the qemu user access.
>>
>> Signed-off-by: Aaron Conole <aconole@redhat.com>
>> ---
>>  INSTALL.DPDK.md   | 17 +++++++++++++++
>>  lib/netdev-dpdk.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
>>  2 files changed, 78 insertions(+), 2 deletions(-)
>>
>> diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
>> index b9d92d0..86f934c 100644
>> --- a/INSTALL.DPDK.md
>> +++ b/INSTALL.DPDK.md
>> @@ -554,6 +554,23 @@ have arbitrary names.
>>
>>      `./vswitchd/ovs-vsctl set Open_vSwitch . other_config:vhost_sock_dir=path`
>>
>> +  - You may specify optional user:group and permissions for the vhost-user
>> +    sockets. If these are not present, the default ownership is the executing
>> +    user and group for ovs-vswitchd, and the default permissions are `0600`.
>> +
>> +    To change the vhost-user ownership, you may modify the `vhost_sock_owners`
>> +    entry in the ovsdb like:
>> +
>> +    `./vswitchd/ovs-vsctl set Open_vSwitch . \
>> +                          other_config:vhost_sock_owners=[user][:group]`
>> +
>> +    To change the vhost-user permissions, you may modify the octal value
>> +    `vhost_sock_permissions` entry in the ovsdb like:
>> +
>> +    `./vswitchd/ovs-vsctl set Open_vSwitch . \
>> +                          other_config:vhost_sock_permissions=permissions`
>> +
>> +
>>  DPDK vhost-user VM configuration:
>>  ---------------------------------
>>  Follow the steps below to attach vhost-user port(s) to a VM.
>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
>> index 696430f..ee59250 100644
>> --- a/lib/netdev-dpdk.c
>> +++ b/lib/netdev-dpdk.c
>> @@ -52,6 +52,7 @@
>>  #include "openvswitch/vlog.h"
>>  #include "smap.h"
>>  #include "vswitch-idl.h"
>> +#include "daemon.h"
>
> I would try to keep #includes in alphabetical order. The reason for
> this is that it reduces possibility of GIT conflicts if someone else
> pushed patch after you sent yours for review, but before revewer
> applied your patch in his repository.

Roger that!

>>
>>  #include "rte_config.h"
>>  #include "rte_mbuf.h"
>> @@ -106,6 +107,9 @@ BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
>>
>>  static char *cuse_dev_name = NULL;    /* Character device cuse_dev_name. */
>>  static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
>> +static char *vhost_sock_owner = NULL; /* user:group notation for ownership
>> +                                         of vhost-user sockets */
>> +static char *vhost_sock_perms = NULL; /* OCTAL string of permission bits */
>>
>>  /*
>>   * Maximum amount of time in micro seconds to try and enqueue to vhost.
>> @@ -682,6 +686,43 @@ netdev_dpdk_vhost_cuse_construct(struct netdev *netdev_)
>>      return err;
>>  }
>>
>> +static void
>> +vhost_set_permissions(const char *vhost_sock_location)
>> +{
>> +    unsigned long int mode = strtoul(vhost_sock_perms, NULL, 0);
>> +    int err = chmod(vhost_sock_location, (mode_t)mode);
>> +    if (err) {
>> +        VLOG_ERR("vhost-user socket cannot set permissions to %s (%s).\n",
>> +                 vhost_sock_perms, ovs_strerror(err));
>> +        return;
>> +    }
>> +    VLOG_INFO("Socket %s changed permissions to %s\n", vhost_sock_location,
>> +              vhost_sock_perms);
>> +}
>> +
>> +static void
>> +vhost_set_ownership(const char *vhost_sock_location)
>> +{
>> +    uid_t vhuid;
>> +    gid_t vhgid;
>> +
>> +    if (get_owners_from_str(vhost_sock_owner, &vhuid, NULL, &vhgid, false)) {
>> +        VLOG_ERR("vhost-user socket unable to set ownership: %s\n",
>> +                 vhost_sock_owner);
>> +        return;
>> +    }
>> +
>> +    int err = chown(vhost_sock_location, vhuid, vhgid);
> FYI:
>
> chown and chmod need to be white listed in openvswitch SELinux policy
> - https://github.com/TresysTechnology/refpolicy-contrib.git.
> Otherwise, SELinux for OVS must be disabled on default Fedora, CentOS
> and RHEL distributions for this to work in the first place.
>
> However, ball for this is in my hands here, because I am working on a
> patch where tailored SELinux policy will be distributed from our own
> packages.

I'll help out here if I can, as well.

>> +    if (err) {
>> +        VLOG_ERR("vhost-user socket unable to set ownership to %s (%s).\n",
>> +                 vhost_sock_owner, ovs_strerror(err));
>> +        return;
>> +    }
>> +
>> +    VLOG_INFO("Socket %s changed ownership to %s.\n", vhost_sock_location,
>> +              vhost_sock_owner);
>> +}
>> +
>>  static int
>>  netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
>>  {
>> @@ -700,6 +741,15 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
>>                   netdev->vhost_id);
>>      }
>>      VLOG_INFO("Socket %s created for vhost-user port %s\n", netdev->vhost_id, netdev_->name);
>> +
>
>
> Try:
> ovs-vsctl set Open_vSwitch . other_config:vhost_sock_owners=:nobody
> <--- The first bug is that if group did not exist, then your code
> picks up the last group (ssh in my case)
> ovs-vsctl set Open_vSwitch . other_config:vhost_sock_permissions=0777

Heh, I actuall caught this, as well; I need to incorporate the chmod
values change suggested by Christian, and I can post an RFC if you want.

> root@prmh-nsx-perf-server118:~/ovs# echo "I want this file to stay
> under root:root" > /r
> root@prmh-nsx-perf-server118:~/ovs# ls -la /r
> -rw-r--r-- 1 root root 10 Jan 29 13:29 /r
> root@prmh-nsx-perf-server118:~/ovs# ovs-vsctl add-port br0
> "../../../../r" -- set interface "../../../../r" type=dpdkvhostuser
> root@prmh-nsx-perf-server118:~/ovs# ls -la /r
> -rwxrwxrwx 1 root ssh 10 Jan 29 13:29 /r   <---- The second bug is
> that you just gave away this file to ssh group.
>
>
> Note, that running Open vSwitch under confined user does not fully
> solve this issue, because you could still change user:group of
> /etc/openvswitch/conf.db.
>
>
> Here is log snippet:
>
> 2016-01-29T21:30:36.837Z|00078|dpdk|ERR|vhost-user socket device setup
> failure for socket //../../../../r
> 2016-01-29T21:30:36.837Z|00079|dpdk|INFO|Socket //../../../../r
> created for vhost-user port ../../../../r
> 2016-01-29T21:30:36.837Z|00080|dpdk|INFO|Socket //../../../../r
> changed permissions to 0777
> 2016-01-29T21:30:36.837Z|00081|dpdk|INFO|Socket //../../../../r
> changed ownership to :nobody.
>
> In your patch I would change owner:group and permissions of a file
> only and only if you are 100% sure that you were the one who just
> created it.

Yikes, I hadn't done that test. I'll put checks around it.

>> +    if (vhost_sock_perms) {
>> +        vhost_set_permissions(netdev->vhost_id);
>> +    }
>> +
>> +    if (vhost_sock_owner) {
>> +        vhost_set_ownership(netdev->vhost_id);
>> +    }
>> +
>>      err = vhost_construct_helper(netdev_);
>>      ovs_mutex_unlock(&dpdk_mutex);
>>      return err;
>> @@ -2217,12 +2267,16 @@ __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
>>
>>      VLOG_INFO("DPDK Enabled, initializing");
>>
>> -#ifdef VHOST_CUSE
>>      if (process_vhost_flags("cuse_dev_name", strdup("vhost-net"),
>>                              PATH_MAX, ovs_cfg, &cuse_dev_name)) {
>> -#else
>> +        /**
>> +         * This is ignored when vhost_user anyway...
>> +         */
>> +    }
>> +
>>      if (process_vhost_flags("vhost_sock_dir", strdup(ovs_rundir()),
>>                              NAME_MAX, ovs_cfg, &vhost_sock_dir)) {
>> +#ifndef VHOST_CUSE
>>          struct stat s;
>>
>>          err = stat(vhost_sock_dir, &s);
>> @@ -2233,6 +2287,11 @@ __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
>>  #endif
>>      }
>>
>> +    (void)process_vhost_flags("vhost_sock_owners", NULL, NAME_MAX, ovs_cfg,
>> +                              &vhost_sock_owner);
>> +    (void)process_vhost_flags("vhost_sock_permissions", "0600", NAME_MAX,
>> +                              ovs_cfg, &vhost_sock_perms);
>> +
>>      /* Get the main thread affinity */
>>      CPU_ZERO(&cpuset);
>>      err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
>> --
>> 2.6.1.133.gf5b6079
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> http://openvswitch.org/mailman/listinfo/dev
diff mbox

Patch

diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
index b9d92d0..86f934c 100644
--- a/INSTALL.DPDK.md
+++ b/INSTALL.DPDK.md
@@ -554,6 +554,23 @@  have arbitrary names.
 
     `./vswitchd/ovs-vsctl set Open_vSwitch . other_config:vhost_sock_dir=path`
 
+  - You may specify optional user:group and permissions for the vhost-user
+    sockets. If these are not present, the default ownership is the executing
+    user and group for ovs-vswitchd, and the default permissions are `0600`.
+
+    To change the vhost-user ownership, you may modify the `vhost_sock_owners`
+    entry in the ovsdb like:
+
+    `./vswitchd/ovs-vsctl set Open_vSwitch . \
+                          other_config:vhost_sock_owners=[user][:group]`
+
+    To change the vhost-user permissions, you may modify the octal value
+    `vhost_sock_permissions` entry in the ovsdb like:
+
+    `./vswitchd/ovs-vsctl set Open_vSwitch . \
+                          other_config:vhost_sock_permissions=permissions`
+
+
 DPDK vhost-user VM configuration:
 ---------------------------------
 Follow the steps below to attach vhost-user port(s) to a VM.
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 696430f..ee59250 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -52,6 +52,7 @@ 
 #include "openvswitch/vlog.h"
 #include "smap.h"
 #include "vswitch-idl.h"
+#include "daemon.h"
 
 #include "rte_config.h"
 #include "rte_mbuf.h"
@@ -106,6 +107,9 @@  BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
 
 static char *cuse_dev_name = NULL;    /* Character device cuse_dev_name. */
 static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
+static char *vhost_sock_owner = NULL; /* user:group notation for ownership
+                                         of vhost-user sockets */
+static char *vhost_sock_perms = NULL; /* OCTAL string of permission bits */
 
 /*
  * Maximum amount of time in micro seconds to try and enqueue to vhost.
@@ -682,6 +686,43 @@  netdev_dpdk_vhost_cuse_construct(struct netdev *netdev_)
     return err;
 }
 
+static void
+vhost_set_permissions(const char *vhost_sock_location)
+{
+    unsigned long int mode = strtoul(vhost_sock_perms, NULL, 0);
+    int err = chmod(vhost_sock_location, (mode_t)mode);
+    if (err) {
+        VLOG_ERR("vhost-user socket cannot set permissions to %s (%s).\n",
+                 vhost_sock_perms, ovs_strerror(err));
+        return;
+    }
+    VLOG_INFO("Socket %s changed permissions to %s\n", vhost_sock_location,
+              vhost_sock_perms);
+}
+
+static void
+vhost_set_ownership(const char *vhost_sock_location)
+{
+    uid_t vhuid;
+    gid_t vhgid;
+
+    if (get_owners_from_str(vhost_sock_owner, &vhuid, NULL, &vhgid, false)) {
+        VLOG_ERR("vhost-user socket unable to set ownership: %s\n",
+                 vhost_sock_owner);
+        return;
+    }
+
+    int err = chown(vhost_sock_location, vhuid, vhgid);
+    if (err) {
+        VLOG_ERR("vhost-user socket unable to set ownership to %s (%s).\n",
+                 vhost_sock_owner, ovs_strerror(err));
+        return;
+    }
+
+    VLOG_INFO("Socket %s changed ownership to %s.\n", vhost_sock_location,
+              vhost_sock_owner);
+}
+
 static int
 netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
 {
@@ -700,6 +741,15 @@  netdev_dpdk_vhost_user_construct(struct netdev *netdev_)
                  netdev->vhost_id);
     }
     VLOG_INFO("Socket %s created for vhost-user port %s\n", netdev->vhost_id, netdev_->name);
+
+    if (vhost_sock_perms) {
+        vhost_set_permissions(netdev->vhost_id);
+    }
+
+    if (vhost_sock_owner) {
+        vhost_set_ownership(netdev->vhost_id);
+    }
+
     err = vhost_construct_helper(netdev_);
     ovs_mutex_unlock(&dpdk_mutex);
     return err;
@@ -2217,12 +2267,16 @@  __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
 
     VLOG_INFO("DPDK Enabled, initializing");
 
-#ifdef VHOST_CUSE
     if (process_vhost_flags("cuse_dev_name", strdup("vhost-net"),
                             PATH_MAX, ovs_cfg, &cuse_dev_name)) {
-#else
+        /**
+         * This is ignored when vhost_user anyway...
+         */
+    }
+
     if (process_vhost_flags("vhost_sock_dir", strdup(ovs_rundir()),
                             NAME_MAX, ovs_cfg, &vhost_sock_dir)) {
+#ifndef VHOST_CUSE
         struct stat s;
 
         err = stat(vhost_sock_dir, &s);
@@ -2233,6 +2287,11 @@  __dpdk_init(const struct ovsrec_open_vswitch *ovs_cfg)
 #endif
     }
 
+    (void)process_vhost_flags("vhost_sock_owners", NULL, NAME_MAX, ovs_cfg,
+                              &vhost_sock_owner);
+    (void)process_vhost_flags("vhost_sock_permissions", "0600", NAME_MAX,
+                              ovs_cfg, &vhost_sock_perms);
+    
     /* Get the main thread affinity */
     CPU_ZERO(&cpuset);
     err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);