Ensure subports status is aligned with parent port

Subports of a trunk should have the same status as the parent port.
However, with ovn, if the parent port is in DOWN status, the subports
are transitioned to ACTIVE as soon as they are attached to the trunk.

This patch ensure the status set on the subports when being attached
matches the one on the parent port.

Closes-Bug: #1957161
Change-Id: I26c43c2909b635e8b21306ea1880da3877477a17
This commit is contained in:
Luis Tomas Bolivar 2022-01-12 11:45:53 +01:00
parent 5e036a6b28
commit 15d6cfffc9
2 changed files with 13 additions and 6 deletions

View File

@ -14,7 +14,6 @@ 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_consts
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
@ -46,10 +45,13 @@ class OVNTrunkHandler(object):
def _set_sub_ports(self, parent_port, subports):
txn = self.plugin_driver.nb_ovn.transaction
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
for port in subports:
with db_api.CONTEXT_WRITER.using(context), (
txn(check_error=True)) as ovn_txn:
self._set_binding_profile(context, port, parent_port, ovn_txn)
self._set_binding_profile(context, port, parent_port,
parent_port_status, ovn_txn)
def _unset_sub_ports(self, subports):
txn = self.plugin_driver.nb_ovn.transaction
@ -59,7 +61,8 @@ class OVNTrunkHandler(object):
txn(check_error=True)) as ovn_txn:
self._unset_binding_profile(context, port, ovn_txn)
def _set_binding_profile(self, context, subport, parent_port, ovn_txn):
def _set_binding_profile(self, context, subport, parent_port,
parent_port_status, ovn_txn):
LOG.debug("Setting parent %s for subport %s",
parent_port, subport.port_id)
db_port = port_obj.Port.get_object(context, id=subport.port_id)
@ -74,8 +77,8 @@ class OVNTrunkHandler(object):
db_port.device_owner = trunk_consts.TRUNK_SUBPORT_OWNER
# NOTE(ksambor): When sub-port was created and event was process
# without binding profile this port will end forever in DOWN
# status so we need to switch it here
db_port.status = n_consts.PORT_STATUS_ACTIVE
# status so we need to switch it here to the parent port status
db_port.status = parent_port_status
for binding in db_port.bindings:
binding.profile['parent_name'] = parent_port
binding.profile['tag'] = subport.segmentation_id

View File

@ -41,6 +41,8 @@ class TestTrunkHandler(base.BaseTestCase):
self.handler = trunk_driver.OVNTrunkHandler(self.plugin_driver)
self.trunk_1 = mock.Mock()
self.trunk_1.port_id = "trunk-1"
self.trunk_1_obj = self._get_fake_port_obj(
port_id='trunk-1')
self.trunk_2 = mock.Mock()
self.trunk_2.port_id = "trunk-2"
@ -77,7 +79,8 @@ class TestTrunkHandler(base.BaseTestCase):
"neutron.objects.ports.Port.get_object").start()
self.mock_get_port.side_effect = lambda ctxt, id: (
self.sub_port_1_obj if id == 'sub_port_1' else (
self.sub_port_2_obj if id == 'sub_port_2' else None))
self.sub_port_2_obj if id == 'sub_port_2' else
self.trunk_1_obj if id == 'trunk-1' else None))
self.mock_port_update = mock.patch(
"neutron.objects.ports.Port.update").start()
self.mock_update_pb = mock.patch(
@ -91,6 +94,7 @@ class TestTrunkHandler(base.BaseTestCase):
port = Port()
port.id = port_id
port.bindings = [PortBinding(profile={}, host='foo.com')]
port.status = 'ACTIVE'
return port
def _assert_calls(self, mock, expected_calls):