From f82c650c8c1bfb0b4283b8624d8b6f32f1f8d188 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Sun, 10 Mar 2024 15:47:09 +0000 Subject: [PATCH] [OVN] Add the network type to the ``Logical_Switch`` register Now the ``Logical_Switch`` register (that represents an OVN network), stored the network type in the "external_ids" field. Related-Bug: #2056558 Change-Id: I9e55a7412d841b7b59602c56c3a4e2f9c954aeed --- .../ovn/mech_driver/ovsdb/maintenance.py | 25 +++++++++++++++++ .../ovn/mech_driver/ovsdb/ovn_client.py | 24 ++++++++++------- .../ovn/mech_driver/ovsdb/test_maintenance.py | 15 +++++++++++ .../ovn/mech_driver/test_mech_driver.py | 6 +++++ .../tests/unit/services/ovn_l3/test_plugin.py | 27 ++++++++++++++++++- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py index fbaf91064ec..825a6689d03 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py @@ -40,6 +40,7 @@ from neutron.conf.plugins.ml2.drivers.ovn import ovn_conf from neutron.db import l3_attrs_db from neutron.db import ovn_hash_ring_db as hash_ring_db from neutron.db import ovn_revision_numbers_db as revision_numbers_db +from neutron.objects import network as network_obj from neutron.objects import ports as ports_obj from neutron.objects import router as router_obj from neutron.objects import servicetype as servicetype_obj @@ -1228,6 +1229,30 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase): raise periodics.NeverAgain() + # TODO(ralonsoh): Remove this method in the E cycle (SLURP release) + @has_lock_periodic(spacing=600, run_immediately=True) + def set_network_type(self): + """Add the network type to the Logical_Switch registers""" + context = n_context.get_admin_context() + net_segments = network_obj.NetworkSegment.get_objects(context) + net_segments = {seg.network_id: seg.network_type + for seg in net_segments} + cmds = [] + for ls in self._nb_idl.ls_list().execute(check_error=True): + if ovn_const.OVN_NETTYPE_EXT_ID_KEY not in ls.external_ids: + net_id = ls.name.replace('neutron-', '') + external_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: net_segments[net_id]} + cmds.append(self._nb_idl.db_set( + 'Logical_Switch', ls.uuid, ('external_ids', external_ids))) + + if cmds: + with self._nb_idl.transaction(check_error=True) as txn: + for cmd in cmds: + txn.add(cmd) + + raise periodics.NeverAgain() + class HashRingHealthCheckPeriodics(object): 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 f94fc799ef3..e4128a0f70b 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 @@ -1647,12 +1647,14 @@ class OVNClient(object): for net in networks) else 'false' return reside_redir_ch - def _gen_router_port_options(self, port, network=None): + def _gen_router_port_options(self, port): options = {} admin_context = n_context.get_admin_context() - if network is None: - network = self._plugin.get_network(admin_context, - port['network_id']) + ls_name = utils.ovn_name(port['network_id']) + ls = self._nb_idl.ls_get(ls_name).execute(check_error=True) + network_type = ls.external_ids[ovn_const.OVN_NETTYPE_EXT_ID_KEY] + network_mtu = int( + ls.external_ids[ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY]) # For VLAN type networks we need to set the # "reside-on-redirect-chassis" option so the routing for this # logical router port is centralized in the chassis hosting the @@ -1660,7 +1662,7 @@ class OVNClient(object): # https://github.com/openvswitch/ovs/commit/85706c34d53d4810f54bec1de662392a3c06a996 # FIXME(ltomasbo): Once Bugzilla 2162756 is fixed the # is_provider_network check should be removed - if network.get(pnet.NETWORK_TYPE) == const.TYPE_VLAN: + if network_type == const.TYPE_VLAN: reside_redir_ch = self._get_reside_redir_for_gateway_port( port['device_id']) options[ovn_const.LRP_OPTIONS_RESIDE_REDIR_CH] = reside_redir_ch @@ -1682,10 +1684,10 @@ class OVNClient(object): admin_context, filters={'id': network_ids}) if ovn_conf.is_ovn_emit_need_to_frag_enabled(): for net in networks: - if net['mtu'] > network['mtu']: + if net['mtu'] > network_mtu: options[ ovn_const.OVN_ROUTER_PORT_GW_MTU_OPTION] = str( - network['mtu']) + network_mtu) break if ovn_conf.is_ovn_distributed_floating_ip(): # NOTE(ltomasbo): For VLAN type networks connected through @@ -2002,7 +2004,11 @@ class OVNClient(object): ovn_const.OVN_REV_NUM_EXT_ID_KEY: str( utils.get_revision_number(network, ovn_const.TYPE_NETWORKS)), ovn_const.OVN_AZ_HINTS_EXT_ID_KEY: - ','.join(common_utils.get_az_hints(network))}} + ','.join(common_utils.get_az_hints(network)), + # NOTE(ralonsoh): it is not considered the case of multiple + # segments. + ovn_const.OVN_NETTYPE_EXT_ID_KEY: network.get(pnet.NETWORK_TYPE), + }} # Enable IGMP snooping if igmp_snooping_enable is enabled in Neutron vlan_transparent = ( @@ -2057,7 +2063,7 @@ class OVNClient(object): commands = [] for port in ports: lrp_name = utils.ovn_lrouter_port_name(port['id']) - options = self._gen_router_port_options(port, prov_net) + options = self._gen_router_port_options(port) commands.append(self._nb_idl.lrp_set_options(lrp_name, **options)) self._transaction(commands, txn=txn) diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py index 0272722864e..aaacb727bff 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py @@ -1220,6 +1220,21 @@ class TestMaintenance(_TestMaintenanceHelper): lr = self.nb_api.lookup('Logical_Router', utils.ovn_name(router['id'])) self.assertEqual([], lr.ports[0].gateway_chassis) + def test_set_network_type(self): + net1 = self._create_network(uuidutils.generate_uuid()) + ls_name = utils.ovn_name(net1['id']) + self.nb_api.db_remove( + 'Logical_Switch', ls_name, 'external_ids', + ovn_const.OVN_NETTYPE_EXT_ID_KEY).execute(check_error=True) + ls = self.nb_api.lookup('Logical_Switch', ls_name) + self.assertIsNone(ls.external_ids.get( + ovn_const.OVN_NETTYPE_EXT_ID_KEY)) + + self.assertRaises(periodics.NeverAgain, self.maint.set_network_type) + ls = self.nb_api.lookup('Logical_Switch', ls_name) + self.assertEqual(net1[provnet_apidef.NETWORK_TYPE], + ls.external_ids.get(ovn_const.OVN_NETTYPE_EXT_ID_KEY)) + class TestLogMaintenance(_TestMaintenanceHelper, test_log_driver.LogApiTestCaseBase): diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py index d59e81bd30f..eb76445f6fc 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/test_mech_driver.py @@ -2565,6 +2565,12 @@ class TestOVNMechanismDriver(TestOVNMechanismDriverBase): network['network']['mtu'] = new_mtu fake_ctx = mock.MagicMock(current=network['network']) fake_ctx.plugin_context.session.is_active = False + external_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: const.TYPE_GENEVE, + ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: str(new_mtu), + } + self.nb_ovn.ls_get.return_value.execute.return_value = ( + mock.Mock(external_ids=external_ids)) self.mech_driver.update_network_postcommit(fake_ctx) diff --git a/neutron/tests/unit/services/ovn_l3/test_plugin.py b/neutron/tests/unit/services/ovn_l3/test_plugin.py index 5f09a53ecbd..b1bba71b44f 100644 --- a/neutron/tests/unit/services/ovn_l3/test_plugin.py +++ b/neutron/tests/unit/services/ovn_l3/test_plugin.py @@ -339,6 +339,12 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): 'neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.ovn_client.' 'OVNClient._get_router_gw_ports', return_value=self.fake_ext_gw_ports) + ext_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: constants.TYPE_GENEVE, + ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: 9000, + } + self.l3_inst._nb_ovn.ls_get.return_value.execute.return_value = ( + mock.Mock(external_ids=ext_ids)) def test__plugin_driver(self): # No valid mech drivers should raise an exception. @@ -744,6 +750,12 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): fake_network_vlan = self.fake_network fake_network_vlan[pnet.NETWORK_TYPE] = constants.TYPE_VLAN gn.return_value = fake_network_vlan + ext_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: constants.TYPE_VLAN, + ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: 1500, + } + self.l3_inst._nb_ovn.ls_get.return_value.execute.return_value = ( + mock.Mock(external_ids=ext_ids)) payload = self._create_payload_for_router_interface(router_id) self.ovn_drv._process_add_router_interface(resources.ROUTER_INTERFACE, @@ -1915,13 +1927,20 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase): ari.return_value = self.fake_router_interface_info grps.return_value = [interface_info] self.get_router.return_value = self.fake_router_with_ext_gw - network_attrs = {'id': 'prov-net', 'mtu': 1200} + mtu = 1200 + network_attrs = {'id': 'prov-net', 'mtu': mtu} prov_net = fake_resources.FakeNetwork.create_one_network( attrs=network_attrs).info() self.fake_router_port['device_owner'] = ( constants.DEVICE_OWNER_ROUTER_GW) gn.return_value = prov_net gns.return_value = [self.fake_network] + ext_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: constants.TYPE_GENEVE, + ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: mtu, + } + self.l3_inst._nb_ovn.ls_get.return_value.execute.return_value = ( + mock.Mock(external_ids=ext_ids)) payload = self._create_payload_for_router_interface(router_id) self.ovn_drv._process_add_router_interface(resources.ROUTER_INTERFACE, @@ -2119,6 +2138,12 @@ class OVNL3ExtrarouteTests(test_l3_gw.ExtGwModeIntTestCase, self.l3_inst._nb_ovn.db_get.return_value.execute.return_value = ext_ids self.l3_inst._nb_ovn.lookup.return_value = mock.Mock( external_ids=ext_ids) + ext_ids = { + ovn_const.OVN_NETTYPE_EXT_ID_KEY: constants.TYPE_GENEVE, + ovn_const.OVN_NETWORK_MTU_EXT_ID_KEY: 9000, + } + self.l3_inst._nb_ovn.ls_get.return_value.execute.return_value = ( + mock.Mock(external_ids=ext_ids)) # Note(dongj): According to bug #1657693, status of an unassociated # floating IP is set to DOWN. Revise expected_status to DOWN for related