From ef0ec21186d93eefbbb17543e861fef91bf4225c Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Thu, 1 Oct 2020 22:44:21 -0400 Subject: [PATCH] ovn: support max_tunid option from NB_Global This option is written by OVN and can be used to determine capacity of the cluster that may depend on e.g. tunnel types enabled for encapsulation. The option is new in 20.09 and may be absent in older releases. Hence grace handling of missing option. While this option is written by OVN regardless of encap types enabled, it is useful only when VXLAN is enabled in the cluster. In this case, due to limitations of the protocol header, the maximum number of segments supported is drastically reduced from what's common when Geneve is used. The patch that adds VXLAN support for OVN is at: I81c016ba9c91282d1bebb40a282077e14ce4bd6b Change-Id: I8ddd52aa958f7dd07fee5d11913a498d6ad4f34f --- .../drivers/ovn/mech_driver/mech_driver.py | 14 ++++++++ neutron/tests/unit/fake_resources.py | 1 + .../ovn/mech_driver/test_mech_driver.py | 32 +++++++++++++++++++ 3 files changed, 47 insertions(+) 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 0da02ebe9f4..0e8644c6fe2 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py @@ -409,7 +409,15 @@ class OVNMechanismDriver(api.MechanismDriver): const.TYPE_VXLAN, const.TYPE_VLAN]) + def _get_max_tunid(self): + try: + return int(self._nb_ovn.nb_global.options.get('max_tunid')) + except (ValueError, TypeError): + # max_tunid may be absent in older OVN versions, return None + pass + def _validate_network_segments(self, network_segments): + max_tunid = self._get_max_tunid() for network_segment in network_segments: network_type = network_segment['network_type'] segmentation_id = network_segment['segmentation_id'] @@ -424,6 +432,12 @@ class OVNMechanismDriver(api.MechanismDriver): if not self._is_network_type_supported(network_type): msg = _('Network type %s is not supported') % network_type raise n_exc.InvalidInput(error_message=msg) + if segmentation_id and max_tunid and segmentation_id > max_tunid: + m = ( + _('Segmentation ID should be lower or equal to %d') % + max_tunid + ) + raise n_exc.InvalidInput(error_message=m) def create_segment_provnet_port(self, resource, event, trigger, context, segment, payload=None): diff --git a/neutron/tests/unit/fake_resources.py b/neutron/tests/unit/fake_resources.py index 86157d31c2a..349c3b9a6bd 100644 --- a/neutron/tests/unit/fake_resources.py +++ b/neutron/tests/unit/fake_resources.py @@ -130,6 +130,7 @@ class FakeOvsdbNbOvnIdl(object): self.pg_del_ports = mock.Mock() self.lsp_get_up = mock.Mock() self.nb_global = mock.Mock() + self.nb_global.options.get.return_value = '100000' self.db_list_rows = mock.Mock() self.lsp_list = mock.MagicMock() self.db_find = mock.Mock() 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 0d005d68a7e..3aec319d626 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 @@ -155,6 +155,38 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase): self.mech_driver._create_neutron_pg_drop) self.assertEqual(2, m_ovsdb_api.get_port_group.call_count) + def test__get_max_tunid_no_key_set(self): + self.mech_driver._nb_ovn.nb_global.options.get.return_value = None + self.assertIsNone(self.mech_driver._get_max_tunid()) + + def test__get_max_tunid_wrong_key_value(self): + self.mech_driver._nb_ovn.nb_global.options.get.return_value = '11wrong' + self.assertIsNone(self.mech_driver._get_max_tunid()) + + def test__get_max_tunid_key_set(self): + self.mech_driver._nb_ovn.nb_global.options.get.return_value = '100' + self.assertEqual(100, self.mech_driver._get_max_tunid()) + + def _test__validate_network_segments_id_succeed(self, val): + segment = { + "network_type": const.TYPE_VXLAN, + "segmentation_id": val, + "physical_network": "physnet1", + } + self.mech_driver._nb_ovn.nb_global.options.get.return_value = '200' + self.mech_driver._validate_network_segments([segment]) + + def test__validate_network_segments_id_below_max_limit(self): + self._test__validate_network_segments_id_succeed(100) + + def test__validate_network_segments_id_eq_max_limit(self): + self._test__validate_network_segments_id_succeed(200) + + def test__validate_network_segments_id_above_max_limit(self): + self.assertRaises( + n_exc.InvalidInput, + self._test__validate_network_segments_id_succeed, 300) + @mock.patch.object(ovn_revision_numbers_db, 'bump_revision') def test__create_security_group(self, mock_bump): self.mech_driver._create_security_group(