Add support for vhost-user
- This change extends the ovs plugin to add support for vhost-user. - Following this change the ovs plugin will accpet VIFVHostUser os-vif vif objects as part of plug and unplug function calls. - This change will be consumed by the reference openvswitch ml2 driver, networking-odl and networking-ovn to enable vhost-user with openvswitch. Change-Id: Ifa53e5e821093459ab7a390ff8af26028b2a9056
This commit is contained in:
parent
ad13b337be
commit
8c58816f46
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- The ovs plugin has been extended to support
|
||||
vhost-user interfaces. vhost-user is a userspace
|
||||
protocol for high speed virtual networking introduced
|
||||
in qemu 2.1 and first supported in ovs 2.4 with dpdk 2.0
|
13
vif_plug_ovs/constants.py
Normal file
13
vif_plug_ovs/constants.py
Normal file
@ -0,0 +1,13 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
OVS_VHOSTUSER_INTERFACE_TYPE = 'dpdkvhostuser'
|
@ -25,6 +25,7 @@ from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from vif_plug_ovs import constants
|
||||
from vif_plug_ovs import exception
|
||||
from vif_plug_ovs.i18n import _LE
|
||||
from vif_plug_ovs import privsep
|
||||
@ -45,18 +46,35 @@ def _ovs_vsctl(args, timeout=None):
|
||||
raise exception.AgentError(method=full_args)
|
||||
|
||||
|
||||
def _create_ovs_vif_cmd(bridge, dev, iface_id, mac,
|
||||
instance_id, interface_type=None):
|
||||
cmd = ['--', '--if-exists', 'del-port', dev, '--',
|
||||
'add-port', bridge, dev,
|
||||
'--', 'set', 'Interface', dev,
|
||||
'external-ids:iface-id=%s' % iface_id,
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=%s' % mac,
|
||||
'external-ids:vm-uuid=%s' % instance_id]
|
||||
if interface_type:
|
||||
cmd += ['type=%s' % interface_type]
|
||||
return cmd
|
||||
|
||||
|
||||
@privsep.vif_plug.entrypoint
|
||||
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id, mtu,
|
||||
timeout=None):
|
||||
_ovs_vsctl(['--', '--if-exists', 'del-port', dev, '--',
|
||||
'add-port', bridge, dev,
|
||||
'--', 'set', 'Interface', dev,
|
||||
'external-ids:iface-id=%s' % iface_id,
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=%s' % mac,
|
||||
'external-ids:vm-uuid=%s' % instance_id],
|
||||
timeout=timeout)
|
||||
_set_device_mtu(dev, mtu)
|
||||
def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id,
|
||||
mtu=None, interface_type=None):
|
||||
_ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id,
|
||||
mac, instance_id,
|
||||
interface_type))
|
||||
# Note at present there is no support for setting the
|
||||
# mtu for vhost-user type ports.
|
||||
if interface_type != constants.OVS_VHOSTUSER_INTERFACE_TYPE:
|
||||
_set_device_mtu(dev, mtu)
|
||||
else:
|
||||
LOG.debug("MTU not set on %(interface_name)s interface "
|
||||
"of type %(interface_type)s.",
|
||||
{'interface_name': dev,
|
||||
'interface_type': interface_type})
|
||||
|
||||
|
||||
@privsep.vif_plug.entrypoint
|
||||
|
@ -21,6 +21,7 @@ from os_vif import objects
|
||||
from os_vif import plugin
|
||||
from oslo_config import cfg
|
||||
|
||||
from vif_plug_ovs import constants
|
||||
from vif_plug_ovs import exception
|
||||
from vif_plug_ovs import linux_net
|
||||
|
||||
@ -52,11 +53,14 @@ class OvsPlugin(plugin.PluginBase):
|
||||
deprecated_group="DEFAULT"),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def gen_port_name(prefix, id):
|
||||
return ("%s%s" % (prefix, id))[:OvsPlugin.NIC_NAME_LEN]
|
||||
|
||||
@staticmethod
|
||||
def get_veth_pair_names(vif):
|
||||
iface_id = vif.id
|
||||
return (("qvb%s" % iface_id)[:OvsPlugin.NIC_NAME_LEN],
|
||||
("qvo%s" % iface_id)[:OvsPlugin.NIC_NAME_LEN])
|
||||
return (OvsPlugin.gen_port_name("qvb", vif.id),
|
||||
OvsPlugin.gen_port_name("qvo", vif.id))
|
||||
|
||||
def describe(self):
|
||||
return objects.host_info.HostPluginInfo(
|
||||
@ -69,9 +73,23 @@ class OvsPlugin(plugin.PluginBase):
|
||||
objects.host_info.HostVIFInfo(
|
||||
vif_object_name=objects.vif.VIFOpenVSwitch.__name__,
|
||||
min_version="1.0",
|
||||
max_version="1.0"),
|
||||
objects.host_info.HostVIFInfo(
|
||||
vif_object_name=objects.vif.VIFVHostUser.__name__,
|
||||
min_version="1.0",
|
||||
max_version="1.0")
|
||||
])
|
||||
|
||||
def _plug_vhostuser(self, vif, instance_info):
|
||||
linux_net.create_ovs_vif_port(
|
||||
vif.network.bridge,
|
||||
OvsPlugin.gen_port_name("vhu", vif.id),
|
||||
vif.port_profile.interface_id,
|
||||
vif.address, instance_info.uuid,
|
||||
self.config.network_device_mtu,
|
||||
timeout=self.config.ovs_vsctl_timeout,
|
||||
interface_type=constants.OVS_VHOSTUSER_INTERFACE_TYPE)
|
||||
|
||||
def _plug_bridge(self, vif, instance_info):
|
||||
"""Plug using hybrid strategy
|
||||
|
||||
@ -107,6 +125,13 @@ class OvsPlugin(plugin.PluginBase):
|
||||
|
||||
if isinstance(vif, objects.vif.VIFBridge):
|
||||
self._plug_bridge(vif, instance_info)
|
||||
elif isinstance(vif, objects.vif.VIFVHostUser):
|
||||
self._plug_vhostuser(vif, instance_info)
|
||||
|
||||
def _unplug_vhostuser(self, vif, instance_info):
|
||||
linux_net.delete_ovs_vif_port(vif.network.bridge,
|
||||
OvsPlugin.gen_port_name("vhu", vif.id),
|
||||
timeout=self.config.ovs_vsctl_timeout)
|
||||
|
||||
def _unplug_bridge(self, vif, instance_info):
|
||||
"""UnPlug using hybrid strategy
|
||||
@ -132,3 +157,5 @@ class OvsPlugin(plugin.PluginBase):
|
||||
|
||||
if isinstance(vif, objects.vif.VIFBridge):
|
||||
self._unplug_bridge(vif, instance_info)
|
||||
elif isinstance(vif, objects.vif.VIFVHostUser):
|
||||
self._unplug_vhostuser(vif, instance_info)
|
||||
|
@ -18,10 +18,10 @@ import testtools
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from vif_plug_ovs import constants
|
||||
from vif_plug_ovs import linux_net
|
||||
from vif_plug_ovs import privsep
|
||||
|
||||
|
||||
if six.PY2:
|
||||
nested = contextlib.nested
|
||||
else:
|
||||
@ -118,3 +118,41 @@ class LinuxNetTest(testtools.TestCase):
|
||||
mock.call('ip', 'link', 'set', 'br0', 'up'),
|
||||
mock.call('brctl', 'addif', 'br0', 'vnet1'),
|
||||
])
|
||||
|
||||
def test_ovs_vif_port_cmd(self):
|
||||
expected = ['--', '--if-exists',
|
||||
'del-port', 'fake-dev', '--', 'add-port',
|
||||
'fake-bridge', 'fake-dev',
|
||||
'--', 'set', 'Interface', 'fake-dev',
|
||||
'external-ids:iface-id=fake-iface-id',
|
||||
'external-ids:iface-status=active',
|
||||
'external-ids:attached-mac=fake-mac',
|
||||
'external-ids:vm-uuid=fake-instance-uuid']
|
||||
cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
|
||||
'fake-iface-id', 'fake-mac',
|
||||
'fake-instance-uuid')
|
||||
|
||||
self.assertEqual(expected, cmd)
|
||||
|
||||
expected += ['type=fake-type']
|
||||
cmd = linux_net._create_ovs_vif_cmd('fake-bridge', 'fake-dev',
|
||||
'fake-iface-id', 'fake-mac',
|
||||
'fake-instance-uuid',
|
||||
'fake-type')
|
||||
self.assertEqual(expected, cmd)
|
||||
|
||||
@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_vhostuser(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_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)
|
||||
self.assertFalse(mock_set_device_mtu.called)
|
||||
self.assertTrue(mock_vsctl.called)
|
||||
|
@ -59,6 +59,7 @@ class PluginTest(testtools.TestCase):
|
||||
|
||||
self.profile_ovs = objects.vif.VIFPortProfileOpenVSwitch(
|
||||
interface_id='e65867e0-9340-4a7f-a256-09af6eb7a3aa')
|
||||
|
||||
self.vif_ovs = objects.vif.VIFBridge(
|
||||
id='b679325f-ca89-4ee0-a8be-6db1409b69ea',
|
||||
address='ca:fe:de:ad:be:ef',
|
||||
@ -67,6 +68,14 @@ class PluginTest(testtools.TestCase):
|
||||
bridge_name="qbrvif-xxx-yyy",
|
||||
port_profile=self.profile_ovs)
|
||||
|
||||
self.vif_vhostuser = 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='client',
|
||||
port_profile=self.profile_ovs)
|
||||
|
||||
self.instance = objects.instance_info.InstanceInfo(
|
||||
name='demo',
|
||||
uuid='f0000000-0000-0000-0000-000000000001')
|
||||
@ -120,3 +129,32 @@ class PluginTest(testtools.TestCase):
|
||||
plugin.unplug(self.vif_ovs, self.instance)
|
||||
delete_bridge.assert_has_calls(calls['delete_bridge'])
|
||||
delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port'])
|
||||
|
||||
def test_plug_ovs_vhostuser(self):
|
||||
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='dpdkvhostuser',
|
||||
timeout=120)]
|
||||
}
|
||||
|
||||
with mock.patch.object(linux_net, 'create_ovs_vif_port') \
|
||||
as (create_ovs_vif_port):
|
||||
plugin = ovs.OvsPlugin.load("ovs")
|
||||
plugin.plug(self.vif_vhostuser, self.instance)
|
||||
create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port'])
|
||||
|
||||
def test_unplug_ovs_vhostuser(self):
|
||||
calls = {
|
||||
'delete_ovs_vif_port': [mock.call('br0', 'vhub679325f-ca',
|
||||
timeout=120)]
|
||||
}
|
||||
with mock.patch.object(linux_net, 'delete_ovs_vif_port') \
|
||||
as delete_ovs_vif_port:
|
||||
plugin = ovs.OvsPlugin.load("ovs")
|
||||
plugin.unplug(self.vif_vhostuser, self.instance)
|
||||
delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port'])
|
||||
|
Loading…
Reference in New Issue
Block a user