diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py index af6e5cb0d5f..6d86d69a24f 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py @@ -1077,9 +1077,11 @@ class OVNMechanismDriver(api.MechanismDriver): hostname = '' # Updates neutron database with hostname for virtual port - self._plugin.update_virtual_port_host(n_context.get_admin_context(), - port_id, hostname) - + context = n_context.get_admin_context() + self._plugin.update_virtual_port_host(context, port_id, hostname) + db_port = self._plugin.get_port(context, port_id) + check_rev_cmd = self.nb_ovn.check_revision_number( + port_id, db_port, ovn_const.TYPE_PORTS) # Updates OVN NB database with hostname for lsp virtual port with self.nb_ovn.transaction(check_error=True) as txn: ext_ids = ('external_ids', @@ -1087,6 +1089,10 @@ class OVNMechanismDriver(api.MechanismDriver): txn.add( self.nb_ovn.db_set( 'Logical_Switch_Port', port_id, ext_ids)) + txn.add(check_rev_cmd) + if check_rev_cmd.result == ovn_const.TXN_COMMITTED: + ovn_revision_numbers_db.bump_revision(context, db_port, + ovn_const.TYPE_PORTS) def get_workers(self): """Get any worker instances that should have their own process diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py index fbba7d3633b..f26dd558313 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py @@ -447,6 +447,30 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): # Check that both neutron and ovn are the same as given host_id return port[portbindings.HOST_ID] == host_id == ovn_host_id + def _check_port_and_port_binding_revision_number(self, port_id): + + def is_port_and_port_binding_same_revision_number(port_id): + # This function checks if given port matches the revision_number + # in the neutron DB as well as in the OVN DB for the port_binding + core_plugin = directory.get_plugin() + + # Get port from neutron DB + port = core_plugin.get_ports( + self.context, filters={'id': [port_id]})[0] + + # Get port binding from OVN DB + bp = self._find_port_binding(port_id) + ovn_port_binding_revision_number = bp.external_ids.get( + ovn_const.OVN_REV_NUM_EXT_ID_KEY, ovn_const.INITIAL_REV_NUM) + + # Check that both neutron and ovn are the same as given host_id + return port['revision_number'] == int( + ovn_port_binding_revision_number) + + check = functools.partial( + is_port_and_port_binding_same_revision_number, port_id) + n_utils.wait_until_true(check, timeout=10) + def test_virtual_port_host_update_upon_failover(self): # NOTE: we can't simulate traffic, but we can simulate the event that # would've been triggered by OVN, which is what we do. @@ -466,6 +490,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): vip_address = vip['fixed_ips'][0]['ip_address'] allowed_address_pairs = [{'ip_address': vip_address}] self._check_port_binding_type(vip['id'], '') + self._check_port_and_port_binding_revision_number(vip['id']) # 3) Create two ports with the allowed address pairs set. hosts = ('ovs-host1', second_chassis_name) @@ -482,6 +507,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): # have been assigned to the port binding self._check_port_binding_type(vip['id'], ovn_const.LSP_TYPE_VIRTUAL) self._check_port_virtual_parents(vip['id'], ','.join(port_ids)) + self._check_port_and_port_binding_revision_number(vip['id']) # 5) Bind the ports to a host, so a chassis is bound, which is # required for the update_virtual_port_host method. Without this @@ -489,11 +515,13 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): self._test_port_binding_and_status(ports[0]['id'], 'bind', 'ACTIVE') self.chassis = second_chassis self._test_port_binding_and_status(ports[1]['id'], 'bind', 'ACTIVE') + self._check_port_and_port_binding_revision_number(vip['id']) # 6) For both ports, bind vip on parent and check hostname in DBs for idx in range(len(ports)): # Set port binding to the first port, and update the chassis self._set_port_binding_virtual_parent(vip['id'], ports[idx]['id']) + self._check_port_and_port_binding_revision_number(vip['id']) # Check if the host_id has been updated in OVN and DB # by the event that eventually calls for method @@ -501,6 +529,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): n_utils.wait_until_true( lambda: self._check_port_host_set(vip['id'], hosts[idx]), timeout=10) + self._check_port_and_port_binding_revision_number(vip['id']) class TestNBDbMonitorOverTcp(TestNBDbMonitor):