add support for vhost-user reconnect
- This change introduces support for createing dpdkvhostuserclient type port in ovs. - This change allows vhost-user to be configured with qemu as the vhost server and ovs as the client allowing the vhost frontend to reconnect to the backend in the event the backend restarts. Change-Id: Ie22e12c9578a2f5bd89a37b9e80efef7ae055b7a
This commit is contained in:
parent
345ff074b5
commit
e2fa516b91
@ -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…
x
Reference in New Issue
Block a user