Update tap ip in metadata agent when metadata port ip updated

Update neutron-ovn-metadata-agent, catch port_binding update event
of monitoring localport type, and judge if the neutron:cidrs field in
the external_ids of port_binding table has changed,
then update_datapath.

Closes-Bug: #1996677
Change-Id: Ibdc1b385b07a2ab1ca8e4b6278f6d39fb5839509
This commit is contained in:
hailun.huang 2022-11-16 09:35:22 +00:00
parent a358bb802b
commit 686698284b
3 changed files with 93 additions and 4 deletions

View File

@ -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

View File

@ -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

View File

@ -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.