[OVN][Trunk] Set the subports correct host during live migration

During the trunk migration, the parent port multiple port binding
will contain the destination host. Because this update is done
before the migration is done (in other words, the parent port
still has two port binding registers), the method setting the
binding profile of the subport will use the destination host
in advance. At the end of the live migration, the subports
host will point to the correct hostname.

Related-Bug: #2027605
Change-Id: I2370ea2f96e2e31dbd43bf232a63394388e6945f
This commit is contained in:
Rodolfo Alonso Hernandez 2023-07-18 00:42:45 +00:00
parent e1f887ca9f
commit 7ed79c1f78
2 changed files with 41 additions and 9 deletions

View File

@ -14,6 +14,7 @@ from neutron_lib.api.definitions import portbindings
from neutron_lib.callbacks import events
from neutron_lib.callbacks import registry
from neutron_lib.callbacks import resources
from neutron_lib import constants as n_const
from neutron_lib import context as n_context
from neutron_lib.db import api as db_api
from neutron_lib import exceptions as n_exc
@ -51,7 +52,11 @@ class OVNTrunkHandler(object):
context = n_context.get_admin_context()
db_parent_port = port_obj.Port.get_object(context, id=parent_port)
parent_port_status = db_parent_port.status
parent_port_bindings = db_parent_port.bindings[0]
try:
parent_port_bindings = [pb for pb in db_parent_port.bindings
if pb.status == n_const.ACTIVE][-1]
except IndexError:
parent_port_bindings = None
for subport in subports:
with db_api.CONTEXT_WRITER.using(context), (
txn(check_error=True)) as ovn_txn:
@ -85,8 +90,10 @@ class OVNTrunkHandler(object):
db_port.id, db_port, ovn_const.TYPE_PORTS)
ovn_txn.add(check_rev_cmd)
parent_binding_host = ''
if parent_port_bindings.host:
parent_binding_host = parent_port_bindings.host
if parent_port_bindings and parent_port_bindings.host:
migrating_to = parent_port_bindings.profile.get(
ovn_const.MIGRATING_ATTR)
parent_binding_host = migrating_to or parent_port_bindings.host
try:
# NOTE(flaviof): We expect binding's host to be set. Otherwise,
# sub-port will not transition from DOWN to ACTIVE.

View File

@ -97,13 +97,23 @@ class TestOVNTrunkDriver(base.TestOVNFunctionalBase):
if trunk.get('status'):
self.assertEqual(trunk_consts.TRUNK_ACTIVE_STATUS, trunk['status'])
def _bind_port(self, port_id, host):
def _bind_port(self, port_id, host_source, host_dest=None):
with db_api.CONTEXT_WRITER.using(self.context):
pb = port_obj.PortBinding.get_object(self.context,
port_id=port_id, host='')
pb.delete()
port_obj.PortBinding(self.context, port_id=port_id, host=host,
vif_type=portbindings.VIF_TYPE_OVS).create()
for pb in port_obj.PortBinding.get_objects(self.context,
port_id=port_id):
pb.delete()
profile = {}
if host_dest:
# When "host_dest" there are 2 port bindings, as in a live
# migration; the second one (destination host) is inactive.
profile[ovn_const.MIGRATING_ATTR] = host_dest
port_obj.PortBinding(
self.context, port_id=port_id, host=host_dest,
vif_type=portbindings.VIF_TYPE_OVS,
status=n_consts.INACTIVE).create()
port_obj.PortBinding(
self.context, port_id=port_id, host=host_source,
profile=profile, vif_type=portbindings.VIF_TYPE_OVS).create()
def test_trunk_create(self):
with self.trunk() as trunk:
@ -148,6 +158,21 @@ class TestOVNTrunkDriver(base.TestOVNFunctionalBase):
self._verify_trunk_info(new_trunk, has_items=True,
host='host1')
def test_subport_add_live_migration_multiple_port_binding(self):
with self.subport() as subport:
with self.trunk() as trunk:
self.trunk_plugin.add_subports(self.context, trunk['id'],
{'sub_ports': [subport]})
new_trunk = self.trunk_plugin.get_trunk(self.context,
trunk['id'])
self._verify_trunk_info(new_trunk, has_items=True)
# Bind parent port. That will trigger the binding of the
# trunk subports too, using the same host ID.
self._bind_port(trunk['port_id'], 'host1', host_dest='host2')
self.mech_driver.set_port_status_up(trunk['port_id'])
self._verify_trunk_info(new_trunk, has_items=True,
host='host2')
def test_subport_delete(self):
with self.subport() as subport:
with self.trunk([subport]) as trunk: