From 2649d05dca6575254757c05eab42cb846b0d9950 Mon Sep 17 00:00:00 2001 From: renliang17 Date: Thu, 7 Jul 2022 14:50:15 +0800 Subject: [PATCH 1/5] Update the Ethernet card information Mellanox series Ethernet card information, update the address for https://community.mellanox.com/s/article/HowTo-Configure-SR-IOV-for-ConnectX-4-ConnectX-5-ConnectX-6-with-KVM-Ethernet Broadcom series Ethernet card information, update the address for https://www.broadcom.com/products/ethernet-connectivity/network-adapters Change-Id: I077c686310638081198acea81e8a26bcbd5cd934 (cherry picked from commit d0d484e41a33612e8162742279869692c3dc629b) --- doc/source/admin/config-sriov.rst | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/doc/source/admin/config-sriov.rst b/doc/source/admin/config-sriov.rst index 662081084ce..4d663fa784f 100644 --- a/doc/source/admin/config-sriov.rst +++ b/doc/source/admin/config-sriov.rst @@ -64,22 +64,14 @@ The following manufacturers are known to work: - QLogic - Broadcom -For information on **Mellanox SR-IOV Ethernet ConnectX cards**, see: +For information on **Mellanox SR-IOV Ethernet ConnectX cards**, see the +`Mellanox: How To Configure SR-IOV VFs on ConnectX-4 or newer `_. -- `Mellanox: How To Configure SR-IOV VFs on ConnectX-4 or newer `_. -- `Mellanox: How To Configure SR-IOV VFs on ConnectX-3/ConnectX-3 Pro `_. +For information on **QLogic SR-IOV Ethernet cards**, see the +`User's Guide OpenStack Deployment with SR-IOV Configuration `_. -For information on **QLogic SR-IOV Ethernet cards**, see: - -- `User's Guide OpenStack Deployment with SR-IOV Configuration `_. - -For information on **Broadcom NetXtreme-E Series Ethernet cards**, see the -`Broadcom NetXtreme-C/NetXtreme-E User Guide -`_. - -For information on **Broadcom NetXtreme-S Series Ethernet cards**, see the -`Broadcom NetXtreme-S Product Page -`_. +For information on **Broadcom NetXtreme Series Ethernet cards**, see the +`Broadcom NetXtreme Product Page `_. Using SR-IOV interfaces ~~~~~~~~~~~~~~~~~~~~~~~ From de89581ace06c74b090bf25f3408a3d3dccf56fb Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Wed, 1 Jun 2022 17:15:42 +0200 Subject: [PATCH 2/5] Mark functional L3ha tests as unstable All functional tests which uses wait_until_ha_router_has_state() method are now marked as unstable so in case of timeout while waiting for router's state transition, job will not fail. Related-Bug: #1956958 Change-Id: I0e5d08c1a9dc475c7b138c4934ef0331a4339a4c (cherry picked from commit d13da77107fd9e9166b891409376a67210f7f48b) --- neutron/tests/functional/agent/l3/framework.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/neutron/tests/functional/agent/l3/framework.py b/neutron/tests/functional/agent/l3/framework.py index af476b7085a..c773d2945f3 100644 --- a/neutron/tests/functional/agent/l3/framework.py +++ b/neutron/tests/functional/agent/l3/framework.py @@ -40,6 +40,7 @@ from neutron.conf.agent import common as agent_config from neutron.conf.agent.l3 import config as l3_config from neutron.conf import common as common_config +from neutron.tests import base as test_base from neutron.tests.common import l3_test_common from neutron.tests.common import net_helpers from neutron.tests.functional import base @@ -703,8 +704,8 @@ def fail_ha_router(self, router): ha_device = ip_lib.IPDevice(device_name, router.ha_namespace) ha_device.link.set_down() - @staticmethod - def wait_until_ha_router_has_state(router, expected_state): + @test_base.unstable_test("bug 1956958") + def wait_until_ha_router_has_state(self, router, expected_state): def router_has_expected_state(): state = router.ha_state From e62c81a5704316ac1b42ce546e31f1732fa9b986 Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Wed, 16 Nov 2022 18:47:04 +0000 Subject: [PATCH 3/5] ovn: first tear down old metadata namespaces, then deploy new While the reverse order may work, it's considered invalid by OVN and not guaranteed to work properly since OVN may not necessarily know which of two ports is the one to configure. This configuration also triggered a bug in OVN where tearing down a port after deploying a new one resulted in removing flows that serve the port. There is a patch up for review for OVN [1] to better handle multiple assignment of the same port, but it doesn't make the setup any more valid. [1] http://patchwork.ozlabs.org/project/ovn/patch/20221114092437.2807815-1-xsimonar@redhat.com/ Closes-Bug: #1997092 Change-Id: Ic7dbc4e8b00423e58f69646a9e3cedc6f72d6c63 (cherry picked from commit 3093aaab13dd6ba04ef0e686eb4c6cc386c58941) --- neutron/agent/ovn/metadata/agent.py | 47 +++++++------ .../unit/agent/ovn/metadata/test_agent.py | 68 ++++++++----------- 2 files changed, 51 insertions(+), 64 deletions(-) diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py index d77ee28cdf8..670606ab981 100644 --- a/neutron/agent/ovn/metadata/agent.py +++ b/neutron/agent/ovn/metadata/agent.py @@ -319,6 +319,12 @@ def _get_ovn_bridge(self): "br-int instead.") return 'br-int' + def get_networks(self): + ports = self.sb_idl.get_ports_on_chassis(self.chassis) + return {(str(p.datapath.uuid), + ovn_utils.get_network_name_from_datapath(p.datapath)) + for p in self._vif_ports(ports)} + @_sync_lock def sync(self): """Agent sync. @@ -327,16 +333,26 @@ def sync(self): chassis are serving metadata. Also, it will tear down those namespaces which were serving metadata but are no longer needed. """ - metadata_namespaces = self.ensure_all_networks_provisioned() + + # first, clean up namespaces that should no longer deploy system_namespaces = tuple( ns.decode('utf-8') if isinstance(ns, bytes) else ns for ns in ip_lib.list_network_namespaces()) + nets = self.get_networks() + metadata_namespaces = [ + self._get_namespace_name(net[1]) + for net in nets + ] unused_namespaces = [ns for ns in system_namespaces if ns.startswith(NS_PREFIX) and ns not in metadata_namespaces] for ns in unused_namespaces: self.teardown_datapath(self._get_datapath_name(ns)) + # now that all obsolete namespaces are cleaned up, deploy required + # networks + self.ensure_all_networks_provisioned(nets) + @staticmethod def _get_veth_name(datapath): return ['{}{}{}'.format(n_const.TAP_DEVICE_PREFIX, @@ -428,8 +444,6 @@ def provision_datapath(self, datapath, net_name): and assign the IP addresses to the interface corresponding to the metadata port of the network. It will also remove existing IP addresses that are no longer needed. - - :return: The metadata namespace name of this datapath """ LOG.debug("Provisioning metadata for network %s", net_name) port = self.sb_idl.get_metadata_port_network(datapath) @@ -537,28 +551,13 @@ def provision_datapath(self, datapath, net_name): self.conf, bind_address=n_const.METADATA_V4_IP, network_id=net_name) - return namespace + def ensure_all_networks_provisioned(self, nets): + """Ensure that all requested datapaths are provisioned. - def ensure_all_networks_provisioned(self): - """Ensure that all datapaths are provisioned. - - This function will make sure that all datapaths with ports bound to - our chassis have its namespace, VETH pair and OVS port created and - metadata proxy is up and running. - - :return: A list with the namespaces that are currently serving - metadata + This function will make sure that requested datapaths have their + namespaces, VETH pair and OVS ports created and metadata proxies are up + and running. """ - # Retrieve all VIF ports in our Chassis - ports = self.sb_idl.get_ports_on_chassis(self.chassis) - nets = {(str(p.datapath.uuid), - ovn_utils.get_network_name_from_datapath(p.datapath)) - for p in self._vif_ports(ports)} - namespaces = [] # Make sure that all those datapaths are serving metadata for datapath, net_name in nets: - netns = self.provision_datapath(datapath, net_name) - if netns: - namespaces.append(netns) - - return namespaces + self.provision_datapath(datapath, net_name) diff --git a/neutron/tests/unit/agent/ovn/metadata/test_agent.py b/neutron/tests/unit/agent/ovn/metadata/test_agent.py index 8a83e5c0ba1..6bfe9ab8c9e 100644 --- a/neutron/tests/unit/agent/ovn/metadata/test_agent.py +++ b/neutron/tests/unit/agent/ovn/metadata/test_agent.py @@ -71,19 +71,29 @@ def setUp(self): self.agent.chassis = 'chassis' self.agent.ovn_bridge = 'br-int' + self.ports = [] + for i in range(0, 3): + self.ports.append(makePort(datapath=DatapathInfo(uuid=str(i), + external_ids={'name': 'neutron-%d' % i}))) + self.agent.sb_idl.get_ports_on_chassis.return_value = self.ports + def test_sync(self): + with mock.patch.object( self.agent, 'ensure_all_networks_provisioned') as enp,\ mock.patch.object( ip_lib, 'list_network_namespaces') as lnn,\ mock.patch.object( self.agent, 'teardown_datapath') as tdp: - enp.return_value = ['ovnmeta-1', 'ovnmeta-2'] lnn.return_value = ['ovnmeta-1', 'ovnmeta-2'] self.agent.sync() - enp.assert_called_once_with() + enp.assert_called_once_with({ + (p.datapath.uuid, p.datapath.uuid) + for p in self.ports + }) + lnn.assert_called_once_with() tdp.assert_not_called() @@ -95,18 +105,20 @@ def test_sync_teardown_namespace(self): ip_lib, 'list_network_namespaces') as lnn,\ mock.patch.object( self.agent, 'teardown_datapath') as tdp: - enp.return_value = ['ovnmeta-1', 'ovnmeta-2'] lnn.return_value = ['ovnmeta-1', 'ovnmeta-2', 'ovnmeta-3', 'ns1', 'ns2'] self.agent.sync() - enp.assert_called_once_with() + enp.assert_called_once_with({ + (p.datapath.uuid, p.datapath.uuid) + for p in self.ports + }) lnn.assert_called_once_with() tdp.assert_called_once_with('3') - def test_ensure_all_networks_provisioned(self): - """Test networks are provisioned. + def test_get_networks(self): + """Test which networks are provisioned. This test simulates that this chassis has the following ports: * datapath '0': 1 port @@ -115,44 +127,27 @@ def test_ensure_all_networks_provisioned(self): * datapath '3': 1 port with type 'external' * datapath '5': 1 port with type 'unknown' - It is expected that only datapaths '0', '1' and '2' are provisioned - once. + It is expected that only datapaths '0', '1' and '2' are scheduled for + provisioning. """ - ports = [] - for i in range(0, 3): - ports.append(makePort(datapath=DatapathInfo(uuid=str(i), - external_ids={'name': 'neutron-%d' % i}))) - ports.append(makePort(datapath=DatapathInfo(uuid='1', + self.ports.append(makePort(datapath=DatapathInfo(uuid='1', external_ids={'name': 'neutron-1'}))) - ports.append(makePort(datapath=DatapathInfo(uuid='3', + self.ports.append(makePort(datapath=DatapathInfo(uuid='3', external_ids={'name': 'neutron-3'}), type='external')) - ports.append(makePort(datapath=DatapathInfo(uuid='5', + self.ports.append(makePort(datapath=DatapathInfo(uuid='5', external_ids={'name': 'neutron-5'}), type='unknown')) - with mock.patch.object(self.agent, 'provision_datapath', - return_value=None) as pdp,\ - mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis', - return_value=ports): - self.agent.ensure_all_networks_provisioned() - - expected_calls = [mock.call(str(i), str(i)) for i in range(0, 4)] - self.assertEqual(sorted(expected_calls), - sorted(pdp.call_args_list)) + expected_networks = {(str(i), str(i)) for i in range(0, 4)} + self.assertEqual(expected_networks, self.agent.get_networks()) def test_update_datapath_provision(self): - ports = [] - for i in range(0, 3): - ports.append(makePort(datapath=DatapathInfo(uuid=str(i), - external_ids={'name': 'neutron-%d' % i}))) - ports.append(makePort(datapath=DatapathInfo(uuid='3', + self.ports.append(makePort(datapath=DatapathInfo(uuid='3', external_ids={'name': 'neutron-3'}), type='external')) with mock.patch.object(self.agent, 'provision_datapath', return_value=None) as pdp,\ - mock.patch.object(self.agent, 'teardown_datapath') as tdp,\ - mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis', - return_value=ports): + mock.patch.object(self.agent, 'teardown_datapath') as tdp: self.agent.update_datapath('1', 'a') self.agent.update_datapath('3', 'b') expected_calls = [mock.call('1', 'a'), mock.call('3', 'b')] @@ -160,16 +155,9 @@ def test_update_datapath_provision(self): tdp.assert_not_called() def test_update_datapath_teardown(self): - ports = [] - for i in range(0, 3): - ports.append(makePort(datapath=DatapathInfo(uuid=str(i), - external_ids={'name': 'neutron-%d' % i}))) - with mock.patch.object(self.agent, 'provision_datapath', return_value=None) as pdp,\ - mock.patch.object(self.agent, 'teardown_datapath') as tdp,\ - mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis', - return_value=ports): + mock.patch.object(self.agent, 'teardown_datapath') as tdp: self.agent.update_datapath('5', 'a') tdp.assert_called_once_with('5', 'a') pdp.assert_not_called() From 4eba379801e8a550dfcdf51a3ebfa45e4c74caa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elvira=20Garc=C3=ADa?= Date: Thu, 10 Nov 2022 00:47:53 +0100 Subject: [PATCH 4/5] Fix behaviour of enable/disable in OVN network log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, only the first log object created that associated to a certain ACL would be able to make changes to the True/False property of that ACL. This patch makes the driver to take in consideration each log object created to enable or disable an ACL logging status. A functional test is added so as to ensure correct behaviour of this feature. Closes-Bug: #1996780 Change-Id: Ib9663495f30562f79babef163729a0c43812089d Signed-off-by: Elvira GarcĂ­a (cherry picked from commit f629b77d3c821717333eb740311a33a7a45b0e8d) --- neutron/services/logapi/drivers/ovn/driver.py | 50 +++++++++++++++-- .../logapi/drivers/ovn/test_driver.py | 56 +++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/neutron/services/logapi/drivers/ovn/driver.py b/neutron/services/logapi/drivers/ovn/driver.py index 080bcc475b8..98ed3f29ec9 100644 --- a/neutron/services/logapi/drivers/ovn/driver.py +++ b/neutron/services/logapi/drivers/ovn/driver.py @@ -302,6 +302,46 @@ def create_log_precommit(self, context, log_obj): if not self.network_logging_supported(self.ovn_nb): raise LoggingNotSupported() + def _unset_disabled_acls(self, context, log_obj, ovn_txn): + """Check if we need to disable any ACLs after an update. + + Will return True if there were more logs, and False if there was + nothing to check. + + :param context: current running context information + :param log_obj: a log_object which was updated + :returns: True if there were other logs enabled, otherwise False. + """ + if log_obj.enabled: + return False + + pgs = self._pgs_from_log_obj(context, log_obj) + other_logs = [log for log in self._get_logs(context) + if log.id != log_obj.id and log.enabled] + if not other_logs: + return False + + if log_obj.event == log_const.ALL_EVENT: + acls_to_check = pgs[0]["acls"].copy() + if not acls_to_check: + return True + for log in other_logs: + for acl in self._pgs_from_log_obj(context, log)[0]["acls"]: + if acl in acls_to_check: + acls_to_check.remove(acl) + if not acls_to_check: + return True + acls_to_remove = [{"name": pgs[0]["name"], "acls": acls_to_check}] + self._remove_acls_log(acls_to_remove, ovn_txn) + else: + all_events = set([log.event for log in other_logs + if (not log.resource_id or + log.resource_id == log_obj.resource_id)]) + if (log_const.ALL_EVENT not in all_events and + log_obj.event not in all_events): + self._remove_acls_log(pgs, ovn_txn) + return True + def update_log(self, context, log_obj): """Update a log_obj invocation. @@ -311,11 +351,13 @@ def update_log(self, context, log_obj): """ LOG.debug("Update_log %s", log_obj) - pgs = self._pgs_from_log_obj(context, log_obj) - actions_enabled = self._acl_actions_enabled(log_obj) with self.ovn_nb.transaction(check_error=True) as ovn_txn: - self._set_acls_log(pgs, ovn_txn, actions_enabled, - utils.ovn_name(log_obj.id)) + + if not self._unset_disabled_acls(context, log_obj, ovn_txn): + pgs = self._pgs_from_log_obj(context, log_obj) + actions_enabled = self._acl_actions_enabled(log_obj) + self._set_acls_log(pgs, ovn_txn, actions_enabled, + utils.ovn_name(log_obj.id)) def delete_log(self, context, log_obj): """Delete a log_obj invocation. diff --git a/neutron/tests/functional/services/logapi/drivers/ovn/test_driver.py b/neutron/tests/functional/services/logapi/drivers/ovn/test_driver.py index b67680b707f..03f1d365d62 100644 --- a/neutron/tests/functional/services/logapi/drivers/ovn/test_driver.py +++ b/neutron/tests/functional/services/logapi/drivers/ovn/test_driver.py @@ -338,3 +338,59 @@ def test_events_one_sg(self): self._add_logs_then_remove( log_const.DROP_EVENT, log_const.ACCEPT_EVENT, sg=self.sg3, sgrs=self.sg3rs) + + def test_disable_logs(self): + # This test ensures that acls are correctly disabled when having + # multiple log objects. + + # Check there are no acls with their logging active + sgrs = self.sg1rs + self._check_sgrs(sgrs, is_enabled=False) + self._check_acl_log_drop(is_enabled=False) + + # Add accept log object + log_data1 = self._log_data(sg_id=self.sg1) + event1 = log_const.ACCEPT_EVENT + log_data1['log']['event'] = event1 + log_obj1 = self.log_plugin.create_log(self.ctxt, log_data1) + self._check_acl_log_drop(is_enabled=False) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + + # Add drop log object + log_data2 = self._log_data(sg_id=self.sg1) + event2 = log_const.DROP_EVENT + log_data2['log']['event'] = event2 + log_obj2 = self.log_plugin.create_log(self.ctxt, log_data2) + self._check_acl_log_drop(is_enabled=True) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + + # Disable drop log object and check it worked correctly + log_data2['log']['enabled'] = False + self.log_plugin.update_log(self.ctxt, log_obj2['id'], log_data2) + self._check_acl_log_drop(is_enabled=False) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + + # Enable drop log and create all log object + log_data2['log']['enabled'] = True + self.log_plugin.update_log(self.ctxt, log_obj2['id'], log_data2) + self._check_acl_log_drop(is_enabled=True) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + + log_data3 = self._log_data(sg_id=self.sg1) + log_data3['log']['event'] = log_const.ALL_EVENT + log_obj3 = self.log_plugin.create_log(self.ctxt, log_data3) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + self._check_acl_log_drop(is_enabled=True) + + # Disable all log object and check all acls are still enabled (because + # of the other objects) + log_data3['log']['enabled'] = False + self.log_plugin.update_log(self.ctxt, log_obj3['id'], log_data3) + self._check_sgrs(sgrs=sgrs, is_enabled=True) + self._check_acl_log_drop(is_enabled=True) + + # Disable accept log object and only drop traffic gets logged + log_data1['log']['enabled'] = False + self.log_plugin.update_log(self.ctxt, log_obj1['id'], log_data1) + self._check_sgrs(sgrs=sgrs, is_enabled=False) + self._check_acl_log_drop(is_enabled=True) From aeed2f44a205d2b221d3aab16ddcd0d215925d87 Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Tue, 5 Apr 2022 09:11:11 +0200 Subject: [PATCH 5/5] Set bigger swap in the functional and fullstack jobs As we are hitting some memory limits (again) in functional tests job, lets configure 8GB of swap in all functional and fullstack jobs. Before that patch swap was configured to 4GB only in the FIPS jobs. Now it will be set to 8GB in all functional and fullstack jobs. Closes-Bug: #1966394 Change-Id: I6b097d8409318a5dfe17e9673adb6c1431a59b0b (cherry picked from commit b8dcb0b7afe06f92090d5d2c366b9aae3a532ebc) --- zuul.d/base.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zuul.d/base.yaml b/zuul.d/base.yaml index f403d3983ce..302538f6f31 100644 --- a/zuul.d/base.yaml +++ b/zuul.d/base.yaml @@ -34,6 +34,7 @@ - ^rally-jobs/.*$ - ^zuul.d/(?!(project)).*\.yaml vars: + configure_swap_size: 8192 Q_BUILD_OVS_FROM_GIT: True MEMORY_TRACKER: True INSTALL_OVN: True @@ -130,7 +131,6 @@ vars: nslookup_target: 'opendev.org' enable_fips: True - configure_swap_size: 4096 devstack_localrc: ISCSI_CHAP_ALGORITHMS: SHA3-256,SHA256 Q_BUILD_OVS_FROM_GIT: true @@ -144,7 +144,6 @@ vars: nslookup_target: 'opendev.org' enable_fips: True - configure_swap_size: 4096 devstack_localrc: ISCSI_CHAP_ALGORITHMS: SHA3-256,SHA256 Q_BUILD_OVS_FROM_GIT: true