Merge "add support for vhost-user reconnect"

This commit is contained in:
Jenkins 2016-12-13 07:13:35 +00:00 committed by Gerrit Code Review
commit 56746802ee
6 changed files with 103 additions and 11 deletions

View File

@ -0,0 +1,14 @@
---
features:
- vhost-user reconnect is a new feature of qemu that
allows a vhost-user frontend(e.g. qemu) to reconnect
to a vhost-user backend (e.g. ovs with dpdk) in the event
that backend is restarted while the interface is in use.
vhost-user reconnect leverages qemu vhost-user server mode
with ovs-dpdk in client mode. This configuration requires
ovs 2.6 with dpdk 16.07 and qemu 2.7 or newer to function.
When qemu server mode is used with older qemu versions such
as 2.5, vhost-user will still function with ovs 2.6 and
dpdk 16.07, however, reconnect functionality will not be
available.

View File

@ -11,6 +11,8 @@
# under the License. # under the License.
OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser' OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser'
OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE = 'dpdkvhostuserclient'
OVS_VHOSTUSER_PREFIX = 'vhu'
OVS_DATAPATH_SYSTEM = 'system' OVS_DATAPATH_SYSTEM = 'system'
OVS_DATAPATH_NETDEV = 'netdev' OVS_DATAPATH_NETDEV = 'netdev'

View File

@ -47,7 +47,8 @@ def _ovs_vsctl(args, timeout=None):
def _create_ovs_vif_cmd(bridge, dev, iface_id, mac, def _create_ovs_vif_cmd(bridge, dev, iface_id, mac,
instance_id, interface_type=None): instance_id, interface_type=None,
vhost_server_path=None):
cmd = ['--', '--if-exists', 'del-port', dev, '--', cmd = ['--', '--if-exists', 'del-port', dev, '--',
'add-port', bridge, dev, 'add-port', bridge, dev,
'--', 'set', 'Interface', dev, '--', 'set', 'Interface', dev,
@ -57,6 +58,8 @@ def _create_ovs_vif_cmd(bridge, dev, iface_id, mac,
'external-ids:vm-uuid=%s' % instance_id] 'external-ids:vm-uuid=%s' % instance_id]
if interface_type: if interface_type:
cmd += ['type=%s' % interface_type] cmd += ['type=%s' % interface_type]
if vhost_server_path:
cmd += ['options:vhost-server-path=%s' % vhost_server_path]
return cmd return cmd
@ -67,13 +70,16 @@ def _create_ovs_bridge_cmd(bridge, datapath_type):
@privsep.vif_plug.entrypoint @privsep.vif_plug.entrypoint
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id,
mtu=None, interface_type=None, timeout=None): mtu=None, interface_type=None, timeout=None,
vhost_server_path=None):
_ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id, _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id,
mac, instance_id, mac, instance_id, interface_type,
interface_type), timeout=timeout) vhost_server_path), timeout=timeout)
# Note at present there is no support for setting the # Note at present there is no support for setting the
# mtu for vhost-user type ports. # mtu for vhost-user type ports.
if mtu and interface_type != constants.OVS_VHOSTUSER_INTERFACE_TYPE: if mtu and interface_type not in [
constants.OVS_VHOSTUSER_INTERFACE_TYPE,
constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE]:
_set_device_mtu(dev, mtu) _set_device_mtu(dev, mtu)
else: else:
LOG.debug("MTU not set on %(interface_name)s interface " LOG.debug("MTU not set on %(interface_name)s interface "

View File

@ -99,10 +99,19 @@ class OvsPlugin(plugin.PluginBase):
def _plug_vhostuser(self, vif, instance_info): def _plug_vhostuser(self, vif, instance_info):
linux_net.ensure_ovs_bridge(vif.network.bridge, linux_net.ensure_ovs_bridge(vif.network.bridge,
constants.OVS_DATAPATH_NETDEV) constants.OVS_DATAPATH_NETDEV)
vif_name = OvsPlugin.gen_port_name("vhu", vif.id) vif_name = OvsPlugin.gen_port_name(
constants.OVS_VHOSTUSER_PREFIX, vif.id)
args = {}
if vif.mode == "client":
args['interface_type'] = \
constants.OVS_VHOSTUSER_INTERFACE_TYPE
else:
args['interface_type'] = \
constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE
args['vhost_server_path'] = vif.path
self._create_vif_port( self._create_vif_port(
vif, vif_name, instance_info, vif, vif_name, instance_info, **args)
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
def _plug_bridge(self, vif, instance_info): def _plug_bridge(self, vif, instance_info):
"""Plug using hybrid strategy """Plug using hybrid strategy
@ -160,7 +169,9 @@ class OvsPlugin(plugin.PluginBase):
def _unplug_vhostuser(self, vif, instance_info): def _unplug_vhostuser(self, vif, instance_info):
linux_net.delete_ovs_vif_port(vif.network.bridge, linux_net.delete_ovs_vif_port(vif.network.bridge,
OvsPlugin.gen_port_name("vhu", vif.id), OvsPlugin.gen_port_name(
constants.OVS_VHOSTUSER_PREFIX,
vif.id),
timeout=self.config.ovs_vsctl_timeout) timeout=self.config.ovs_vsctl_timeout)
def _unplug_bridge(self, vif, instance_info): def _unplug_bridge(self, vif, instance_info):

View File

@ -131,6 +131,14 @@ class LinuxNetTest(testtools.TestCase):
'fake-type') 'fake-type')
self.assertEqual(expected, cmd) self.assertEqual(expected, cmd)
expected += ['options:vhost-server-path=/fake/path']
cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
'fake-iface-id', 'fake-mac',
'fake-instance-uuid',
'fake-type',
vhost_server_path='/fake/path')
self.assertEqual(expected, cmd)
@mock.patch.object(linux_net, '_create_ovs_bridge_cmd') @mock.patch.object(linux_net, '_create_ovs_bridge_cmd')
@mock.patch.object(linux_net, '_ovs_vsctl') @mock.patch.object(linux_net, '_ovs_vsctl')
def test_ensure_ovs_bridge(self, mock_vsctl, mock_create_ovs_bridge): def test_ensure_ovs_bridge(self, mock_vsctl, mock_create_ovs_bridge):
@ -161,7 +169,27 @@ class LinuxNetTest(testtools.TestCase):
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE) interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
mock_create_cmd.assert_called_once_with('fake-bridge', mock_create_cmd.assert_called_once_with('fake-bridge',
'fake-dev', 'fake-iface-id', 'fake-mac', 'fake-dev', 'fake-iface-id', 'fake-mac',
"fake-instance-uuid", constants.OVS_VHOSTUSER_INTERFACE_TYPE) "fake-instance-uuid", constants.OVS_VHOSTUSER_INTERFACE_TYPE,
None)
self.assertFalse(mock_set_device_mtu.called)
self.assertTrue(mock_vsctl.called)
@mock.patch.object(linux_net, '_ovs_vsctl')
@mock.patch.object(linux_net, '_create_ovs_vif_cmd')
@mock.patch.object(linux_net, '_set_device_mtu')
def test_ovs_vif_port_with_type_vhostuserclient(self,
mock_set_device_mtu, mock_create_cmd, mock_vsctl):
linux_net.create_ovs_vif_port(
'fake-bridge',
'fake-dev', 'fake-iface-id', 'fake-mac',
"fake-instance-uuid", mtu=1500,
interface_type=constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE,
vhost_server_path="/fake/path")
mock_create_cmd.assert_called_once_with('fake-bridge',
'fake-dev', 'fake-iface-id', 'fake-mac',
"fake-instance-uuid",
constants.OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE,
"/fake/path")
self.assertFalse(mock_set_device_mtu.called) self.assertFalse(mock_set_device_mtu.called)
self.assertTrue(mock_vsctl.called) self.assertTrue(mock_vsctl.called)
@ -176,7 +204,7 @@ class LinuxNetTest(testtools.TestCase):
"fake-instance-uuid") "fake-instance-uuid")
mock_create_cmd.assert_called_once_with('fake-bridge', mock_create_cmd.assert_called_once_with('fake-bridge',
'fake-dev', 'fake-iface-id', 'fake-mac', 'fake-dev', 'fake-iface-id', 'fake-mac',
"fake-instance-uuid", None) "fake-instance-uuid", None, None)
self.assertFalse(mock_set_device_mtu.called) self.assertFalse(mock_set_device_mtu.called)
self.assertTrue(mock_vsctl.called) self.assertTrue(mock_vsctl.called)

View File

@ -80,6 +80,14 @@ class PluginTest(testtools.TestCase):
mode='client', mode='client',
port_profile=self.profile_ovs) port_profile=self.profile_ovs)
self.vif_vhostuser_client = objects.vif.VIFVHostUser(
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
address='ca:fe:de:ad:be:ef',
network=self.network_ovs,
path='/var/run/openvswitch/vhub679325f-ca',
mode='server', # qemu server mode <=> ovs client mode
port_profile=self.profile_ovs)
self.instance = objects.instance_info.InstanceInfo( self.instance = objects.instance_info.InstanceInfo(
name='demo', name='demo',
uuid='f0000000-0000-0000-0000-000000000001') uuid='f0000000-0000-0000-0000-000000000001')
@ -242,6 +250,29 @@ class PluginTest(testtools.TestCase):
_create_vif_port.assert_has_calls(calls['_create_vif_port']) _create_vif_port.assert_has_calls(calls['_create_vif_port'])
ensure_ovs_bridge.assert_has_calls(calls['ensure_ovs_bridge']) ensure_ovs_bridge.assert_has_calls(calls['ensure_ovs_bridge'])
@mock.patch.object(linux_net, 'ensure_ovs_bridge')
@mock.patch.object(linux_net, 'create_ovs_vif_port')
def test_plug_ovs_vhostuser_client(self, create_ovs_vif_port,
ensure_ovs_bridge):
calls = {
'create_ovs_vif_port': [
mock.call(
'br0', 'vhub679325f-ca',
'e65867e0-9340-4a7f-a256-09af6eb7a3aa',
'ca:fe:de:ad:be:ef',
'f0000000-0000-0000-0000-000000000001',
1500, interface_type='dpdkvhostuserclient',
vhost_server_path='/var/run/openvswitch/vhub679325f-ca',
timeout=120)],
'ensure_ovs_bridge': [mock.call('br0',
constants.OVS_DATAPATH_NETDEV)]
}
plugin = ovs.OvsPlugin.load("ovs")
plugin.plug(self.vif_vhostuser_client, self.instance)
create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port'])
ensure_ovs_bridge.assert_has_calls(calls['ensure_ovs_bridge'])
@mock.patch.object(linux_net, 'delete_ovs_vif_port') @mock.patch.object(linux_net, 'delete_ovs_vif_port')
def test_unplug_ovs_vhostuser(self, delete_ovs_vif_port): def test_unplug_ovs_vhostuser(self, delete_ovs_vif_port):
calls = { calls = {