Skip to content

Commit 9813eac

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "libvirt: Delegate OVS plug to os-vif" into stable/wallaby
2 parents c9fc9ba + 23a4b27 commit 9813eac

File tree

16 files changed

+419
-132
lines changed

16 files changed

+419
-132
lines changed

nova/compute/manager.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7997,11 +7997,12 @@ def check_can_live_migrate_destination(self, ctxt, instance,
79977997
'but source is either too old, or is set to an '
79987998
'older upgrade level.', instance=instance)
79997999
if self.network_api.supports_port_binding_extension(ctxt):
8000-
# Create migrate_data vifs
8001-
migrate_data.vifs = \
8002-
migrate_data_obj.\
8003-
VIFMigrateData.create_skeleton_migrate_vifs(
8004-
instance.get_network_info())
8000+
# Create migrate_data vifs if not provided by driver.
8001+
if 'vifs' not in migrate_data:
8002+
migrate_data.vifs = (
8003+
migrate_data_obj.
8004+
VIFMigrateData.create_skeleton_migrate_vifs(
8005+
instance.get_network_info()))
80058006
# Claim PCI devices for VIFs on destination (if needed)
80068007
port_id_to_pci = self._claim_pci_for_instance_vifs(
80078008
ctxt, instance)

nova/network/model.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ def __init__(self, id=None, address=None, network=None, type=None,
384384
details=None, devname=None, ovs_interfaceid=None,
385385
qbh_params=None, qbg_params=None, active=False,
386386
vnic_type=VNIC_TYPE_NORMAL, profile=None,
387-
preserve_on_delete=False, **kwargs):
387+
preserve_on_delete=False, delegate_create=False,
388+
**kwargs):
388389
super(VIF, self).__init__()
389390

390391
self['id'] = id
@@ -401,14 +402,15 @@ def __init__(self, id=None, address=None, network=None, type=None,
401402
self['vnic_type'] = vnic_type
402403
self['profile'] = profile
403404
self['preserve_on_delete'] = preserve_on_delete
405+
self['delegate_create'] = delegate_create
404406

405407
self._set_meta(kwargs)
406408

407409
def __eq__(self, other):
408410
keys = ['id', 'address', 'network', 'vnic_type',
409411
'type', 'profile', 'details', 'devname',
410412
'ovs_interfaceid', 'qbh_params', 'qbg_params',
411-
'active', 'preserve_on_delete']
413+
'active', 'preserve_on_delete', 'delegate_create']
412414
return all(self[k] == other[k] for k in keys)
413415

414416
def __ne__(self, other):

nova/network/neutron.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3066,7 +3066,8 @@ def _build_vif_model(self, context, client, current_neutron_port,
30663066
ovs_interfaceid=ovs_interfaceid,
30673067
devname=devname,
30683068
active=vif_active,
3069-
preserve_on_delete=preserve_on_delete
3069+
preserve_on_delete=preserve_on_delete,
3070+
delegate_create=True,
30703071
)
30713072

30723073
def _build_network_info_model(self, context, instance, networks=None,

nova/network/os_vif_util.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from os_vif import objects
2222
from oslo_config import cfg
2323
from oslo_log import log as logging
24+
import pbr.version
2425

2526
from nova import exception
2627
from nova.i18n import _
@@ -347,6 +348,27 @@ def _nova_to_osvif_vif_ovs(vif):
347348
vif_name=vif_name,
348349
bridge_name=_get_hybrid_bridge_name(vif))
349350
else:
351+
# NOTE(stephenfin): The 'create_port' attribute was added in os-vif
352+
# 1.15.0 and isn't available with the lowest version supported here
353+
if (
354+
pbr.version.VersionInfo('os-vif').semantic_version() >=
355+
pbr.version.SemanticVersion.from_pip_string('1.15.0')
356+
):
357+
profile.create_port = vif.get('delegate_create', False)
358+
elif vif.get('delegate_create', False):
359+
# NOTE(stephenfin): This should never happen, since if the
360+
# 'delegate_create' attribute is true then it was set by the
361+
# destination compute node as part of the live migration operation:
362+
# the same destination compute node that we are currently running
363+
# on. We include it for sanity-preservation
364+
LOG.warning(
365+
'os-vif 1.15.0 or later is required to support '
366+
'delegated port creation but you have %s; consider '
367+
'updating this package to resolve bugs #1734320 and '
368+
'#1815989',
369+
pbr.version.VersionInfo('os-vif').version_string(),
370+
)
371+
350372
obj = _get_vif_instance(
351373
vif,
352374
objects.vif.VIFOpenVSwitch,

nova/objects/migrate_data.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
from nova.objects import base as obj_base
2323
from nova.objects import fields
2424

25-
2625
LOG = log.getLogger(__name__)
26+
OS_VIF_DELEGATION = 'os_vif_delegation'
2727

2828

2929
@obj_base.NovaObjectRegistry.register
@@ -60,6 +60,8 @@ class VIFMigrateData(obj_base.NovaObject):
6060

6161
@property
6262
def vif_details(self):
63+
if 'vif_details_json' not in self:
64+
return {}
6365
return jsonutils.loads(self.vif_details_json)
6466

6567
@vif_details.setter
@@ -68,12 +70,27 @@ def vif_details(self, vif_details_dict):
6870

6971
@property
7072
def profile(self):
73+
if 'profile_json' not in self:
74+
return {}
7175
return jsonutils.loads(self.profile_json)
7276

7377
@profile.setter
7478
def profile(self, profile_dict):
7579
self.profile_json = jsonutils.dumps(profile_dict)
7680

81+
@property
82+
def supports_os_vif_delegation(self):
83+
return self.profile.get(OS_VIF_DELEGATION, False)
84+
85+
# TODO(stephenfin): add a proper delegation field instead of storing this
86+
# info in the profile catch-all blob
87+
@supports_os_vif_delegation.setter
88+
def supports_os_vif_delegation(self, supported):
89+
# we can't simply set the attribute using dict notation since the
90+
# getter returns a copy of the data, not the data itself
91+
self.profile = dict(
92+
self.profile or {}, **{OS_VIF_DELEGATION: supported})
93+
7794
def get_dest_vif(self):
7895
"""Get a destination VIF representation of this object.
7996
@@ -91,6 +108,7 @@ def get_dest_vif(self):
91108
vif['vnic_type'] = self.vnic_type
92109
vif['profile'] = self.profile
93110
vif['details'] = self.vif_details
111+
vif['delegate_create'] = self.supports_os_vif_delegation
94112
return vif
95113

96114
@classmethod

nova/tests/functional/libvirt/test_pci_sriov_servers.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -577,16 +577,15 @@ def test_get_server_diagnostics_server_with_VF(self):
577577
self.start_compute(pci_info=pci_info)
578578

579579
# create the SR-IOV port
580-
self.neutron.create_port({'port': self.neutron.network_4_port_1})
580+
port = self.neutron.create_port(
581+
{'port': self.neutron.network_4_port_1})
581582

582-
# create a server using the VF and multiple networks
583-
extra_spec = {'pci_passthrough:alias': f'{self.VFS_ALIAS_NAME}:1'}
584-
flavor_id = self._create_flavor(extra_spec=extra_spec)
583+
flavor_id = self._create_flavor()
585584
server = self._create_server(
586585
flavor_id=flavor_id,
587586
networks=[
588587
{'uuid': base.LibvirtNeutronFixture.network_1['id']},
589-
{'port': base.LibvirtNeutronFixture.network_4_port_1['id']},
588+
{'port': port['port']['id']},
590589
],
591590
)
592591

@@ -600,13 +599,16 @@ def test_get_server_diagnostics_server_with_VF(self):
600599
base.LibvirtNeutronFixture.network_1_port_2['mac_address'],
601600
diagnostics['nic_details'][0]['mac_address'],
602601
)
603-
self.assertIsNotNone(diagnostics['nic_details'][0]['tx_packets'])
602+
603+
for key in ('rx_packets', 'tx_packets'):
604+
self.assertIn(key, diagnostics['nic_details'][0])
604605

605606
self.assertEqual(
606607
base.LibvirtNeutronFixture.network_4_port_1['mac_address'],
607608
diagnostics['nic_details'][1]['mac_address'],
608609
)
609-
self.assertIsNone(diagnostics['nic_details'][1]['tx_packets'])
610+
for key in ('rx_packets', 'tx_packets'):
611+
self.assertIn(key, diagnostics['nic_details'][1])
610612

611613
def test_create_server_after_change_in_nonsriov_pf_to_sriov_pf(self):
612614
# Starts a compute with PF not configured with SRIOV capabilities

nova/tests/unit/fake_network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def update_cache_fake(*args, **kwargs):
120120
qbg_params=None,
121121
active=False,
122122
vnic_type='normal',
123-
profile=None,
123+
profile={},
124124
preserve_on_delete=False,
125125
meta={'rxtx_cap': 30},
126126
)

nova/tests/unit/network/test_neutron.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3271,6 +3271,7 @@ def test_build_network_info_model(self, mock_get_client,
32713271
requested_ports[index].get(
32723272
constants.BINDING_PROFILE) or {},
32733273
nw_info.get('profile'))
3274+
self.assertTrue(nw_info.get('delegate_create'))
32743275
index += 1
32753276

32763277
self.assertFalse(nw_infos[0]['active'])

nova/tests/unit/network/test_os_vif_util.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,8 @@ def test_nova_to_osvif_vif_agilio_ovs_fallthrough(self):
458458
subnets=[]),
459459
details={
460460
model.VIF_DETAILS_PORT_FILTER: True,
461-
}
461+
},
462+
delegate_create=False,
462463
)
463464

464465
actual = os_vif_util.nova_to_osvif_vif(vif)
@@ -471,7 +472,8 @@ def test_nova_to_osvif_vif_agilio_ovs_fallthrough(self):
471472
plugin="ovs",
472473
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
473474
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
474-
datapath_type=None),
475+
datapath_type=None,
476+
create_port=False),
475477
preserve_on_delete=False,
476478
vif_name="nicdc065497-3c",
477479
network=osv_objects.network.Network(
@@ -588,6 +590,7 @@ def test_nova_to_osvif_vif_ovs_plain(self):
588590
model.VIF_DETAILS_OVS_DATAPATH_TYPE:
589591
model.VIF_DETAILS_OVS_DATAPATH_SYSTEM
590592
},
593+
delegate_create=True,
591594
)
592595

593596
actual = os_vif_util.nova_to_osvif_vif(vif)
@@ -600,7 +603,8 @@ def test_nova_to_osvif_vif_ovs_plain(self):
600603
plugin="ovs",
601604
port_profile=osv_objects.vif.VIFPortProfileOpenVSwitch(
602605
interface_id="dc065497-3c8d-4f44-8fb4-e1d33c16a536",
603-
datapath_type=model.VIF_DETAILS_OVS_DATAPATH_SYSTEM),
606+
datapath_type=model.VIF_DETAILS_OVS_DATAPATH_SYSTEM,
607+
create_port=True),
604608
preserve_on_delete=False,
605609
vif_name="nicdc065497-3c",
606610
network=osv_objects.network.Network(

nova/tests/unit/objects/test_migrate_data.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,24 @@ def test_create_skeleton_migrate_vifs(self):
316316
self.assertEqual(len(vifs), len(mig_vifs))
317317
self.assertEqual([vif['id'] for vif in vifs],
318318
[mig_vif.port_id for mig_vif in mig_vifs])
319+
320+
def test_supports_os_vif_delegation(self):
321+
# first try setting on a object without 'profile' defined
322+
migrate_vif = objects.VIFMigrateData(
323+
port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL,
324+
vif_type=network_model.VIF_TYPE_OVS, vif_details={},
325+
host='fake-dest-host')
326+
migrate_vif.supports_os_vif_delegation = True
327+
self.assertTrue(migrate_vif.supports_os_vif_delegation)
328+
self.assertEqual(migrate_vif.profile, {'os_vif_delegation': True})
329+
330+
# now do the same but with profile defined
331+
migrate_vif = objects.VIFMigrateData(
332+
port_id=uuids.port_id, vnic_type=network_model.VNIC_TYPE_NORMAL,
333+
vif_type=network_model.VIF_TYPE_OVS, vif_details={},
334+
host='fake-dest-host', profile={'interface_name': 'eth0'})
335+
migrate_vif.supports_os_vif_delegation = True
336+
self.assertTrue(migrate_vif.supports_os_vif_delegation)
337+
self.assertEqual(
338+
migrate_vif.profile,
339+
{'os_vif_delegation': True, 'interface_name': 'eth0'})

0 commit comments

Comments
 (0)