Skip to content

Commit ef7740e

Browse files
committed
Fix tunnel network detection to use tunnel type driver ranges
The ``_is_tunnel_project_network`` method in ``DNSExtensionDriverML2`` was only checking the static tunnel ranges from ml2_conf.ini, ignoring the dynamic ranges provided by the ``network-segment-range service`` plugin. When segment ranges are managed via the API, external DNS eligibility for tenant tunnel networks could be wrong. Update the method to use the ML2 tunnel type driver's ``get_network_segment_ranges()``, which handles both static configuration and DB-based ranges when the network-segment-range plugin is enabled. Conflicts: neutron/plugins/ml2/extensions/dns_integration.py Closes-Bug: #2154266 Related-Bug: #2140291 Assisted-By: Cursor Composer 2.5 Signed-off-by: Rodolfo Alonso Hernandez <ralonsoh@redhat.com> Change-Id: I5d96efa626d18b7589cf2563fdac3a8d399a69a8 (cherry picked from commit 6913303) (cherry picked from commit 1941988) (cherry picked from commit d04e845)
1 parent c6c4e14 commit ef7740e

2 files changed

Lines changed: 104 additions & 17 deletions

File tree

neutron/plugins/ml2/extensions/dns_integration.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -351,35 +351,42 @@ class DNSExtensionDriverML2(DNSExtensionDriver):
351351
def __init__(self):
352352
super().__init__()
353353
self._vlan_driver = None
354+
self._tunnel_drivers = {}
354355
self._plugin = None
355356

356357
def initialize(self):
357358
LOG.info("DNSExtensionDriverML2 initialization complete")
358359

360+
@property
361+
def plugin(self):
362+
if not self._plugin:
363+
self._plugin = directory.get_plugin()
364+
return self._plugin
365+
359366
@property
360367
def vlan_driver(self):
361368
if not self._vlan_driver:
362-
if not self._plugin:
363-
self._plugin = directory.get_plugin()
364-
self._vlan_driver = self._plugin.type_manager.drivers.get(
369+
self._vlan_driver = self.plugin.type_manager.drivers.get(
365370
lib_const.TYPE_VLAN)
366371
return self._vlan_driver
367372

368-
def _is_tunnel_tenant_network(self, provider_net):
369-
if provider_net['network_type'] == lib_const.TYPE_GENEVE:
370-
tunnel_ranges = cfg.CONF.ml2_type_geneve.vni_ranges
371-
elif provider_net['network_type'] == lib_const.TYPE_VXLAN:
372-
tunnel_ranges = cfg.CONF.ml2_type_vxlan.vni_ranges
373-
else:
374-
tunnel_ranges = cfg.CONF.ml2_type_gre.tunnel_id_ranges
373+
def get_tunnel_driver(self, network_type):
374+
if network_type not in self._tunnel_drivers:
375+
self._tunnel_drivers[network_type] = (
376+
self.plugin.type_manager.drivers.get(network_type))
377+
return self._tunnel_drivers[network_type]
375378

379+
def _is_tunnel_project_network(self, provider_net):
380+
network_type = provider_net['network_type']
381+
tunnel_driver = self.get_tunnel_driver(network_type)
382+
if not tunnel_driver:
383+
return False
384+
tunnel_ranges = tunnel_driver.obj.get_network_segment_ranges()
385+
if not tunnel_ranges:
386+
return False
376387
segmentation_id = int(provider_net['segmentation_id'])
377-
for entry in tunnel_ranges:
378-
entry = entry.strip()
379-
tun_min, tun_max = entry.split(':')
380-
tun_min = tun_min.strip()
381-
tun_max = tun_max.strip()
382-
return int(tun_min) <= segmentation_id <= int(tun_max)
388+
return any(tun_min <= segmentation_id <= tun_max
389+
for tun_min, tun_max in tunnel_ranges)
383390

384391
def _is_vlan_tenant_network(self, provider_net):
385392
if not self.vlan_driver:
@@ -414,7 +421,7 @@ def external_dns_not_needed(self, context, network, subnets):
414421
if provider_net['network_type'] in [
415422
lib_const.TYPE_GRE, lib_const.TYPE_VXLAN,
416423
lib_const.TYPE_GENEVE]:
417-
return self._is_tunnel_tenant_network(provider_net)
424+
return self._is_tunnel_project_network(provider_net)
418425
return True
419426

420427

neutron/tests/unit/plugins/ml2/extensions/test_dns_integration.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,86 @@ def test__is_vlan_tenant_network_no_vlan_driver(self):
864864
}
865865
self.assertFalse(self.driver._is_vlan_tenant_network(provider_net))
866866

867+
def _mock_tunnel_driver(self, network_type, ranges):
868+
mock_tunnel_driver = mock.Mock()
869+
mock_tunnel_driver.obj.get_network_segment_ranges.return_value = ranges
870+
return mock.patch.object(
871+
self.driver, 'get_tunnel_driver',
872+
return_value=mock_tunnel_driver)
873+
874+
def test__is_tunnel_project_network_with_multiple_ranges(self):
875+
with self._mock_tunnel_driver(
876+
constants.TYPE_VXLAN, [(100, 200), (300, 400)]):
877+
provider_net_in_range = {
878+
'network_type': constants.TYPE_VXLAN,
879+
'segmentation_id': 150,
880+
}
881+
self.assertTrue(
882+
self.driver._is_tunnel_project_network(provider_net_in_range))
883+
884+
provider_net_between_ranges = {
885+
'network_type': constants.TYPE_VXLAN,
886+
'segmentation_id': 250,
887+
}
888+
self.assertFalse(self.driver._is_tunnel_project_network(
889+
provider_net_between_ranges))
890+
891+
provider_net_second_range = {
892+
'network_type': constants.TYPE_VXLAN,
893+
'segmentation_id': 350,
894+
}
895+
self.assertTrue(self.driver._is_tunnel_project_network(
896+
provider_net_second_range))
897+
898+
def test__is_tunnel_project_network_boundary_values(self):
899+
with self._mock_tunnel_driver(constants.TYPE_GENEVE, [(100, 200)]):
900+
provider_net_min = {
901+
'network_type': constants.TYPE_GENEVE,
902+
'segmentation_id': 100,
903+
}
904+
self.assertTrue(
905+
self.driver._is_tunnel_project_network(provider_net_min))
906+
907+
provider_net_max = {
908+
'network_type': constants.TYPE_GENEVE,
909+
'segmentation_id': 200,
910+
}
911+
self.assertTrue(
912+
self.driver._is_tunnel_project_network(provider_net_max))
913+
914+
provider_net_below = {
915+
'network_type': constants.TYPE_GENEVE,
916+
'segmentation_id': 99,
917+
}
918+
self.assertFalse(
919+
self.driver._is_tunnel_project_network(provider_net_below))
920+
921+
provider_net_above = {
922+
'network_type': constants.TYPE_GENEVE,
923+
'segmentation_id': 201,
924+
}
925+
self.assertFalse(
926+
self.driver._is_tunnel_project_network(provider_net_above))
927+
928+
def test__is_tunnel_project_network_empty_ranges(self):
929+
with self._mock_tunnel_driver(constants.TYPE_GRE, []):
930+
provider_net = {
931+
'network_type': constants.TYPE_GRE,
932+
'segmentation_id': 100,
933+
}
934+
self.assertFalse(
935+
self.driver._is_tunnel_project_network(provider_net))
936+
937+
def test__is_tunnel_project_network_no_tunnel_driver(self):
938+
with mock.patch.object(
939+
self.driver, 'get_tunnel_driver', return_value=None):
940+
provider_net = {
941+
'network_type': constants.TYPE_VXLAN,
942+
'segmentation_id': 100,
943+
}
944+
self.assertFalse(
945+
self.driver._is_tunnel_project_network(provider_net))
946+
867947

868948
class TestDesignateClientKeystoneV3(testtools.TestCase):
869949
"""Test case for designate clients """

0 commit comments

Comments
 (0)