From f2e8a619c5ce7a4b4713f40c6da68da1a3e4410c Mon Sep 17 00:00:00 2001 From: "hailun.huang" Date: Mon, 20 Dec 2021 17:47:26 +0800 Subject: [PATCH] Delete MAC binding for LRP when the port is deleted If router_A connect subnet by ip and there are packets through it when always_learn_from_arp_request is set to False(patch[1]), the mac_binding table of ovn south db will learn mac address of . If disconnect the subnet, the mac of still exits in mac_binding table. When reconnecting subnet by the same ip as , the mac_binding can not update the mac of to the latest mac address. This will cause packets that need pass can not normal arrival destination address. Fix it by clearing mac address of the in mac_binding tables when disconnects the subnet. [1]https://review.opendev.org/c/openstack/neutron/+/814421 Closes-Bug: #1954771 Change-Id: I57d531eafb08dbebee7f1c4c98ba98ce7e4c4b4a --- .../ovn/mech_driver/ovsdb/ovn_client.py | 27 +++++++++++++++++++ .../tests/unit/services/ovn_l3/test_plugin.py | 8 ++++++ 2 files changed, 35 insertions(+) diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py index 6f7dee24e85..fa6d64fbce1 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_client.py @@ -32,10 +32,12 @@ from neutron_lib.plugins import directory from neutron_lib.plugins import utils as p_utils from neutron_lib.utils import helpers from neutron_lib.utils import net as n_net +from oslo_concurrency import processutils from oslo_config import cfg from oslo_log import log from oslo_utils import excutils from ovsdbapp.backend.ovs_idl import idlutils +import tenacity from neutron.common.ovn import acl as ovn_acl from neutron.common.ovn import constants as ovn_const @@ -1561,6 +1563,26 @@ class OVNClient(object): db_rev.bump_revision( context, port, ovn_const.TYPE_ROUTER_PORTS) + @tenacity.retry(wait=tenacity.wait_random(min=2, max=3), + stop=tenacity.stop_after_attempt(3)) + def delete_mac_binding_entries_by_mac(self, mac): + """Delete all MAC_Binding entries associated to this mac address + + The reason for using ovsdb-client intead of sb_ovn.db_destroy + is refer to patch: + https://review.opendev.org/c/openstack/neutron/+/812805 + """ + cmd = ['ovsdb-client', 'transact', ovn_conf.get_ovn_sb_connection(), + '--timeout', str(ovn_conf.get_ovn_ovsdb_timeout())] + if ovn_conf.get_ovn_sb_private_key(): + cmd += ['-p', ovn_conf.get_ovn_sb_private_key(), '-c', + ovn_conf.get_ovn_sb_certificate(), '-C', + ovn_conf.get_ovn_sb_ca_cert()] + cmd += ['["OVN_Southbound", {"op": "delete", "table": "MAC_Binding", ' + '"where": [["mac", "==", "%s"]]}]' % mac] + return processutils.execute(*cmd, + log_errors=processutils.LOG_FINAL_ERROR) + def _delete_lrouter_port(self, context, port_id, router_id=None, txn=None): """Delete a logical router port.""" commands = [self._nb_idl.lrp_del( @@ -1580,6 +1602,7 @@ class OVNClient(object): subnet_ids = subnet_ids or [] port_removed = False + port_mac = ovn_port.mac with self._nb_idl.transaction(check_error=True) as txn: port = None try: @@ -1610,6 +1633,8 @@ class OVNClient(object): if port_removed: self._delete_lrouter_port(context, port_id, router_id, txn=txn) + if port_mac: + self.delete_mac_binding_entries_by_mac(port_mac) return if not subnet_ids: @@ -1644,6 +1669,8 @@ class OVNClient(object): # revision database to ensure consistency if port_removed: self._delete_lrouter_port(context, port_id, router_id, txn=txn) + if port_mac: + self.delete_mac_binding_entries_by_mac(port_mac) else: # otherwise, we just update the revision database db_rev.bump_revision( diff --git a/neutron/tests/unit/services/ovn_l3/test_plugin.py b/neutron/tests/unit/services/ovn_l3/test_plugin.py index 0e7a115a07c..7e9b6ab8383 100644 --- a/neutron/tests/unit/services/ovn_l3/test_plugin.py +++ b/neutron/tests/unit/services/ovn_l3/test_plugin.py @@ -293,6 +293,10 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): '.OVNClient._is_lb_member_fip', return_value=False) self.mock_is_lb_member_fip.start() + self._start_mock( + 'neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.ovn_client.' + 'OVNClient.delete_mac_binding_entries_by_mac', + return_value=1) def test__plugin_driver(self): # No valid mech drivers should raise an exception. @@ -1712,6 +1716,10 @@ class OVNL3ExtrarouteTests(test_l3_gw.ExtGwModeIntTestCase, self._start_mock( 'neutron.common.ovn.utils.get_revision_number', return_value=1) + self._start_mock( + 'neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.ovn_client.' + 'OVNClient.delete_mac_binding_entries_by_mac', + return_value=1) self.setup_notification_driver() # Note(dongj): According to bug #1657693, status of an unassociated