diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py index d5679e7d565..70d14f4f334 100644 --- a/neutron/agent/ovn/metadata/agent.py +++ b/neutron/agent/ovn/metadata/agent.py @@ -43,7 +43,7 @@ CHASSIS_METADATA_LOCK = 'chassis_metadata_lock' NS_PREFIX = 'ovnmeta-' MAC_PATTERN = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) -OVN_VIF_PORT_TYPES = ("", "external", ) +OVN_VIF_PORT_TYPES = ("", "external", ovn_const.LSP_TYPE_LOCALPORT, ) MetadataPortInfo = collections.namedtuple('MetadataPortInfo', ['mac', 'ip_addresses']) @@ -82,6 +82,20 @@ class PortBindingChassisEvent(row_event.RowEvent): resync = False if row.type not in OVN_VIF_PORT_TYPES: return + if row.type == ovn_const.LSP_TYPE_LOCALPORT: + new_ext_ids = row.external_ids + old_ext_ids = old.external_ids + device_id = row.external_ids.get( + ovn_const.OVN_DEVID_EXT_ID_KEY, "") + if not device_id.startswith(NS_PREFIX): + return + new_cidrs = new_ext_ids.get(ovn_const.OVN_CIDRS_EXT_ID_KEY, "") + old_cidrs = old_ext_ids.get(ovn_const.OVN_CIDRS_EXT_ID_KEY, "") + # If old_cidrs is "", it is create event, + # nothing needs to be done. + # If old_cidrs equals new_cidrs, the ip does not change. + if old_cidrs in ("", new_cidrs, ): + return with _SYNC_STATE_LOCK.read_lock(): try: net_name = ovn_utils.get_network_name_from_datapath( @@ -96,6 +110,24 @@ class PortBindingChassisEvent(row_event.RowEvent): self.agent.resync() +class PortBindingMetaPortUpdatedEvent(PortBindingChassisEvent): + LOG_MSG = "Metadata Port %s in datapath %s updated." + + def __init__(self, metadata_agent): + events = (self.ROW_UPDATE,) + super(PortBindingMetaPortUpdatedEvent, self).__init__( + metadata_agent, events) + + def match_fn(self, event, row, old): + if row.type == ovn_const.LSP_TYPE_LOCALPORT: + if hasattr(row, 'external_ids') and hasattr(old, 'external_ids'): + device_id = row.external_ids.get( + ovn_const.OVN_DEVID_EXT_ID_KEY, "") + if device_id.startswith(NS_PREFIX): + return True + return False + + class PortBindingChassisCreatedEvent(PortBindingChassisEvent): LOG_MSG = "Port %s in datapath %s bound to our chassis" @@ -245,7 +277,8 @@ class MetadataAgent(object): 'Chassis') events = (PortBindingChassisCreatedEvent(self), PortBindingChassisDeletedEvent(self), - SbGlobalUpdateEvent(self)) + SbGlobalUpdateEvent(self), + PortBindingMetaPortUpdatedEvent(self)) # TODO(lucasagomes): Remove this in the future. Try to register # the Chassis_Private table, if not present, fallback to the normal diff --git a/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py b/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py index 80ecaa7b040..abf485db872 100644 --- a/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py +++ b/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py @@ -141,7 +141,19 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): type=ovn_const.LSP_TYPE_LOCALPORT, addresses='AA:AA:AA:AA:AA:AA 192.168.122.123', external_ids={ - ovn_const.OVN_CIDRS_EXT_ID_KEY: '192.168.122.123/24'})) + ovn_const.OVN_CIDRS_EXT_ID_KEY: '192.168.122.123/24', + ovn_const.OVN_DEVID_EXT_ID_KEY: 'ovnmeta-' + lswitch_name + })) + return mdt_port_name + + def _update_metadata_port_ip(self, metadata_port_name): + external_ids = { + ovn_const.OVN_CIDRS_EXT_ID_KEY: "192.168.122.2/24", + ovn_const.OVN_DEVID_EXT_ID_KEY: + 'ovnmeta-' + uuidutils.generate_uuid() + } + self.nb_api.set_lswitch_port(lport_name=metadata_port_name, + external_ids=external_ids).execute() def _create_logical_switch_port(self, type_=None): lswitch_name = 'ovn-' + uuidutils.generate_uuid() @@ -192,16 +204,25 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): n_utils.wait_until_true(check_mock_pbinding, timeout=10, exception=exc) - def _test_agent_events(self, delete, type_=None): + def _test_agent_events(self, delete, type_=None, update=False): m_pb_created = mock.patch.object( agent.PortBindingChassisCreatedEvent, 'run').start() m_pb_deleted = mock.patch.object( agent.PortBindingChassisDeletedEvent, 'run').start() + m_pb_updated = mock.patch.object( + agent.PortBindingMetaPortUpdatedEvent, 'run').start() lswitchport_name, lswitch_name = self._create_logical_switch_port( type_) self.sb_api.lsp_bind(lswitchport_name, self.chassis_name).execute( check_error=True, log_errors=True) + if update and type_ == ovn_const.LSP_TYPE_LOCALPORT: + with self.nb_api.transaction( + check_error=True, log_errors=True) as txn: + mdt_port_name = self._create_metadata_port(txn, lswitch_name) + self.sb_api.lsp_bind(mdt_port_name, self.chassis_name).execute( + check_error=True, log_errors=True) + self._update_metadata_port_ip(mdt_port_name) def pb_created(): if m_pb_created.call_count < 1: @@ -219,6 +240,31 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): "PortBindingChassisCreatedEvent didn't happen on port " "binding.")) + def pb_updated(): + if m_pb_updated.call_count < 1: + return False + args = m_pb_updated.call_args[0] + self.assertEqual('update', args[0]) + self.assertTrue(args[1].external_ids) + self.assertTrue(args[2].external_ids) + device_id = args[1].external_ids.get( + ovn_const.OVN_DEVID_EXT_ID_KEY, "") + self.assertTrue(device_id.startswith("ovnmeta-")) + new_cidrs = args[1].external_ids.get( + ovn_const.OVN_CIDRS_EXT_ID_KEY, "") + old_cidrs = args[2].external_ids.get( + ovn_const.OVN_CIDRS_EXT_ID_KEY, "") + self.assertNotEqual(new_cidrs, old_cidrs) + self.assertNotEqual(old_cidrs, "") + return True + if update and type_ == ovn_const.LSP_TYPE_LOCALPORT: + n_utils.wait_until_true( + pb_updated, + timeout=10, + exception=Exception( + "PortBindingMetaPortUpdatedEvent didn't happen on " + "metadata port ip address updated.")) + if delete: self.nb_api.delete_lswitch_port( lswitchport_name, lswitch_name).execute( @@ -290,6 +336,10 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): timeout=10, exception=exc) + def test_agent_metadata_port_ip_update_event(self): + self._test_agent_events( + delete=False, type_=ovn_const.LSP_TYPE_LOCALPORT, update=True) + def test_metadata_agent_only_monitors_own_chassis(self): # We already have the fake chassis which we should be monitoring, so # create an event looking for a change to another chassis diff --git a/releasenotes/notes/bug-1996677-64851b476a0c5a37.yaml b/releasenotes/notes/bug-1996677-64851b476a0c5a37.yaml new file mode 100644 index 00000000000..0743a617881 --- /dev/null +++ b/releasenotes/notes/bug-1996677-64851b476a0c5a37.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + `1996677 <https://bugs.launchpad.net/neutron/+bug/1996677>`_ + When the fixed_ips of metadata port is modified, the ip address of + tap device in metadata agent is modified.