diff -Nru neutron-16.4.2/debian/changelog neutron-16.4.2/debian/changelog --- neutron-16.4.2/debian/changelog 2023-08-21 19:29:46.000000000 +0000 +++ neutron-16.4.2/debian/changelog 2023-11-08 16:41:21.000000000 +0000 @@ -1,3 +1,25 @@ +neutron (2:16.4.2-0ubuntu6.4) focal; urgency=medium + + [ Corey Bryant ] + * d/p/ovn-db-sync-continue-on-duplicate-normalise.patch: Cherry-picked + from upstream to allow ovn_db_sync to continue on duplicate normalised + CIDR (LP: #1961112). + * d/p/ovn-db-sync-check-for-router-port-differences.patch: + Cherry-picked from upstream to ensure router ports are marked + for needing updates only if they have changed (LP: #2030773). + * d/p/ovn-specify-port-type-if-router-port-when-updating.patch: + Specify port type if it's a router port when updating to avoid + port flapping (LP: #1955578). + * d/p/fix-acl-sync-when-default-sg-group-created.patch: + Cherry-picked form upstream to fix ACL sync when default security + group is created (LP: #2008943). + + [ Mustafa Kemal GILOR ] + * d/p/add_uplink_status_propagation.patch: Add the + 'uplink-status-propagation' extension to ML2/OVN (LP: #2032770). + + -- Corey Bryant Wed, 08 Nov 2023 11:41:21 -0500 + neutron (2:16.4.2-0ubuntu6.3) focal; urgency=medium * d/p/check-subnet-in-remove-subnet-dhcp-options.patch: Ensure dhcp_options diff -Nru neutron-16.4.2/debian/patches/add_uplink_status_propagation.patch neutron-16.4.2/debian/patches/add_uplink_status_propagation.patch --- neutron-16.4.2/debian/patches/add_uplink_status_propagation.patch 1970-01-01 00:00:00.000000000 +0000 +++ neutron-16.4.2/debian/patches/add_uplink_status_propagation.patch 2023-11-08 16:41:21.000000000 +0000 @@ -0,0 +1,41 @@ +From: Rodolfo Alonso Hernandez +Date: Mon, 28 Aug 2023 09:55:05 +0000 +Subject: [PATCH] [OVN] Add the 'uplink-status-propagation' extension to ML2/OVN +Origin: upstream: https://review.opendev.org/c/openstack/neutron/+/892895 + +Bug: https://bugs.launchpad.net/neutron/+bug/2032770 +Closes-Bug: #2032770 + +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +diff --git a/neutron/common/ovn/extensions.py b/neutron/common/ovn/extensions.py +index 3934e56..b9e0dc6 100644 +--- a/neutron/common/ovn/extensions.py ++++ b/neutron/common/ovn/extensions.py +@@ -15,6 +15,7 @@ + from neutron_lib.api.definitions import agent as agent_def + from neutron_lib.api.definitions import availability_zone as az_def + from neutron_lib.api.definitions import router_availability_zone as raz_def ++from neutron_lib.api.definitions import uplink_status_propagation + + # NOTE(russellb) This remains in its own file (vs constants.py) because we want + # to be able to easily import it and export the info without any dependencies +@@ -61,4 +62,5 @@ + 'standard-attr-timestamp', + 'trunk', + 'quota_details', ++ uplink_status_propagation.ALIAS, + ] +diff --git a/releasenotes/notes/ovn-add-extension-uplink-status-propagation-4c232954f8b4f0ef.yaml b/releasenotes/notes/ovn-add-extension-uplink-status-propagation-4c232954f8b4f0ef.yaml +new file mode 100644 +index 0000000..84eeee9 +--- /dev/null ++++ b/releasenotes/notes/ovn-add-extension-uplink-status-propagation-4c232954f8b4f0ef.yaml +@@ -0,0 +1,7 @@ ++--- ++other: ++ - | ++ Added the missing extension ``uplink-status-propagation`` to the ML2/OVN ++ mechanism driver. This extension is used by the ML2/SR-IOV mechanism ++ driver, that could be loaded with ML2/OVN. Now it is possible to create ++ ports with the "uplink-status-propagation" flag defined. diff -Nru neutron-16.4.2/debian/patches/fix-acl-sync-when-default-sg-group-created.patch neutron-16.4.2/debian/patches/fix-acl-sync-when-default-sg-group-created.patch --- neutron-16.4.2/debian/patches/fix-acl-sync-when-default-sg-group-created.patch 1970-01-01 00:00:00.000000000 +0000 +++ neutron-16.4.2/debian/patches/fix-acl-sync-when-default-sg-group-created.patch 2023-11-08 16:41:21.000000000 +0000 @@ -0,0 +1,85 @@ +From a6f5160b6c20144db5293b615f3c9e35c8fc59c7 Mon Sep 17 00:00:00 2001 +From: Miro Tomaska +Date: Wed, 1 Mar 2023 16:32:50 -0600 +Subject: [PATCH] Fix ACL sync when default sg group is created + +Port group not being available in NB DB during ACL sync +is bit of a corner case but possible during the ML2/OVS +to ML2/OVN migration sync. It can also happen in ML2/OVN +only enviroment. See my detailed description of both +scenarios in the linked Bug. +The easiest fix is to just retry ALL port groups sync +one more time if ACL sync cant find a port group row. This +additional resync is really quick. + +Conflicts: + neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py + +Closes-Bug: #2008943 +Change-Id: Iac1472f7f896ea434deacb6d236ab469f4f6ed56 +(cherry picked from commit 33cf2cdc83a8cee9ee075eb371f779c3d356cf48) +--- + .../ovn/mech_driver/ovsdb/ovn_db_sync.py | 33 +++++++++++++++---- + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +index 6d8544180d..08fee14d8c 100644 +--- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py ++++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +@@ -24,6 +24,7 @@ from neutron_lib.plugins import constants as plugin_constants + from neutron_lib.plugins import directory + from neutron_lib.utils import helpers + from oslo_log import log ++from ovsdbapp.backend.ovs_idl import idlutils + import six + + from neutron.common.ovn import acl as acl_utils +@@ -93,7 +94,6 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + LOG.debug("Starting OVN-Northbound DB sync process") + + ctx = context.get_admin_context() +- + self.sync_port_groups(ctx) + self.sync_networks_ports_and_dhcp_opts(ctx) + self.sync_port_dns_records(ctx) +@@ -275,11 +275,32 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + 'remove': num_acls_to_remove}) + + if self.mode == SYNC_MODE_REPAIR: +- with self.ovn_api.transaction(check_error=True) as txn: +- for acla in neutron_acls: +- LOG.warning('ACL found in Neutron but not in ' +- 'OVN DB for port group %s', acla['port_group']) +- txn.add(self.ovn_api.pg_acl_add(**acla, may_exist=True)) ++ pg_resync_count = 0 ++ while True: ++ try: ++ with self.ovn_api.transaction(check_error=True) as txn: ++ for acla in neutron_acls: ++ LOG.warning('ACL found in Neutron but not in ' ++ 'OVN DB for port group %s', ++ acla['port_group']) ++ txn.add(self.ovn_api.pg_acl_add( ++ **acla, may_exist=True)) ++ except idlutils.RowNotFound as row_err: ++ if row_err.msg.startswith("Cannot find Port_Group"): ++ if pg_resync_count < 1: ++ LOG.warning('Port group row was not found during ' ++ 'ACLs sync. Will attempt to sync port ' ++ 'groups one more time. The caught ' ++ 'exception is: %s', row_err) ++ self.sync_port_groups(ctx) ++ pg_resync_count += 1 ++ continue ++ LOG.error('Port group exception during ACL sync ' ++ 'even after one more port group resync. ' ++ 'The caught exception is: %s', row_err) ++ else: ++ raise ++ break + + with self.ovn_api.transaction(check_error=True) as txn: + for aclr in ovn_acls: +-- +2.34.1 + diff -Nru neutron-16.4.2/debian/patches/ovn-db-sync-check-for-router-port-differences.patch neutron-16.4.2/debian/patches/ovn-db-sync-check-for-router-port-differences.patch --- neutron-16.4.2/debian/patches/ovn-db-sync-check-for-router-port-differences.patch 1970-01-01 00:00:00.000000000 +0000 +++ neutron-16.4.2/debian/patches/ovn-db-sync-check-for-router-port-differences.patch 2023-11-08 16:41:21.000000000 +0000 @@ -0,0 +1,181 @@ +From 6af6771deb66b75f0189733771e9cc288d6139ed Mon Sep 17 00:00:00 2001 +From: Lucas Alvares Gomes +Date: Tue, 8 Aug 2023 15:17:40 +0100 +Subject: [PATCH] [OVN] ovn-db-sync check for router port differences + +Prior to this patch the ovn-db-sync script did not check if the router +ports were actually out-of-sync before marking them to be updated. This +behavior introduced irrelevant information in the sync report (specially +when ran in "log" mode) making the user think that the databases were +out-of-sync even when they were not. + +This patch adds the code checking for differences in the Neutron Router +Ports and OVN Logical Router Port entries prior to updating them. + +NOTE FOR THIS BACKPORT: + +The lrp_get() method from ovsdbapp is not present for this stable +branch, so this patch was adapted to use the get_lrouter_port() +instead. + +Conflicts: + neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py + neutron/tests/unit/fake_resources.py + +Change-Id: Id7bf5a6aa547795ba78724eed59ba9d4fb74f758 +Closes-Bug: #2030773 +Signed-off-by: Lucas Alvares Gomes +(cherry picked from commit 4693836a1b58b477298e51cb47622222e3556752) +--- + .../ovn/mech_driver/ovsdb/ovn_db_sync.py | 47 +++++++++++++++++-- + neutron/tests/unit/fake_resources.py | 1 + + .../ovn/mech_driver/ovsdb/test_ovn_db_sync.py | 42 +++++++++++++++++ + 3 files changed, 85 insertions(+), 5 deletions(-) + +diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +index 08fee14d8c..00d74205df 100644 +--- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py ++++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +@@ -342,6 +342,39 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + + return to_add, to_remove + ++ def _is_router_port_changed(self, db_router_port, lrport_nets): ++ """Check if the router port needs to be updated. ++ ++ This method checks for networks and ipv6_ra_configs (if supported) ++ changes on a given router port. ++ """ ++ db_lrport_nets = db_router_port['networks'] ++ if db_lrport_nets != lrport_nets: ++ return True ++ ++ # Check for ipv6_ra_configs changes ++ db_lrport_ra = db_router_port['ipv6_ra_configs'] ++ lrport_ra = {} ++ ipv6_ra_supported = self.ovn_api.is_col_present( ++ 'Logical_Router_Port', 'ipv6_ra_configs') ++ if ipv6_ra_supported: ++ lrp_name = utils.ovn_lrouter_port_name(db_router_port['id']) ++ try: ++ ovn_lrport = self.ovn_api.get_lrouter_port(lrp_name) ++ except idlutils.RowNotFound: ++ # If the port is not found in the OVN database the ++ # ovn-db-sync script will recreate this port later ++ # and it will have the latest information. No need ++ # to update it. ++ return False ++ ++ if not ovn_lrport: ++ return False ++ ++ lrport_ra = ovn_lrport.ipv6_ra_configs ++ ++ return db_lrport_ra != lrport_ra ++ + def sync_routers_and_rports(self, ctx): + """Sync Routers between neutron and NB. + +@@ -411,6 +444,12 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + constants.DEVICE_OWNER_HA_REPLICATED_INT]) + for interface in interfaces: + db_router_ports[interface['id']] = interface ++ networks, ipv6_ra_configs = ( ++ self._ovn_client._get_nets_and_ipv6_ra_confs_for_router_port( ++ ctx, interface)) ++ db_router_ports[interface['id']]['networks'] = networks ++ db_router_ports[interface['id']][ ++ 'ipv6_ra_configs'] = ipv6_ra_configs + + lrouters = self.ovn_api.get_all_logical_routers_with_rports() + +@@ -424,11 +463,9 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + if lrouter['name'] in db_routers: + for lrport, lrport_nets in lrouter['ports'].items(): + if lrport in db_router_ports: +- # We dont have to check for the networks and +- # ipv6_ra_configs values. Lets add it to the +- # update_lrport_list. If they are in sync, then +- # update_router_port will be a no-op. +- update_lrport_list.append(db_router_ports[lrport]) ++ if self._is_router_port_changed( ++ db_router_ports[lrport], lrport_nets): ++ update_lrport_list.append(db_router_ports[lrport]) + del db_router_ports[lrport] + else: + del_lrouter_ports_list.append( +diff --git a/neutron/tests/unit/fake_resources.py b/neutron/tests/unit/fake_resources.py +index 3f59d08aaf..ac0f03b5a8 100644 +--- a/neutron/tests/unit/fake_resources.py ++++ b/neutron/tests/unit/fake_resources.py +@@ -147,6 +147,7 @@ class FakeOvsdbNbOvnIdl(object): + self.ha_chassis_group_del = mock.Mock() + self.ha_chassis_group_add_chassis = mock.Mock() + self.ha_chassis_group_del_chassis = mock.Mock() ++ self.get_lrouter_port = mock.Mock() + + + class FakeOvsdbSbOvnIdl(object): +diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py +index a27eb83f08..414a94a34b 100644 +--- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py ++++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py +@@ -23,6 +23,7 @@ from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import impl_idl_ovn + from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_client + from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_db_sync + from neutron.services.ovn_l3 import plugin as ovn_plugin ++from neutron.tests.unit import fake_resources as fakes + from neutron.tests.unit.plugins.ml2.drivers.ovn.mech_driver import \ + test_mech_driver + +@@ -882,6 +883,47 @@ class TestOvnNbSyncML2(test_mech_driver.OVNMechanismDriverTestCase): + del_port_groups_list) + + ++class TestIsRouterPortChanged(test_mech_driver.OVNMechanismDriverTestCase): ++ ++ def setUp(self): ++ super(TestIsRouterPortChanged, self).setUp() ++ self.ovn_nb_synchronizer = ovn_db_sync.OvnNbSynchronizer( ++ self.plugin, self.mech_driver.nb_ovn, self.mech_driver.sb_ovn, ++ 'log', self.mech_driver) ++ ++ self.db_router_port = { ++ 'id': 'aa076509-915d-4b1c-8d9d-3db53d9c5faf', ++ 'networks': ['fdf9:ad62:3a04::1/64'], ++ 'ipv6_ra_configs': {'address_mode': 'slaac', ++ 'send_periodic': 'true', ++ 'mtu': '1442'} ++ } ++ self.lrport_nets = ['fdf9:ad62:3a04::1/64'] ++ self.ovn_lrport = fakes.FakeOvsdbRow.create_one_ovsdb_row( ++ attrs={'ipv6_ra_configs': {'address_mode': 'slaac', ++ 'send_periodic': 'true', ++ 'mtu': '1442'}}) ++ ++ self.ovn_nb_synchronizer.ovn_api.is_col_present.return_value = True ++ self.ovn_nb_synchronizer.ovn_api.get_lrouter_port.return_value = ( ++ self.ovn_lrport) ++ ++ def test__is_router_port_changed_not_changed(self): ++ self.assertFalse(self.ovn_nb_synchronizer._is_router_port_changed( ++ self.db_router_port, self.lrport_nets)) ++ ++ def test__is_router_port_changed_network_changed(self): ++ self.db_router_port['networks'] = ['172.24.4.26/24', ++ '2001:db8::206/64'] ++ self.assertTrue(self.ovn_nb_synchronizer._is_router_port_changed( ++ self.db_router_port, self.lrport_nets)) ++ ++ def test__is_router_port_changed_ipv6_ra_configs_changed(self): ++ self.db_router_port['ipv6_ra_configs']['mtu'] = '1500' ++ self.assertTrue(self.ovn_nb_synchronizer._is_router_port_changed( ++ self.db_router_port, self.lrport_nets)) ++ ++ + class TestOvnSbSyncML2(test_mech_driver.OVNMechanismDriverTestCase): + + def test_ovn_sb_sync(self): +-- +2.34.1 + diff -Nru neutron-16.4.2/debian/patches/ovn-db-sync-continue-on-duplicate-normalise.patch neutron-16.4.2/debian/patches/ovn-db-sync-continue-on-duplicate-normalise.patch --- neutron-16.4.2/debian/patches/ovn-db-sync-continue-on-duplicate-normalise.patch 1970-01-01 00:00:00.000000000 +0000 +++ neutron-16.4.2/debian/patches/ovn-db-sync-continue-on-duplicate-normalise.patch 2023-11-08 16:41:21.000000000 +0000 @@ -0,0 +1,38 @@ +From f1fe5260c7f22415fef7e098a2b66e84f116c649 Mon Sep 17 00:00:00 2001 +From: Jake Yip +Date: Tue, 20 Jul 2021 17:03:08 +1000 +Subject: [PATCH] Allow ovn_db_sync to continue on duplicate normalised CIDR + +OVN now uses normalised CIDR when adding a security group rule[1]. It +uses may_exist=True for adding ACL (secgroup rule), in case there are +multiple CIDRs in neutron that normalises to the same. + +Do the same in ovn_db_sync, so that the sync don't fail hard on such +duplicates. + +[1] https://review.opendev.org/c/openstack/neutron/+/736386/ + +Change-Id: I9d9c21e460029e4a6a845520bfcc2889ad20429b +Related-Bug: #1869129 +Closes-Bug: #1961112 +(cherry picked from commit 5a0a2b7847da067817640404f53e0807755e08d7) +--- + .../plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +index 10c2c1db3f..15ab5285ac 100644 +--- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py ++++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +@@ -279,7 +279,7 @@ class OvnNbSynchronizer(OvnDbSynchronizer): + for acla in neutron_acls: + LOG.warning('ACL found in Neutron but not in ' + 'OVN DB for port group %s', acla['port_group']) +- txn.add(self.ovn_api.pg_acl_add(**acla)) ++ txn.add(self.ovn_api.pg_acl_add(**acla, may_exist=True)) + + with self.ovn_api.transaction(check_error=True) as txn: + for aclr in ovn_acls: +-- +2.34.1 + diff -Nru neutron-16.4.2/debian/patches/ovn-specify-port-type-if-router-port-when-updating.patch neutron-16.4.2/debian/patches/ovn-specify-port-type-if-router-port-when-updating.patch --- neutron-16.4.2/debian/patches/ovn-specify-port-type-if-router-port-when-updating.patch 1970-01-01 00:00:00.000000000 +0000 +++ neutron-16.4.2/debian/patches/ovn-specify-port-type-if-router-port-when-updating.patch 2023-11-08 16:41:21.000000000 +0000 @@ -0,0 +1,150 @@ +From 6e1b7d15d7d68f2d409ce34e9a518c6aa0289022 Mon Sep 17 00:00:00 2001 +From: Arnau Verdaguer +Date: Thu, 16 Dec 2021 21:53:27 +0100 +Subject: [PATCH] [ovn] Specify port type if it's a router port when updating + +In order to avoid multiple LogicalSwitchPortUpdateUpEvent and +LogicalSwitchPortUpdateDownEvent is mandatory to specify the +router port type when udpating the port. + +If the port is not specified when updating the port, the +transactions will trigger a modification on the ovnnb db +that will set the port status to down[0]. Triggering an unnecessary +DownEvent followed by another UpEvent. Those unnecessary event +most likely will trigger a revision conflict. + +[0] - https://github.com/ovn-org/ovn/blob/ +4f93381d7d38aa21f56fb3ff4ec00490fca12614/northd/northd.c#L15604 + +Conflicts: + neutron/common/ovn/constants.py + +Closes-Bug: #1955578 +Change-Id: I296003a936db16dd3a7d184ec44908fb3f261876 +(cherry picked from commit 8c482b83f2cf6f5495f4df2e5698595db704798d) +--- + neutron/common/ovn/constants.py | 1 + + .../ovn/mech_driver/ovsdb/ovn_client.py | 7 ++ + .../ovn/mech_driver/test_mech_driver.py | 69 +++++++++++++++++++ + 3 files changed, 77 insertions(+) + +diff --git a/neutron/common/ovn/constants.py b/neutron/common/ovn/constants.py +index 776df5a911..4597848802 100644 +--- a/neutron/common/ovn/constants.py ++++ b/neutron/common/ovn/constants.py +@@ -288,6 +288,7 @@ PORT_SECURITYGROUPS = 'security_groups' + LSP_TYPE_LOCALNET = 'localnet' + LSP_TYPE_VIRTUAL = 'virtual' + LSP_TYPE_EXTERNAL = 'external' ++LSP_TYPE_ROUTER = 'router' + LSP_OPTIONS_VIRTUAL_PARENTS_KEY = 'virtual-parents' + LSP_OPTIONS_VIRTUAL_IP_KEY = 'virtual-ip' + LSP_OPTIONS_MCAST_FLOOD_REPORTS = 'mcast_flood_reports' +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 7d76accd2b..c8eccd6e29 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 +@@ -491,6 +491,13 @@ class OVNClient(object): + txn.add(check_rev_cmd) + columns_dict = {} + if utils.is_lsp_router_port(port): ++ # It is needed to specify the port type, if not specified ++ # the AddLSwitchPortCommand will trigger a change ++ # on the northd status column from UP to DOWN, triggering a ++ # LogicalSwitchPortUpdateDownEvent, that will most likely ++ # cause a revision conflict. ++ # https://bugs.launchpad.net/neutron/+bug/1955578 ++ columns_dict['type'] = ovn_const.LSP_TYPE_ROUTER + port_info.options.update( + self._nb_idl.get_router_port_options(port['id'])) + else: +diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +index 5ee1ea8ea1..0157c689d6 100644 +--- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py ++++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +@@ -34,6 +34,7 @@ from neutron.db import ovn_revision_numbers_db as db_rev + from neutron.plugins.ml2.drivers.ovn.mech_driver import mech_driver + from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import impl_idl_ovn + from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_client ++from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovsdb_monitor + from neutron.tests import base as tests_base + from neutron.tests.functional import base + +@@ -507,6 +508,74 @@ class TestExternalPorts(base.TestOVNFunctionalBase): + self.assertEqual(str(self.default_ch_grp.uuid), + str(ovn_port.ha_chassis_group[0].uuid)) + ++ def _create_router_port(self, vnic_type): ++ net_id = self.n1['network']['id'] ++ port_data = { ++ 'port': {'network_id': net_id, ++ 'tenant_id': self._tenant_id, ++ portbindings.VNIC_TYPE: 'normal'}} ++ ++ # Create port ++ port_req = self.new_create_request('ports', port_data, self.fmt) ++ port_res = port_req.get_response(self.api) ++ port = self.deserialize(self.fmt, port_res)['port'] ++ ++ # Update it as lsp port ++ port_upt_data = { ++ 'port': {'device_owner': "network:router_gateway"} ++ } ++ port_req = self.new_update_request( ++ 'ports', port_upt_data, port['id'], self.fmt) ++ port_res = port_req.get_response(self.api) ++ ++ def test_add_external_port_avoid_flapping(self): ++ class LogicalSwitchPortUpdateUpEventTest(event.RowEvent): ++ def __init__(self): ++ self.count = 0 ++ table = 'Logical_Switch_Port' ++ events = (self.ROW_UPDATE,) ++ super(LogicalSwitchPortUpdateUpEventTest, self).__init__( ++ events, table, (('up', '=', True),), ++ old_conditions=(('up', '=', False),)) ++ ++ def run(self, event, row, old): ++ self.count += 1 ++ ++ def get_count(self): ++ return self.count ++ ++ class LogicalSwitchPortUpdateDownEventTest(event.RowEvent): ++ def __init__(self): ++ self.count = 0 ++ table = 'Logical_Switch_Port' ++ events = (self.ROW_UPDATE,) ++ super(LogicalSwitchPortUpdateDownEventTest, self).__init__( ++ events, table, (('up', '=', False),), ++ old_conditions=(('up', '=', True),)) ++ ++ def run(self, event, row, old): ++ self.count += 1 ++ ++ def get_count(self): ++ return self.count ++ ++ og_up_event = ovsdb_monitor.LogicalSwitchPortUpdateUpEvent(None) ++ og_down_event = ovsdb_monitor.LogicalSwitchPortUpdateDownEvent(None) ++ test_down_event = LogicalSwitchPortUpdateDownEventTest() ++ test_up_event = LogicalSwitchPortUpdateUpEventTest() ++ self.nb_api.idl.notify_handler.unwatch_events( ++ [og_up_event, og_down_event]) ++ self.nb_api.idl.notify_handler.watch_events( ++ [test_down_event, test_up_event]) ++ # Creating a port the same way as the osp cli cmd ++ # openstack router add port ROUTER PORT ++ # shouldn't trigger an status flapping (up -> down -> up) ++ # it should be created with status false and then change the ++ # status as up, triggering only a LogicalSwitchPortUpdateUpEvent. ++ self._create_router_port(portbindings.VNIC_DIRECT) ++ self.assertEqual(test_down_event.get_count(), 0) ++ self.assertEqual(test_up_event.get_count(), 1) ++ + def test_external_port_create_vnic_direct(self): + self._test_external_port_create(portbindings.VNIC_DIRECT) + +-- +2.34.1 + diff -Nru neutron-16.4.2/debian/patches/series neutron-16.4.2/debian/patches/series --- neutron-16.4.2/debian/patches/series 2023-08-21 19:29:46.000000000 +0000 +++ neutron-16.4.2/debian/patches/series 2023-11-08 16:41:21.000000000 +0000 @@ -17,3 +17,8 @@ CVE-2022-3277.patch check-subnet-in-remove-subnet-dhcp-options.patch ovn-fix-untrusted-port-security-enabled-check.patch +ovn-db-sync-continue-on-duplicate-normalise.patch +ovn-db-sync-check-for-router-port-differences.patch +ovn-specify-port-type-if-router-port-when-updating.patch +add_uplink_status_propagation.patch +fix-acl-sync-when-default-sg-group-created.patch