diff --git a/neutron/services/ovn_l3/plugin.py b/neutron/services/ovn_l3/plugin.py index 38cbfa7bd16..bbb970f138b 100644 --- a/neutron/services/ovn_l3/plugin.py +++ b/neutron/services/ovn_l3/plugin.py @@ -249,7 +249,18 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase, port = self._plugin.update_port( context, port['id'], {'port': {portbindings.HOST_ID: host}}) - + # Updates OVN NB database with hostname for lsp router + # gateway port + with self._nb_ovn.transaction(check_error=True) as txn: + ext_ids = ( + "external_ids", + {ovn_const.OVN_HOST_ID_EXT_ID_KEY: host}, + ) + txn.add( + self._nb_ovn.db_set( + "Logical_Switch_Port", port["id"], ext_ids + ) + ) if port['status'] != status: self._plugin.update_port_status(context, port['id'], status) diff --git a/neutron/tests/functional/services/ovn_l3/test_plugin.py b/neutron/tests/functional/services/ovn_l3/test_plugin.py index fdbc8b584fb..7f4429797ca 100644 --- a/neutron/tests/functional/services/ovn_l3/test_plugin.py +++ b/neutron/tests/functional/services/ovn_l3/test_plugin.py @@ -531,6 +531,12 @@ class TestRouter(base.TestOVNFunctionalBase): # hosted in any chassis. self.assertGreaterEqual(plugin_select.call_count, 2) + def _find_port_binding(self, port_id): + cmd = self.sb_api.db_find_rows('Port_Binding', + ('logical_port', '=', port_id)) + rows = cmd.execute(check_error=True) + return rows[0] if rows else None + def test_router_gateway_port_binding_host_id(self): # Test setting chassis on chassisredirect port in Port_Binding table, # will update host_id of corresponding router gateway port @@ -553,14 +559,30 @@ class TestRouter(base.TestOVNFunctionalBase): may_exist=True).execute(check_error=True) def check_port_binding_host_id(port_id): + # Get port from Neutron DB port = core_plugin.get_ports( self.context, filters={'id': [port_id]})[0] - return port[portbindings.HOST_ID] == host_id + # Get port from OVN DB + bp = self._find_port_binding(port_id) + ovn_host_id = bp.external_ids.get(ovn_const.OVN_HOST_ID_EXT_ID_KEY) + return port[portbindings.HOST_ID] == host_id == ovn_host_id # Test if router gateway port updated with this chassis n_utils.wait_until_true(lambda: check_port_binding_host_id( gw_port_id)) + # Simulate failover to another chassis and check host_id in Neutron DB + # and external_ids:neutron:host_id in OVN DB are updated + chassis = idlutils.row_by_value( + self.sb_api.idl, "Chassis", "name", self.chassis2 + ) + host_id = chassis.hostname + self.sb_api.lsp_unbind(logical_port).execute(check_error=True) + self.sb_api.lsp_bind(logical_port, self.chassis2).execute( + check_error=True + ) + n_utils.wait_until_true(lambda: check_port_binding_host_id(gw_port_id)) + def _validate_router_ipv6_ra_configs(self, lrp_name, expected_ra_confs): lrp = idlutils.row_by_value(self.nb_api.idl, 'Logical_Router_Port', 'name', lrp_name)