os-vif: convert libvirt driver to use os-vif for fast path vhostuser

Signed-off-by: Francesco Santoro <francesco.santoro@6wind.com>

Change-Id: Iedb00f171bb198c86b843d315154bac5732b0af3
Implements: blueprint libvirt-os-vif-fastpath-vhostuser
This commit is contained in:
Francesco Santoro 2016-09-21 10:43:58 +02:00 committed by Matt Riedemann
parent 32e2654152
commit 67868cf7d7
6 changed files with 235 additions and 230 deletions

View File

@ -2099,6 +2099,11 @@ class API(base_api.NetworkAPI):
bridge = port_details.get(network_model.VIF_DETAILS_BRIDGE_NAME,
CONF.neutron.ovs_bridge)
ovs_interfaceid = port['id']
elif (vif_type == network_model.VIF_TYPE_VHOSTUSER and
port_details.get(network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG,
False)):
bridge = port_details.get(network_model.VIF_DETAILS_BRIDGE_NAME,
"brq" + port['network_id'])
# Prune the bridge name if necessary. For the DVS this is not done
# as the bridge is a '<network-name>-<network-UUID>'.

View File

@ -78,6 +78,26 @@ def _is_firewall_required(vif):
return False
def _set_vhostuser_settings(vif, obj):
"""Set vhostuser socket mode and path
:param vif: the nova.network.model.VIF instance
:param obj: a os_vif.objects.vif.VIFVHostUser instance
:raises: exception.VifDetailsMissingVhostuserSockPath
"""
obj.mode = vif['details'].get(
model.VIF_DETAILS_VHOSTUSER_MODE, 'server')
path = vif['details'].get(
model.VIF_DETAILS_VHOSTUSER_SOCKET, None)
if path:
obj.path = path
else:
raise exception.VifDetailsMissingVhostuserSockPath(
vif_id=vif['id'])
def nova_to_osvif_instance(instance):
"""Convert a Nova instance object to an os-vif instance object
@ -281,7 +301,28 @@ def _nova_to_osvif_vif_ovs(vif):
# VIF_TYPE_VHOST_USER = 'vhostuser'
def _nova_to_osvif_vif_vhostuser(vif):
if vif['details'].get(model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, False):
if vif['details'].get(model.VIF_DETAILS_VHOSTUSER_FP_PLUG, False):
if vif['details'].get(model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, False):
profile = objects.vif.VIFPortProfileFPOpenVSwitch(
interface_id=vif.get('ovs_interfaceid') or vif['id'])
if _is_firewall_required(vif) or vif.is_hybrid_plug_enabled():
profile.bridge_name = _get_hybrid_bridge_name(vif)
profile.hybrid_plug = True
else:
profile.hybrid_plug = False
if vif["network"]["bridge"] is not None:
profile.bridge_name = vif["network"]["bridge"]
else:
profile = objects.vif.VIFPortProfileFPBridge()
if vif["network"]["bridge"] is not None:
profile.bridge_name = vif["network"]["bridge"]
obj = _get_vif_instance(vif, objects.vif.VIFVHostUser,
plugin="vhostuser_fp",
vif_name=_get_vif_name(vif),
port_profile=profile)
_set_vhostuser_settings(vif, obj)
return obj
elif vif['details'].get(model.VIF_DETAILS_VHOSTUSER_OVS_PLUG, False):
profile = objects.vif.VIFPortProfileOpenVSwitch(
interface_id=vif.get('ovs_interfaceid') or vif['id'])
vif_name = ('vhu' + vif['id'])[:model.NIC_NAME_LEN]
@ -290,15 +331,7 @@ def _nova_to_osvif_vif_vhostuser(vif):
vif_name=vif_name)
if vif["network"]["bridge"] is not None:
obj.bridge_name = vif["network"]["bridge"]
obj.mode = vif['details'].get(
model.VIF_DETAILS_VHOSTUSER_MODE, 'server')
path = vif['details'].get(
model.VIF_DETAILS_VHOSTUSER_SOCKET, None)
if path:
obj.path = path
else:
raise exception.VifDetailsMissingVhostuserSockPath(
vif_id=vif['id'])
_set_vhostuser_settings(vif, obj)
return obj
else:
raise NotImplementedError()

View File

@ -2815,6 +2815,32 @@ class TestNeutronv2(TestNeutronv2Base):
self.assertNotIn('should_create_bridge', net)
self.assertEqual('port-id', iid)
def test_nw_info_build_network_vhostuser_fp(self):
fake_port = {
'fixed_ips': [{'ip_address': '1.1.1.1'}],
'id': 'port-id',
'network_id': 'net-id',
'binding:vif_type': model.VIF_TYPE_VHOSTUSER,
'binding:vif_details': {
model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: False,
}
}
fake_subnets = [model.Subnet(cidr='1.0.0.0/8')]
fake_nets = [{'id': 'net-id', 'name': 'foo', 'tenant_id': 'tenant'}]
api = neutronapi.API()
neutronapi.get_client(mox.IgnoreArg()).AndReturn(self.moxed_client)
self.mox.ReplayAll()
neutronapi.get_client(uuids.fake)
net, ovs_interfaceid = api._nw_info_build_network(
fake_port, fake_nets, fake_subnets)
self.assertEqual(fake_subnets, net['subnets'])
self.assertEqual('net-id', net['id'])
self.assertEqual('foo', net['label'])
self.assertEqual('tenant', net.get_meta('tenant_id'))
self.assertEqual('brqnet-id', net['bridge'])
self.assertIsNone(ovs_interfaceid)
def _test_nw_info_build_custom_bridge(self, vif_type, extra_details=None):
fake_port = {
'fixed_ips': [{'ip_address': '1.1.1.1'}],

View File

@ -625,6 +625,165 @@ class OSVIFUtilTestCase(test.NoDBTestCase):
self.assertIsNone(os_vif_util.nova_to_osvif_vif(vif))
def test_nova_to_osvif_vhostuser_fp_ovs_hybrid(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
type=model.VIF_TYPE_VHOSTUSER,
address="22:52:25:62:e2:aa",
network=model.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
mtu="1500",
subnets=[]),
details={
model.VIF_DETAILS_VHOSTUSER_MODE: 'client',
model.VIF_DETAILS_VHOSTUSER_SOCKET: '/fake/socket',
model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True,
model.VIF_DETAILS_OVS_HYBRID_PLUG: True,
model.VIF_DETAILS_PORT_FILTER: False,
}
)
actual = os_vif_util.nova_to_osvif_vif(vif)
expect = osv_objects.vif.VIFVHostUser(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
active=False,
address="22:52:25:62:e2:aa",
plugin="vhostuser_fp",
port_profile=osv_objects.vif.VIFPortProfileFPOpenVSwitch(
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
bridge_name="qbrdc065497-3c",
hybrid_plug=True),
vif_name="nicdc065497-3c",
path='/fake/socket',
mode='client',
has_traffic_filtering=False,
preserve_on_delete=False,
network=osv_objects.network.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
bridge_interface=None,
label="Demo Net",
mtu="1500",
subnets=osv_objects.subnet.SubnetList(
objects=[])))
self.assertObjEqual(expect, actual)
def test_nova_to_osvif_vhostuser_fp_ovs_plain(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
type=model.VIF_TYPE_VHOSTUSER,
address="22:52:25:62:e2:aa",
network=model.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
mtu="1500",
bridge="br-int",
subnets=[]),
details={
model.VIF_DETAILS_VHOSTUSER_MODE: 'client',
model.VIF_DETAILS_VHOSTUSER_SOCKET: '/fake/socket',
model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True,
model.VIF_DETAILS_OVS_HYBRID_PLUG: False,
model.VIF_DETAILS_PORT_FILTER: True,
}
)
actual = os_vif_util.nova_to_osvif_vif(vif)
expect = osv_objects.vif.VIFVHostUser(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
active=False,
address="22:52:25:62:e2:aa",
plugin="vhostuser_fp",
port_profile=osv_objects.vif.VIFPortProfileFPOpenVSwitch(
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
bridge_name="br-int",
hybrid_plug=False),
vif_name="nicdc065497-3c",
path='/fake/socket',
mode='client',
has_traffic_filtering=True,
preserve_on_delete=False,
network=osv_objects.network.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
bridge_interface=None,
label="Demo Net",
mtu="1500",
bridge="br-int",
subnets=osv_objects.subnet.SubnetList(
objects=[])))
self.assertObjEqual(expect, actual)
def test_nova_to_osvif_vhostuser_fp_lb(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
type=model.VIF_TYPE_VHOSTUSER,
address="22:52:25:62:e2:aa",
network=model.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
mtu="1500",
bridge="brq12345",
subnets=[]),
details={
model.VIF_DETAILS_VHOSTUSER_MODE: 'client',
model.VIF_DETAILS_VHOSTUSER_SOCKET: '/fake/socket',
model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: False,
}
)
actual = os_vif_util.nova_to_osvif_vif(vif)
expect = osv_objects.vif.VIFVHostUser(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
active=False,
address="22:52:25:62:e2:aa",
plugin="vhostuser_fp",
port_profile=osv_objects.vif.VIFPortProfileFPBridge(
bridge_name="brq12345"),
vif_name="nicdc065497-3c",
path='/fake/socket',
mode='client',
has_traffic_filtering=False,
preserve_on_delete=False,
network=osv_objects.network.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
bridge_interface=None,
label="Demo Net",
mtu="1500",
bridge="brq12345",
subnets=osv_objects.subnet.SubnetList(
objects=[])))
self.assertObjEqual(expect, actual)
def test_nova_to_osvif_vhostuser_fp_no_socket_path(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
type=model.VIF_TYPE_VHOSTUSER,
address="22:52:25:62:e2:aa",
network=model.Network(
id="b82c1929-051e-481d-8110-4669916c7915",
label="Demo Net",
subnets=[]),
details={
model.VIF_DETAILS_VHOSTUSER_MODE: 'client',
model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: False,
model.VIF_DETAILS_PORT_FILTER: True,
}
)
self.assertRaises(exception.VifDetailsMissingVhostuserSockPath,
os_vif_util.nova_to_osvif_vif,
vif)
def test_nova_to_osvif_vif_ivs_plain(self):
vif = model.VIF(
id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",

View File

@ -302,16 +302,6 @@ class LibvirtVifTestCase(test.NoDBTestCase):
'/tmp/vif-xxx-yyy-zzz'}
)
vif_vhostuser_fp = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
network=network_bridge,
type=network_model.VIF_TYPE_VHOSTUSER,
devname='tap-xxx-yyy-zzz',
details = {network_model.VIF_DETAILS_VHOSTUSER_SOCKET:
'/tmp/usv-xxx-yyy-zzz',
network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True},
)
vif_vhostuser_ovs = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
network=network_bridge,
@ -323,33 +313,6 @@ class LibvirtVifTestCase(test.NoDBTestCase):
ovs_interfaceid='aaa-bbb-ccc', mtu=1500
)
vif_vhostuser_ovs_fp = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
network=network_bridge,
type=network_model.VIF_TYPE_VHOSTUSER,
details = {network_model.VIF_DETAILS_VHOSTUSER_MODE: 'server',
network_model.VIF_DETAILS_VHOSTUSER_SOCKET:
'/tmp/usv-xxx-yyy-zzz',
network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True,
network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True},
devname='tap-xxx-yyy-zzz',
ovs_interfaceid='aaa-bbb-ccc'
)
vif_vhostuser_ovs_fp_hybrid = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
network=network_bridge,
type=network_model.VIF_TYPE_VHOSTUSER,
details = {'ovs_hybrid_plug': True,
network_model.VIF_DETAILS_VHOSTUSER_MODE: 'server',
network_model.VIF_DETAILS_VHOSTUSER_SOCKET:
'/tmp/usv-xxx-yyy-zzz',
network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG: True,
network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG: True},
devname='tap-xxx-yyy-zzz',
ovs_interfaceid='aaa-bbb-ccc'
)
vif_vhostuser_no_path = network_model.VIF(id='vif-xxx-yyy-zzz',
address='ca:fe:de:ad:be:ef',
network=network_bridge,
@ -1405,129 +1368,6 @@ class LibvirtVifTestCase(test.NoDBTestCase):
self._assertMacEquals(node, self.vif_vhostuser_ovs)
self._assertModel(xml, network_model.VIF_MODEL_VIRTIO)
@mock.patch.object(linux_net, 'create_fp_dev')
def test_vhostuser_fp_plug(self, mock_create_fp_dev):
d = vif.LibvirtGenericVIFDriver()
d.plug(self.instance, self.vif_vhostuser_fp)
mock_create_fp_dev.assert_has_calls(
[mock.call('tap-xxx-yyy-zzz', '/tmp/usv-xxx-yyy-zzz', 'client')])
@mock.patch.object(linux_net, 'delete_fp_dev')
def test_vhostuser_fp_unplug(self, mock_delete_fp_dev):
d = vif.LibvirtGenericVIFDriver()
d.unplug(self.instance, self.vif_vhostuser_fp)
mock_delete_fp_dev.assert_has_calls([mock.call('tap-xxx-yyy-zzz')])
def test_vhostuser_ovs_fp_plug(self):
calls = {
'create_fp_dev': [mock.call('tap-xxx-yyy-zzz',
'/tmp/usv-xxx-yyy-zzz',
'client')],
'create_ovs_vif_port': [mock.call(
'br0', 'tap-xxx-yyy-zzz',
'aaa-bbb-ccc', 'ca:fe:de:ad:be:ef',
'f0000000-0000-0000-0000-000000000001',
9000)]
}
with test.nested(
mock.patch.object(linux_net, 'create_fp_dev'),
mock.patch.object(linux_net, 'create_ovs_vif_port'),
) as (create_fp_dev, create_ovs_vif_port):
d = vif.LibvirtGenericVIFDriver()
d.plug_vhostuser(self.instance, self.vif_vhostuser_ovs_fp)
create_fp_dev.assert_has_calls(calls['create_fp_dev'])
create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port'])
def test_vhostuser_ovs_fp_unplug(self):
calls = {
'delete_ovs_vif_port': [mock.call('br0', 'tap-xxx-yyy-zzz',
False)],
'delete_fp_dev': [mock.call('tap-xxx-yyy-zzz')],
}
with test.nested(
mock.patch.object(linux_net, 'delete_ovs_vif_port'),
mock.patch.object(linux_net, 'delete_fp_dev')
) as (delete_ovs_port, delete_fp_dev):
d = vif.LibvirtGenericVIFDriver()
d.unplug_vhostuser(None, self.vif_vhostuser_ovs_fp)
delete_ovs_port.assert_has_calls(calls['delete_ovs_vif_port'])
delete_fp_dev.assert_has_calls(calls['delete_fp_dev'])
def test_vhostuser_ovs_fp_hybrid_plug(self):
calls = {
'create_fp_dev': [mock.call('tap-xxx-yyy-zzz',
'/tmp/usv-xxx-yyy-zzz',
'client')],
'device_exists': [mock.call('tap-xxx-yyy-zzz'),
mock.call('qbrvif-xxx-yyy'),
mock.call('qvovif-xxx-yyy')],
'_create_veth_pair': [mock.call('qvbvif-xxx-yyy',
'qvovif-xxx-yyy', 9000)],
'execute': [mock.call('brctl', 'addbr', 'qbrvif-xxx-yyy',
run_as_root=True),
mock.call('brctl', 'setfd', 'qbrvif-xxx-yyy', 0,
run_as_root=True),
mock.call('brctl', 'stp', 'qbrvif-xxx-yyy', 'off',
run_as_root=True),
mock.call('tee', ('/sys/class/net/qbrvif-xxx-yyy'
'/bridge/multicast_snooping'),
process_input='0', run_as_root=True,
check_exit_code=[0, 1]),
mock.call('ip', 'link', 'set', 'qbrvif-xxx-yyy', 'up',
run_as_root=True),
mock.call('brctl', 'addif', 'qbrvif-xxx-yyy',
'qvbvif-xxx-yyy', run_as_root=True),
mock.call('brctl', 'addif', 'qbrvif-xxx-yyy',
'tap-xxx-yyy-zzz', run_as_root=True)],
'create_ovs_vif_port': [mock.call(
'br0', 'qvovif-xxx-yyy',
'aaa-bbb-ccc', 'ca:fe:de:ad:be:ef',
'f0000000-0000-0000-0000-000000000001',
9000)]
}
with test.nested(
mock.patch.object(linux_net, 'create_fp_dev'),
mock.patch.object(linux_net, 'device_exists',
return_value=False),
mock.patch.object(utils, 'execute'),
mock.patch.object(linux_net, '_create_veth_pair'),
mock.patch.object(linux_net, 'create_ovs_vif_port')
) as (create_fp_dev, device_exists, execute, _create_veth_pair,
create_ovs_vif_port):
d = vif.LibvirtGenericVIFDriver()
d.plug_vhostuser(self.instance, self.vif_vhostuser_ovs_fp_hybrid)
create_fp_dev.assert_has_calls(calls['create_fp_dev'])
device_exists.assert_has_calls(calls['device_exists'])
_create_veth_pair.assert_has_calls(calls['_create_veth_pair'])
execute.assert_has_calls(calls['execute'])
create_ovs_vif_port.assert_has_calls(calls['create_ovs_vif_port'])
def test_vhostuser_ovs_fp_hybrid_unplug(self):
calls = {
'device_exists': [mock.call('qbrvif-xxx-yyy')],
'execute': [mock.call('brctl', 'delif', 'qbrvif-xxx-yyy',
'qvbvif-xxx-yyy', run_as_root=True),
mock.call('ip', 'link', 'set',
'qbrvif-xxx-yyy', 'down', run_as_root=True),
mock.call('brctl', 'delbr',
'qbrvif-xxx-yyy', run_as_root=True)],
'delete_ovs_vif_port': [mock.call('br0', 'qvovif-xxx-yyy')],
'delete_fp_dev': [mock.call('tap-xxx-yyy-zzz')]
}
with test.nested(
mock.patch.object(linux_net, 'device_exists',
return_value=True),
mock.patch.object(utils, 'execute'),
mock.patch.object(linux_net, 'delete_ovs_vif_port'),
mock.patch.object(linux_net, 'delete_fp_dev')
) as (device_exists, execute, delete_ovs_vif_port, delete_fp_dev):
d = vif.LibvirtGenericVIFDriver()
d.unplug_vhostuser(None, self.vif_vhostuser_ovs_fp_hybrid)
device_exists.assert_has_calls(calls['device_exists'])
execute.assert_has_calls(calls['execute'])
delete_ovs_vif_port.assert_has_calls(calls['delete_ovs_vif_port'])
delete_fp_dev.assert_has_calls(calls['delete_fp_dev'])
@mock.patch("nova.network.os_vif_util.nova_to_osvif_instance")
@mock.patch("nova.network.os_vif_util.nova_to_osvif_vif")
@mock.patch.object(os_vif, "plug")

View File

@ -699,43 +699,8 @@ class LibvirtGenericVIFDriver(object):
mtu = network.get_meta('mtu') if network else None
linux_net._set_device_mtu(dev, mtu)
def plug_vhostuser_fp(self, instance, vif):
"""Create a fp netdevice interface with a vhostuser socket"""
dev = self.get_vif_devname(vif)
if linux_net.device_exists(dev):
return
ovs_plug = vif['details'].get(
network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG,
False)
sockmode_qemu, sockpath = self._get_vhostuser_settings(vif)
sockmode_port = 'client' if sockmode_qemu == 'server' else 'server'
try:
linux_net.create_fp_dev(dev, sockpath, sockmode_port)
if ovs_plug:
if vif.is_hybrid_plug_enabled():
self.plug_ovs_hybrid(instance, vif)
utils.execute('brctl', 'addif',
self.get_br_name(vif['id']),
dev, run_as_root=True)
else:
iface_id = self.get_ovs_interfaceid(vif)
mtu = vif['network'].get_meta('mtu')
linux_net.create_ovs_vif_port(self.get_bridge_name(vif),
dev, iface_id,
vif['address'],
instance.uuid, mtu)
except processutils.ProcessExecutionError:
LOG.exception(_LE("Failed while plugging vif"), instance=instance)
def plug_vhostuser(self, instance, vif):
fp_plug = vif['details'].get(
network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG,
False)
if fp_plug:
self.plug_vhostuser_fp(instance, vif)
pass
def plug_vrouter(self, instance, vif):
"""Plug into Contrail's network port
@ -948,31 +913,8 @@ class LibvirtGenericVIFDriver(object):
LOG.exception(_LE("Failed while unplugging vif"),
instance=instance)
def unplug_vhostuser_fp(self, instance, vif):
"""Delete a fp netdevice interface with a vhostuser socket"""
dev = self.get_vif_devname(vif)
ovs_plug = vif['details'].get(
network_model.VIF_DETAILS_VHOSTUSER_OVS_PLUG,
False)
try:
if ovs_plug:
if vif.is_hybrid_plug_enabled():
self.unplug_ovs_hybrid(instance, vif)
else:
linux_net.delete_ovs_vif_port(self.get_bridge_name(vif),
dev, False)
linux_net.delete_fp_dev(dev)
except processutils.ProcessExecutionError:
LOG.exception(_LE("Failed while unplugging vif"),
instance=instance)
def unplug_vhostuser(self, instance, vif):
fp_plug = vif['details'].get(
network_model.VIF_DETAILS_VHOSTUSER_FP_PLUG,
False)
if fp_plug:
self.unplug_vhostuser_fp(instance, vif)
pass
def unplug_vrouter(self, instance, vif):
"""Unplug Contrail's network port