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.
|
# 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'
|
||||||
|
@ -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 "
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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 = {
|
||||||
|
Loading…
Reference in New Issue
Block a user