From ca60a91cbd3668c469313a3bd6c0c99aeff30a74 Mon Sep 17 00:00:00 2001 From: Sean Mooney Date: Mon, 18 Jul 2016 04:19:04 +0000 Subject: [PATCH] adds support for vhost user reconnect. - vhost-user reconnect is a new feature added in dpdk 16.07 and qemu 2.7. - vhost-user reconnect allows VMs using vhost-user interfaces to reconnect to the vhost-user backend if the backend terminates either as a result of a graceful shutdown or a crash with out requiring the vm to reboot. - vhost-user reconnect requires qemu to be the vhost-user server and ovs to be the client. - dpdk prior to 16.07 only supports qemu client/ dpdk server mode. - This change extends the ovs mech driver to select the correct qemu vhost user socket mode based on the available interface types reported by the agent. Change-Id: Iec89eaa597311e086c5f6e8d67308d446b07ac33 Closes-Bug: #1604924 Depends-on: Ia5da5b3ef28d1b23b217adc5196199df47b54ed9 --- .../openvswitch/agent/common/constants.py | 1 + .../mech_driver/mech_openvswitch.py | 28 ++++++--- .../mech_driver/test_mech_openvswitch.py | 59 +++++++++++++++++++ ...vhost-user-reconnect-7650134520022e7d.yaml | 21 +++++++ 4 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/vhost-user-reconnect-7650134520022e7d.yaml diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py index 38aa8cee356..8322c0fddb0 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/common/constants.py @@ -127,6 +127,7 @@ EXTENSION_DRIVER_TYPE = 'ovs' OVS_DATAPATH_SYSTEM = 'system' OVS_DATAPATH_NETDEV = 'netdev' OVS_DPDK_VHOST_USER = 'dpdkvhostuser' +OVS_DPDK_VHOST_USER_CLIENT = 'dpdkvhostuserclient' # default ovs vhost-user socket location VHOST_USER_SOCKET_DIR = '/var/run/openvswitch' diff --git a/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py b/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py index 494cbb54bb4..f9536d60c9b 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py +++ b/neutron/plugins/ml2/drivers/openvswitch/mech_driver/mech_openvswitch.py @@ -81,12 +81,22 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase): def get_vif_type(self, agent, context): caps = agent['configurations'].get('ovs_capabilities', {}) - if (a_const.OVS_DPDK_VHOST_USER in caps.get('iface_types', []) and - agent['configurations'].get('datapath_type') == - a_const.OVS_DATAPATH_NETDEV): + if (any(x in caps.get('iface_types', []) for x + in [a_const.OVS_DPDK_VHOST_USER, + a_const.OVS_DPDK_VHOST_USER_CLIENT]) and + agent['configurations'].get('datapath_type') == + a_const.OVS_DATAPATH_NETDEV): return portbindings.VIF_TYPE_VHOST_USER return self.vif_type + def get_vhost_mode(self, iface_types): + # NOTE(sean-k-mooney): this function converts the ovs vhost user + # driver mode into the qemu vhost user mode. If OVS is the server, + # qemu is the client and vice-versa. + if (a_const.OVS_DPDK_VHOST_USER_CLIENT in iface_types): + return portbindings.VHOST_USER_MODE_SERVER + return portbindings.VHOST_USER_MODE_CLIENT + def get_vif_details(self, agent, context): vif_details = self._pre_get_vif_details(agent, context) self._set_bridge_name(context.current, vif_details) @@ -107,7 +117,8 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase): def _pre_get_vif_details(self, agent, context): a_config = agent['configurations'] - if a_config.get('datapath_type') != a_const.OVS_DATAPATH_NETDEV: + vif_type = self.get_vif_type(agent, context) + if vif_type != portbindings.VIF_TYPE_VHOST_USER: details = dict(self.vif_details) hybrid = portbindings.OVS_HYBRID_PLUG if hybrid in a_config: @@ -115,13 +126,14 @@ class OpenvswitchMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase): # in the constructor if the agent specifically requests it details[hybrid] = a_config[hybrid] return details - caps = a_config.get('ovs_capabilities', {}) - if a_const.OVS_DPDK_VHOST_USER in caps.get('iface_types', []): + else: sock_path = self.agent_vhu_sockpath(agent, context.current['id']) + caps = a_config.get('ovs_capabilities', {}) + mode = self.get_vhost_mode(caps.get('iface_types', [])) return { portbindings.CAP_PORT_FILTER: False, - portbindings.VHOST_USER_MODE: - portbindings.VHOST_USER_MODE_CLIENT, + portbindings.OVS_HYBRID_PLUG: False, + portbindings.VHOST_USER_MODE: mode, portbindings.VHOST_USER_OVS_PLUG: True, portbindings.VHOST_USER_SOCKET: sock_path } diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py index beed8eedc04..f9555f69757 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/mech_driver/test_mech_openvswitch.py @@ -177,3 +177,62 @@ class OpenvswitchMechanismFirewallUndefinedTestCase( cfg.CONF.set_override('firewall_driver', '', 'SECURITYGROUP') self.driver = mech_openvswitch.OpenvswitchMechanismDriver() self.driver.initialize() + + +class OpenvswitchMechanismDPDKTestCase(OpenvswitchMechanismBaseTestCase): + + GOOD_MAPPINGS = {'fake_physical_network': 'fake_bridge'} + + GOOD_TUNNEL_TYPES = ['gre', 'vxlan'] + + VHOST_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS, + 'tunnel_types': GOOD_TUNNEL_TYPES, + 'datapath_type': a_const.OVS_DATAPATH_NETDEV, + 'ovs_capabilities': { + 'iface_types': [a_const.OVS_DPDK_VHOST_USER]}} + + VHOST_SERVER_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS, + 'tunnel_types': GOOD_TUNNEL_TYPES, + 'datapath_type': a_const.OVS_DATAPATH_NETDEV, + 'ovs_capabilities': { + 'iface_types': [a_const.OVS_DPDK_VHOST_USER_CLIENT]}} + + SYSTEM_CONFIGS = {'bridge_mappings': GOOD_MAPPINGS, + 'tunnel_types': GOOD_TUNNEL_TYPES, + 'datapath_type': a_const.OVS_DATAPATH_SYSTEM, + 'ovs_capabilities': {'iface_types': []}} + + AGENT = {'alive': True, + 'configurations': VHOST_CONFIGS, + 'host': 'host'} + + AGENT_SERVER = {'alive': True, + 'configurations': VHOST_SERVER_CONFIGS, + 'host': 'host'} + + AGENT_SYSTEM = {'alive': True, + 'configurations': SYSTEM_CONFIGS, + 'host': 'host'} + + def test_get_vhost_mode(self): + ifaces = [] + result = self.driver.get_vhost_mode(ifaces) + self.assertEqual(portbindings.VHOST_USER_MODE_CLIENT, result) + + ifaces = [a_const.OVS_DPDK_VHOST_USER] + result = self.driver.get_vhost_mode(ifaces) + self.assertEqual(portbindings.VHOST_USER_MODE_CLIENT, result) + + ifaces = [a_const.OVS_DPDK_VHOST_USER_CLIENT] + result = self.driver.get_vhost_mode(ifaces) + self.assertEqual(portbindings.VHOST_USER_MODE_SERVER, result) + + def test_get_vif_type(self): + result = self.driver.get_vif_type(self.AGENT, None) + self.assertEqual(portbindings.VIF_TYPE_VHOST_USER, result) + + result = self.driver.get_vif_type(self.AGENT_SERVER, None) + self.assertEqual(portbindings.VIF_TYPE_VHOST_USER, result) + + result = self.driver.get_vif_type(self.AGENT_SYSTEM, None) + self.assertEqual(portbindings.VIF_TYPE_OVS, result) diff --git a/releasenotes/notes/vhost-user-reconnect-7650134520022e7d.yaml b/releasenotes/notes/vhost-user-reconnect-7650134520022e7d.yaml new file mode 100644 index 00000000000..cffc194ed45 --- /dev/null +++ b/releasenotes/notes/vhost-user-reconnect-7650134520022e7d.yaml @@ -0,0 +1,21 @@ +--- +features: + - vhost-user reconnect is a mechanism which allows + a vhost-user frontend to reconnect to a vhost-user + backend in the event the backend terminates. + This enable a VM utilising a vhost-user interface + to reconnect automatically to the backend e.g. + a vSwitch without requiring the VM to reboot. + In this release, support was added to the neutron + Open vSwitch agent and ml2 driver for vhost-user + reconnect. +other: + - vhost-user reconnect allows VMs using vhost-user + interfaces to reconnect to the vhost-user backend if + the backend terminates either as a result of a graceful + shutdown or a crash without requiring the VM to reboot. + - vhost-user reconnect requires dpdk 16.07 and qemu 2.7 + and ovs 2.6 to function. if an older qemu is used, + reconnect will not be available but vhost-user will + still function. +