Merge "add support for vhost-user reconnect"
This commit is contained in:
commit
56746802ee
@ -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.
|
||||
|
@ -11,6 +11,8 @@
|
||||
# under the License.
|
||||
|
||||
OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser'
|
||||
OVS_VHOSTUSER_CLIENT_INTERFACE_TYPE = 'dpdkvhostuserclient'
|
||||
OVS_VHOSTUSER_PREFIX = 'vhu'
|
||||
|
||||
OVS_DATAPATH_SYSTEM = 'system'
|
||||
OVS_DATAPATH_NETDEV = 'netdev'
|
||||
|
@ -47,7 +47,8 @@ def _ovs_vsctl(args, timeout=None):
|
||||
|
||||
|
||||
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, '--',
|
||||
'add-port', bridge, 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]
|
||||
if interface_type:
|
||||
cmd += ['type=%s' % interface_type]
|
||||
if vhost_server_path:
|
||||
cmd += ['options:vhost-server-path=%s' % vhost_server_path]
|
||||
return cmd
|
||||
|
||||
|
||||
@ -67,13 +70,16 @@ def _create_ovs_bridge_cmd(bridge, datapath_type):
|
||||
|
||||
@privsep.vif_plug.entrypoint
|
||||
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,
|
||||
mac, instance_id,
|
||||
interface_type), timeout=timeout)
|
||||
mac, instance_id, interface_type,
|
||||
vhost_server_path), timeout=timeout)
|
||||
# Note at present there is no support for setting the
|
||||
# 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)
|
||||
else:
|
||||
LOG.debug("MTU not set on %(interface_name)s interface "
|
||||
|
@ -99,10 +99,19 @@ class OvsPlugin(plugin.PluginBase):
|
||||
def _plug_vhostuser(self, vif, instance_info):
|
||||
linux_net.ensure_ovs_bridge(vif.network.bridge,
|
||||
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(
|
||||
vif, vif_name, instance_info,
|
||||
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
||||
vif, vif_name, instance_info, **args)
|
||||
|
||||
def _plug_bridge(self, vif, instance_info):
|
||||
"""Plug using hybrid strategy
|
||||
@ -160,7 +169,9 @@ class OvsPlugin(plugin.PluginBase):
|
||||
|
||||
def _unplug_vhostuser(self, vif, instance_info):
|
||||
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)
|
||||
|
||||
def _unplug_bridge(self, vif, instance_info):
|
||||
|
@ -131,6 +131,14 @@ class LinuxNetTest(testtools.TestCase):
|
||||
'fake-type')
|
||||
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, '_ovs_vsctl')
|
||||
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)
|
||||
mock_create_cmd.assert_called_once_with('fake-bridge',
|
||||
'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.assertTrue(mock_vsctl.called)
|
||||
|
||||
@ -176,7 +204,7 @@ class LinuxNetTest(testtools.TestCase):
|
||||
"fake-instance-uuid")
|
||||
mock_create_cmd.assert_called_once_with('fake-bridge',
|
||||
'fake-dev', 'fake-iface-id', 'fake-mac',
|
||||
"fake-instance-uuid", None)
|
||||
"fake-instance-uuid", None, None)
|
||||
self.assertFalse(mock_set_device_mtu.called)
|
||||
self.assertTrue(mock_vsctl.called)
|
||||
|
||||
|
@ -80,6 +80,14 @@ class PluginTest(testtools.TestCase):
|
||||
mode='client',
|
||||
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(
|
||||
name='demo',
|
||||
uuid='f0000000-0000-0000-0000-000000000001')
|
||||
@ -242,6 +250,29 @@ class PluginTest(testtools.TestCase):
|
||||
_create_vif_port.assert_has_calls(calls['_create_vif_port'])
|
||||
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')
|
||||
def test_unplug_ovs_vhostuser(self, delete_ovs_vif_port):
|
||||
calls = {
|
||||
|
Loading…
Reference in New Issue
Block a user