diff mbox

[ovs-dev,RFC,1/1] netdev-dpdk: vHost client mode and reconnect

Message ID 1468319227-19544-2-git-send-email-ciara.loftus@intel.com
State Superseded
Delegated to: Daniele Di Proietto
Headers show

Commit Message

Ciara Loftus July 12, 2016, 10:27 a.m. UTC
A new other_config DB option has been added called 'vhost_driver_mode'.
By default this is set to 'server' which is the mode of operation OVS
with DPDK has used up until this point - whereby OVS creates and manages
vHost user sockets.

If set to 'client', OVS will act as the vHost client and connect to
sockets created and managed by QEMU which acts as the server. This mode
allows for reconnect capability, which allows vHost ports to resume
normal connectivity in event of switch reset.

QEMU v2.7.0+ is required when using OVS in client mode and QEMU in
server mode.

Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
---
 INSTALL.DPDK-ADVANCED.md | 27 +++++++++++++++++++++++++++
 NEWS                     |  1 +
 lib/netdev-dpdk.c        | 37 ++++++++++++++++++++++++++-----------
 vswitchd/vswitch.xml     | 13 +++++++++++++
 4 files changed, 67 insertions(+), 11 deletions(-)

Comments

Aaron Conole July 12, 2016, 4:58 p.m. UTC | #1
Ciara Loftus <ciara.loftus@intel.com> writes:

> A new other_config DB option has been added called 'vhost_driver_mode'.
> By default this is set to 'server' which is the mode of operation OVS
> with DPDK has used up until this point - whereby OVS creates and manages
> vHost user sockets.
>
> If set to 'client', OVS will act as the vHost client and connect to
> sockets created and managed by QEMU which acts as the server. This mode
> allows for reconnect capability, which allows vHost ports to resume
> normal connectivity in event of switch reset.
>
> QEMU v2.7.0+ is required when using OVS in client mode and QEMU in
> server mode.
>
> Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
> ---
>  INSTALL.DPDK-ADVANCED.md | 27 +++++++++++++++++++++++++++
>  NEWS                     |  1 +
>  lib/netdev-dpdk.c        | 37 ++++++++++++++++++++++++++-----------
>  vswitchd/vswitch.xml     | 13 +++++++++++++
>  4 files changed, 67 insertions(+), 11 deletions(-)
>
> diff --git a/INSTALL.DPDK-ADVANCED.md b/INSTALL.DPDK-ADVANCED.md
> index ec1de29..ad3e59e 100644
> --- a/INSTALL.DPDK-ADVANCED.md
> +++ b/INSTALL.DPDK-ADVANCED.md
> @@ -489,6 +489,33 @@ DPDK 16.07 supports two types of vhost:
>         where `-L`: Changes the numbers of channels of the specified network device
>         and `combined`: Changes the number of multi-purpose channels.
>  
> +    4. Enable OVS vHost client-mode & vHost reconnect (OPTIONAL)
> +
> +       By default, OVS DPDK acts as the vHost socket server and QEMU the
> +       client. In QEMU v2.7 the option is available for QEMU to act as the
> +       server. In order for this to work, OVS DPDK must be switched to 'client'
> +       mode. This is possible by setting the 'vhost_driver_mode' DB entry to
> +       'client' like so:
> +
> +       ```
> +       ovs-vsctl set Open_vSwitch . other_config:vhost_driver_mode="client"
> +       ```
> +
> +       This must be done before the switch is launched. It cannot sucessfully
> +       be changed after switch has launched.
> +
> +       One must also append ',server' to the 'chardev' arguments on the QEMU
> +       command line, to instruct QEMU to use vHost server mode, like so:
> +
> +       ````
> +       -chardev socket,id=char0,path=/usr/local/var/run/openvswitch/vhost0,server
> +       ````
> +
> +       One benefit of using this mode is the ability for vHost ports to
> +       'reconnect' in event of the switch crashing or being brought down. Once
> +       it is brought back up, the vHost ports will reconnect automatically and
> +       normal service will resume.
> +
>    - VM Configuration with libvirt
>  
>      * change the user/group, access control policty and restart libvirtd.
> diff --git a/NEWS b/NEWS
> index f50b05e..08bac37 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -53,6 +53,7 @@ Post-v2.5.0
>       * PMD threads servicing vHost User ports can now come from the NUMA
>         node that device memory is located on if CONFIG_RTE_LIBRTE_VHOST_NUMA
>         is enabled in DPDK.
> +     * OVS client mode for vHost and vHost reconnect (Requires QEMU 2.7)
>     - ovs-benchmark: This utility has been removed due to lack of use and
>       bitrot.
>     - ovs-appctl:
> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
> index 9cf0b0c..6763039 100644
> --- a/lib/netdev-dpdk.c
> +++ b/lib/netdev-dpdk.c
> @@ -138,9 +138,11 @@ BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
>                                            * yet mapped to another queue. */
>  
>  #ifdef VHOST_CUSE
> -static char *cuse_dev_name = NULL;    /* Character device cuse_dev_name. */
> +static char *cuse_dev_name = NULL;      /* Character device cuse_dev_name. */
> +#else
> +static char *vhost_sock_dir = NULL;     /* Location of vhost-user sockets */
> +static uint64_t vhost_driver_flags = 0; /* Denote whether client/server mode */
>  #endif
> -static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
>  
>  #define VHOST_ENQ_RETRY_NUM 8
>  
> @@ -845,7 +847,6 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev)
>      struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
>      const char *name = netdev->name;
>      int err;
> -    uint64_t flags = 0;
>  
>      /* 'name' is appended to 'vhost_sock_dir' and used to create a socket in
>       * the file system. '/' or '\' would traverse directories, so they're not
> @@ -868,14 +869,17 @@ netdev_dpdk_vhost_user_construct(struct netdev *netdev)
>      snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s",
>               vhost_sock_dir, name);
>  
> -    err = rte_vhost_driver_register(dev->vhost_id, flags);
> +    err = rte_vhost_driver_register(dev->vhost_id, vhost_driver_flags);
>      if (err) {
>          VLOG_ERR("vhost-user socket device setup failure for socket %s\n",
>                   dev->vhost_id);
>      } else {
> -        fatal_signal_add_file_to_unlink(dev->vhost_id);
> -        VLOG_INFO("Socket %s created for vhost-user port %s\n",
> -                  dev->vhost_id, name);
> +        if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
> +            /* OVS server mode - OVS may delete the socket */
> +            fatal_signal_add_file_to_unlink(dev->vhost_id);
> +            VLOG_INFO("Socket %s created for vhost-user port %s\n",
> +                      dev->vhost_id, name);
> +        }
>          err = vhost_construct_helper(netdev);
>      }
>  
> @@ -945,7 +949,8 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev)
>  
>      if (rte_vhost_driver_unregister(dev->vhost_id)) {
>          VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id);
> -    } else {
> +    } else if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
> +        /* OVS server mode - OVS may delete the socket */
>          fatal_signal_remove_file_to_unlink(dev->vhost_id);
>      }
>  
> @@ -3208,6 +3213,7 @@ dpdk_init__(const struct smap *ovs_other_config)
>      cpu_set_t cpuset;
>  #ifndef VHOST_CUSE
>      char *sock_dir_subcomponent;
> +    const char *val;
>  #endif
>  
>      if (!smap_get_bool(ovs_other_config, "dpdk-init", false)) {
> @@ -3218,8 +3224,8 @@ dpdk_init__(const struct smap *ovs_other_config)
>      VLOG_INFO("DPDK Enabled, initializing");
>  
>  #ifdef VHOST_CUSE
> -    if (process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
> -                            PATH_MAX, ovs_other_config, &cuse_dev_name)) {
> +    process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
> +                        PATH_MAX, ovs_other_config, &cuse_dev_name);
>  #else
>      if (process_vhost_flags("vhost-sock-dir", xstrdup(ovs_rundir()),
>                              NAME_MAX, ovs_other_config,
> @@ -3243,8 +3249,17 @@ dpdk_init__(const struct smap *ovs_other_config)
>          free(sock_dir_subcomponent);
>      } else {
>          vhost_sock_dir = sock_dir_subcomponent;
> -#endif
>      }
> +    val = smap_get(ovs_other_config, "vhost_driver_mode");
> +    if (val != NULL && strncmp(val, "client", strlen(val)) == 0) {
> +        vhost_driver_flags |= RTE_VHOST_USER_CLIENT;
> +        VLOG_INFO("OVS client mode (QEMU server mode) selected for vHost");
> +    } else  {
> +        /* default case */
> +        vhost_driver_flags &= ~RTE_VHOST_USER_CLIENT;
> +        VLOG_INFO("OVS server mode (QEMU client mode) selected for vHost");
> +    }

Is it possible to just use the process_vhost_flags call for this section
instead?  Do you think it would make sense for consistency?

> +#endif
>  
>      argv = grow_argv(&argv, 0, 1);
>      argc = 1;
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index fed6f56..66007e5 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -311,6 +311,19 @@
>          </p>
>        </column>
>  
> +      <column name="other_config" key="vhost_driver_mode"
> +              type='{"type": "string", "enum": ["set", ["server", "client"]]}'>
> +        <p>
> +          Specifies which mode OVS will use for vHost. In 'server' mode, OVS
> +          creates and destroys the vHost User sockets. In 'client' mode, OVS
> +          attaches to sockets created by QEMU.
> +        </p>
> +        <p>
> +          Defaults to 'server' mode. Changing this value requires restarting
> +          the daemon.
> +        </p>
> +      </column>
> +
>        <column name="other_config" key="n-handler-threads"
>                type='{"type": "integer", "minInteger": 1}'>
>          <p>
Ciara Loftus July 13, 2016, 8:29 a.m. UTC | #2
> Ciara Loftus <ciara.loftus@intel.com> writes:
> 
> > A new other_config DB option has been added called 'vhost_driver_mode'.
> > By default this is set to 'server' which is the mode of operation OVS
> > with DPDK has used up until this point - whereby OVS creates and manages
> > vHost user sockets.
> >
> > If set to 'client', OVS will act as the vHost client and connect to
> > sockets created and managed by QEMU which acts as the server. This
> mode
> > allows for reconnect capability, which allows vHost ports to resume
> > normal connectivity in event of switch reset.
> >
> > QEMU v2.7.0+ is required when using OVS in client mode and QEMU in
> > server mode.
> >
> > Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
> > ---
> >  INSTALL.DPDK-ADVANCED.md | 27 +++++++++++++++++++++++++++
> >  NEWS                     |  1 +
> >  lib/netdev-dpdk.c        | 37 ++++++++++++++++++++++++++-----------
> >  vswitchd/vswitch.xml     | 13 +++++++++++++
> >  4 files changed, 67 insertions(+), 11 deletions(-)
> >
> > diff --git a/INSTALL.DPDK-ADVANCED.md b/INSTALL.DPDK-ADVANCED.md
> > index ec1de29..ad3e59e 100644
> > --- a/INSTALL.DPDK-ADVANCED.md
> > +++ b/INSTALL.DPDK-ADVANCED.md
> > @@ -489,6 +489,33 @@ DPDK 16.07 supports two types of vhost:
> >         where `-L`: Changes the numbers of channels of the specified network
> device
> >         and `combined`: Changes the number of multi-purpose channels.
> >
> > +    4. Enable OVS vHost client-mode & vHost reconnect (OPTIONAL)
> > +
> > +       By default, OVS DPDK acts as the vHost socket server and QEMU the
> > +       client. In QEMU v2.7 the option is available for QEMU to act as the
> > +       server. In order for this to work, OVS DPDK must be switched to 'client'
> > +       mode. This is possible by setting the 'vhost_driver_mode' DB entry to
> > +       'client' like so:
> > +
> > +       ```
> > +       ovs-vsctl set Open_vSwitch .
> other_config:vhost_driver_mode="client"
> > +       ```
> > +
> > +       This must be done before the switch is launched. It cannot sucessfully
> > +       be changed after switch has launched.
> > +
> > +       One must also append ',server' to the 'chardev' arguments on the
> QEMU
> > +       command line, to instruct QEMU to use vHost server mode, like so:
> > +
> > +       ````
> > +       -chardev
> socket,id=char0,path=/usr/local/var/run/openvswitch/vhost0,server
> > +       ````
> > +
> > +       One benefit of using this mode is the ability for vHost ports to
> > +       'reconnect' in event of the switch crashing or being brought down.
> Once
> > +       it is brought back up, the vHost ports will reconnect automatically and
> > +       normal service will resume.
> > +
> >    - VM Configuration with libvirt
> >
> >      * change the user/group, access control policty and restart libvirtd.
> > diff --git a/NEWS b/NEWS
> > index f50b05e..08bac37 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -53,6 +53,7 @@ Post-v2.5.0
> >       * PMD threads servicing vHost User ports can now come from the
> NUMA
> >         node that device memory is located on if
> CONFIG_RTE_LIBRTE_VHOST_NUMA
> >         is enabled in DPDK.
> > +     * OVS client mode for vHost and vHost reconnect (Requires QEMU 2.7)
> >     - ovs-benchmark: This utility has been removed due to lack of use and
> >       bitrot.
> >     - ovs-appctl:
> > diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
> > index 9cf0b0c..6763039 100644
> > --- a/lib/netdev-dpdk.c
> > +++ b/lib/netdev-dpdk.c
> > @@ -138,9 +138,11 @@ BUILD_ASSERT_DECL((MAX_NB_MBUF /
> ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
> >                                            * yet mapped to another queue. */
> >
> >  #ifdef VHOST_CUSE
> > -static char *cuse_dev_name = NULL;    /* Character device
> cuse_dev_name. */
> > +static char *cuse_dev_name = NULL;      /* Character device
> cuse_dev_name. */
> > +#else
> > +static char *vhost_sock_dir = NULL;     /* Location of vhost-user sockets */
> > +static uint64_t vhost_driver_flags = 0; /* Denote whether client/server
> mode */
> >  #endif
> > -static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
> >
> >  #define VHOST_ENQ_RETRY_NUM 8
> >
> > @@ -845,7 +847,6 @@ netdev_dpdk_vhost_user_construct(struct netdev
> *netdev)
> >      struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> >      const char *name = netdev->name;
> >      int err;
> > -    uint64_t flags = 0;
> >
> >      /* 'name' is appended to 'vhost_sock_dir' and used to create a socket in
> >       * the file system. '/' or '\' would traverse directories, so they're not
> > @@ -868,14 +869,17 @@ netdev_dpdk_vhost_user_construct(struct
> netdev *netdev)
> >      snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s",
> >               vhost_sock_dir, name);
> >
> > -    err = rte_vhost_driver_register(dev->vhost_id, flags);
> > +    err = rte_vhost_driver_register(dev->vhost_id, vhost_driver_flags);
> >      if (err) {
> >          VLOG_ERR("vhost-user socket device setup failure for socket %s\n",
> >                   dev->vhost_id);
> >      } else {
> > -        fatal_signal_add_file_to_unlink(dev->vhost_id);
> > -        VLOG_INFO("Socket %s created for vhost-user port %s\n",
> > -                  dev->vhost_id, name);
> > +        if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
> > +            /* OVS server mode - OVS may delete the socket */
> > +            fatal_signal_add_file_to_unlink(dev->vhost_id);
> > +            VLOG_INFO("Socket %s created for vhost-user port %s\n",
> > +                      dev->vhost_id, name);
> > +        }
> >          err = vhost_construct_helper(netdev);
> >      }
> >
> > @@ -945,7 +949,8 @@ netdev_dpdk_vhost_destruct(struct netdev
> *netdev)
> >
> >      if (rte_vhost_driver_unregister(dev->vhost_id)) {
> >          VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id);
> > -    } else {
> > +    } else if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
> > +        /* OVS server mode - OVS may delete the socket */
> >          fatal_signal_remove_file_to_unlink(dev->vhost_id);
> >      }
> >
> > @@ -3208,6 +3213,7 @@ dpdk_init__(const struct smap
> *ovs_other_config)
> >      cpu_set_t cpuset;
> >  #ifndef VHOST_CUSE
> >      char *sock_dir_subcomponent;
> > +    const char *val;
> >  #endif
> >
> >      if (!smap_get_bool(ovs_other_config, "dpdk-init", false)) {
> > @@ -3218,8 +3224,8 @@ dpdk_init__(const struct smap
> *ovs_other_config)
> >      VLOG_INFO("DPDK Enabled, initializing");
> >
> >  #ifdef VHOST_CUSE
> > -    if (process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
> > -                            PATH_MAX, ovs_other_config, &cuse_dev_name)) {
> > +    process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
> > +                        PATH_MAX, ovs_other_config, &cuse_dev_name);
> >  #else
> >      if (process_vhost_flags("vhost-sock-dir", xstrdup(ovs_rundir()),
> >                              NAME_MAX, ovs_other_config,
> > @@ -3243,8 +3249,17 @@ dpdk_init__(const struct smap
> *ovs_other_config)
> >          free(sock_dir_subcomponent);
> >      } else {
> >          vhost_sock_dir = sock_dir_subcomponent;
> > -#endif
> >      }
> > +    val = smap_get(ovs_other_config, "vhost_driver_mode");
> > +    if (val != NULL && strncmp(val, "client", strlen(val)) == 0) {
> > +        vhost_driver_flags |= RTE_VHOST_USER_CLIENT;
> > +        VLOG_INFO("OVS client mode (QEMU server mode) selected for
> vHost");
> > +    } else  {
> > +        /* default case */
> > +        vhost_driver_flags &= ~RTE_VHOST_USER_CLIENT;
> > +        VLOG_INFO("OVS server mode (QEMU client mode) selected for
> vHost");
> > +    }
> 
> Is it possible to just use the process_vhost_flags call for this section
> instead?  Do you think it would make sense for consistency?

Good suggestion - I'll try make this change in the next version.

Thanks,
Ciara

> 
> > +#endif
> >
> >      argv = grow_argv(&argv, 0, 1);
> >      argc = 1;
> > diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> > index fed6f56..66007e5 100644
> > --- a/vswitchd/vswitch.xml
> > +++ b/vswitchd/vswitch.xml
> > @@ -311,6 +311,19 @@
> >          </p>
> >        </column>
> >
> > +      <column name="other_config" key="vhost_driver_mode"
> > +              type='{"type": "string", "enum": ["set", ["server", "client"]]}'>
> > +        <p>
> > +          Specifies which mode OVS will use for vHost. In 'server' mode, OVS
> > +          creates and destroys the vHost User sockets. In 'client' mode, OVS
> > +          attaches to sockets created by QEMU.
> > +        </p>
> > +        <p>
> > +          Defaults to 'server' mode. Changing this value requires restarting
> > +          the daemon.
> > +        </p>
> > +      </column>
> > +
> >        <column name="other_config" key="n-handler-threads"
> >                type='{"type": "integer", "minInteger": 1}'>
> >          <p>
diff mbox

Patch

diff --git a/INSTALL.DPDK-ADVANCED.md b/INSTALL.DPDK-ADVANCED.md
index ec1de29..ad3e59e 100644
--- a/INSTALL.DPDK-ADVANCED.md
+++ b/INSTALL.DPDK-ADVANCED.md
@@ -489,6 +489,33 @@  DPDK 16.07 supports two types of vhost:
        where `-L`: Changes the numbers of channels of the specified network device
        and `combined`: Changes the number of multi-purpose channels.
 
+    4. Enable OVS vHost client-mode & vHost reconnect (OPTIONAL)
+
+       By default, OVS DPDK acts as the vHost socket server and QEMU the
+       client. In QEMU v2.7 the option is available for QEMU to act as the
+       server. In order for this to work, OVS DPDK must be switched to 'client'
+       mode. This is possible by setting the 'vhost_driver_mode' DB entry to
+       'client' like so:
+
+       ```
+       ovs-vsctl set Open_vSwitch . other_config:vhost_driver_mode="client"
+       ```
+
+       This must be done before the switch is launched. It cannot sucessfully
+       be changed after switch has launched.
+
+       One must also append ',server' to the 'chardev' arguments on the QEMU
+       command line, to instruct QEMU to use vHost server mode, like so:
+
+       ````
+       -chardev socket,id=char0,path=/usr/local/var/run/openvswitch/vhost0,server
+       ````
+
+       One benefit of using this mode is the ability for vHost ports to
+       'reconnect' in event of the switch crashing or being brought down. Once
+       it is brought back up, the vHost ports will reconnect automatically and
+       normal service will resume.
+
   - VM Configuration with libvirt
 
     * change the user/group, access control policty and restart libvirtd.
diff --git a/NEWS b/NEWS
index f50b05e..08bac37 100644
--- a/NEWS
+++ b/NEWS
@@ -53,6 +53,7 @@  Post-v2.5.0
      * PMD threads servicing vHost User ports can now come from the NUMA
        node that device memory is located on if CONFIG_RTE_LIBRTE_VHOST_NUMA
        is enabled in DPDK.
+     * OVS client mode for vHost and vHost reconnect (Requires QEMU 2.7)
    - ovs-benchmark: This utility has been removed due to lack of use and
      bitrot.
    - ovs-appctl:
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 9cf0b0c..6763039 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -138,9 +138,11 @@  BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
                                           * yet mapped to another queue. */
 
 #ifdef VHOST_CUSE
-static char *cuse_dev_name = NULL;    /* Character device cuse_dev_name. */
+static char *cuse_dev_name = NULL;      /* Character device cuse_dev_name. */
+#else
+static char *vhost_sock_dir = NULL;     /* Location of vhost-user sockets */
+static uint64_t vhost_driver_flags = 0; /* Denote whether client/server mode */
 #endif
-static char *vhost_sock_dir = NULL;   /* Location of vhost-user sockets */
 
 #define VHOST_ENQ_RETRY_NUM 8
 
@@ -845,7 +847,6 @@  netdev_dpdk_vhost_user_construct(struct netdev *netdev)
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     const char *name = netdev->name;
     int err;
-    uint64_t flags = 0;
 
     /* 'name' is appended to 'vhost_sock_dir' and used to create a socket in
      * the file system. '/' or '\' would traverse directories, so they're not
@@ -868,14 +869,17 @@  netdev_dpdk_vhost_user_construct(struct netdev *netdev)
     snprintf(dev->vhost_id, sizeof(dev->vhost_id), "%s/%s",
              vhost_sock_dir, name);
 
-    err = rte_vhost_driver_register(dev->vhost_id, flags);
+    err = rte_vhost_driver_register(dev->vhost_id, vhost_driver_flags);
     if (err) {
         VLOG_ERR("vhost-user socket device setup failure for socket %s\n",
                  dev->vhost_id);
     } else {
-        fatal_signal_add_file_to_unlink(dev->vhost_id);
-        VLOG_INFO("Socket %s created for vhost-user port %s\n",
-                  dev->vhost_id, name);
+        if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
+            /* OVS server mode - OVS may delete the socket */
+            fatal_signal_add_file_to_unlink(dev->vhost_id);
+            VLOG_INFO("Socket %s created for vhost-user port %s\n",
+                      dev->vhost_id, name);
+        }
         err = vhost_construct_helper(netdev);
     }
 
@@ -945,7 +949,8 @@  netdev_dpdk_vhost_destruct(struct netdev *netdev)
 
     if (rte_vhost_driver_unregister(dev->vhost_id)) {
         VLOG_ERR("Unable to remove vhost-user socket %s", dev->vhost_id);
-    } else {
+    } else if (!(vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
+        /* OVS server mode - OVS may delete the socket */
         fatal_signal_remove_file_to_unlink(dev->vhost_id);
     }
 
@@ -3208,6 +3213,7 @@  dpdk_init__(const struct smap *ovs_other_config)
     cpu_set_t cpuset;
 #ifndef VHOST_CUSE
     char *sock_dir_subcomponent;
+    const char *val;
 #endif
 
     if (!smap_get_bool(ovs_other_config, "dpdk-init", false)) {
@@ -3218,8 +3224,8 @@  dpdk_init__(const struct smap *ovs_other_config)
     VLOG_INFO("DPDK Enabled, initializing");
 
 #ifdef VHOST_CUSE
-    if (process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
-                            PATH_MAX, ovs_other_config, &cuse_dev_name)) {
+    process_vhost_flags("cuse-dev-name", xstrdup("vhost-net"),
+                        PATH_MAX, ovs_other_config, &cuse_dev_name);
 #else
     if (process_vhost_flags("vhost-sock-dir", xstrdup(ovs_rundir()),
                             NAME_MAX, ovs_other_config,
@@ -3243,8 +3249,17 @@  dpdk_init__(const struct smap *ovs_other_config)
         free(sock_dir_subcomponent);
     } else {
         vhost_sock_dir = sock_dir_subcomponent;
-#endif
     }
+    val = smap_get(ovs_other_config, "vhost_driver_mode");
+    if (val != NULL && strncmp(val, "client", strlen(val)) == 0) {
+        vhost_driver_flags |= RTE_VHOST_USER_CLIENT;
+        VLOG_INFO("OVS client mode (QEMU server mode) selected for vHost");
+    } else  {
+        /* default case */
+        vhost_driver_flags &= ~RTE_VHOST_USER_CLIENT;
+        VLOG_INFO("OVS server mode (QEMU client mode) selected for vHost");
+    }
+#endif
 
     argv = grow_argv(&argv, 0, 1);
     argc = 1;
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index fed6f56..66007e5 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -311,6 +311,19 @@ 
         </p>
       </column>
 
+      <column name="other_config" key="vhost_driver_mode"
+              type='{"type": "string", "enum": ["set", ["server", "client"]]}'>
+        <p>
+          Specifies which mode OVS will use for vHost. In 'server' mode, OVS
+          creates and destroys the vHost User sockets. In 'client' mode, OVS
+          attaches to sockets created by QEMU.
+        </p>
+        <p>
+          Defaults to 'server' mode. Changing this value requires restarting
+          the daemon.
+        </p>
+      </column>
+
       <column name="other_config" key="n-handler-threads"
               type='{"type": "integer", "minInteger": 1}'>
         <p>