Skip to content

Commit 1ce5ef7

Browse files
committed
[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 (cherry picked from commit 7ed79c1)
1 parent 6a9990d commit 1ce5ef7

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

neutron/services/trunk/drivers/ovn/trunk_driver.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from neutron_lib.callbacks import events
1515
from neutron_lib.callbacks import registry
1616
from neutron_lib.callbacks import resources
17+
from neutron_lib import constants as n_const
1718
from neutron_lib import context as n_context
1819
from neutron_lib.db import api as db_api
1920
from neutron_lib import exceptions as n_exc
@@ -51,7 +52,11 @@ def _set_sub_ports(self, parent_port, subports):
5152
context = n_context.get_admin_context()
5253
db_parent_port = port_obj.Port.get_object(context, id=parent_port)
5354
parent_port_status = db_parent_port.status
54-
parent_port_bindings = db_parent_port.bindings[0]
55+
try:
56+
parent_port_bindings = [pb for pb in db_parent_port.bindings
57+
if pb.status == n_const.ACTIVE][-1]
58+
except IndexError:
59+
parent_port_bindings = None
5560
for subport in subports:
5661
with db_api.CONTEXT_WRITER.using(context), (
5762
txn(check_error=True)) as ovn_txn:
@@ -85,8 +90,10 @@ def _set_binding_profile(self, context, subport, parent_port,
8590
db_port.id, db_port, ovn_const.TYPE_PORTS)
8691
ovn_txn.add(check_rev_cmd)
8792
parent_binding_host = ''
88-
if parent_port_bindings.host:
89-
parent_binding_host = parent_port_bindings.host
93+
if parent_port_bindings and parent_port_bindings.host:
94+
migrating_to = parent_port_bindings.profile.get(
95+
ovn_const.MIGRATING_ATTR)
96+
parent_binding_host = migrating_to or parent_port_bindings.host
9097
try:
9198
# NOTE(flaviof): We expect binding's host to be set. Otherwise,
9299
# sub-port will not transition from DOWN to ACTIVE.

neutron/tests/functional/services/trunk/drivers/ovn/test_trunk_driver.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,23 @@ def _verify_trunk_info(self, trunk, has_items, host=''):
9797
if trunk.get('status'):
9898
self.assertEqual(trunk_consts.TRUNK_ACTIVE_STATUS, trunk['status'])
9999

100-
def _bind_port(self, port_id, host):
100+
def _bind_port(self, port_id, host_source, host_dest=None):
101101
with db_api.CONTEXT_WRITER.using(self.context):
102-
pb = port_obj.PortBinding.get_object(self.context,
103-
port_id=port_id, host='')
104-
pb.delete()
105-
port_obj.PortBinding(self.context, port_id=port_id, host=host,
106-
vif_type=portbindings.VIF_TYPE_OVS).create()
102+
for pb in port_obj.PortBinding.get_objects(self.context,
103+
port_id=port_id):
104+
pb.delete()
105+
profile = {}
106+
if host_dest:
107+
# When "host_dest" there are 2 port bindings, as in a live
108+
# migration; the second one (destination host) is inactive.
109+
profile[ovn_const.MIGRATING_ATTR] = host_dest
110+
port_obj.PortBinding(
111+
self.context, port_id=port_id, host=host_dest,
112+
vif_type=portbindings.VIF_TYPE_OVS,
113+
status=n_consts.INACTIVE).create()
114+
port_obj.PortBinding(
115+
self.context, port_id=port_id, host=host_source,
116+
profile=profile, vif_type=portbindings.VIF_TYPE_OVS).create()
107117

108118
def test_trunk_create(self):
109119
with self.trunk() as trunk:
@@ -148,6 +158,21 @@ def test_subport_add(self):
148158
self._verify_trunk_info(new_trunk, has_items=True,
149159
host='host1')
150160

161+
def test_subport_add_live_migration_multiple_port_binding(self):
162+
with self.subport() as subport:
163+
with self.trunk() as trunk:
164+
self.trunk_plugin.add_subports(self.context, trunk['id'],
165+
{'sub_ports': [subport]})
166+
new_trunk = self.trunk_plugin.get_trunk(self.context,
167+
trunk['id'])
168+
self._verify_trunk_info(new_trunk, has_items=True)
169+
# Bind parent port. That will trigger the binding of the
170+
# trunk subports too, using the same host ID.
171+
self._bind_port(trunk['port_id'], 'host1', host_dest='host2')
172+
self.mech_driver.set_port_status_up(trunk['port_id'])
173+
self._verify_trunk_info(new_trunk, has_items=True,
174+
host='host2')
175+
151176
def test_subport_delete(self):
152177
with self.subport() as subport:
153178
with self.trunk([subport]) as trunk:

0 commit comments

Comments
 (0)