From: sridhargaddam Date: Mon, 15 Dec 2014 11:11:15 +0000 (+0000) Subject: Fix neutron hang for IPv6 allocation pool update X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=b38f1bfa7b4f662182f552530b43301b214baa8d;p=openstack-build%2Fneutron-build.git Fix neutron hang for IPv6 allocation pool update While rebuilding IPAllocationPools, Neutron is using netaddr.iter_iprange (a generator that produces IPAddress objects). For an IPv6 subnet, this is a costly operation and is causing Neutron Server to hang. This patch addresses the issue by replacing netaddr.iter_iprange with netaddr.IPRange which provides the same functionality while calculating the IPSets. Closes-Bug: #1401751 Change-Id: I2287e5348aab82e39cf1b6e2884d08237a09b06d --- diff --git a/neutron/db/db_base_plugin_v2.py b/neutron/db/db_base_plugin_v2.py index 6f062fcaf..37ad8b758 100644 --- a/neutron/db/db_base_plugin_v2.py +++ b/neutron/db/db_base_plugin_v2.py @@ -268,8 +268,8 @@ class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2, for pool in pool_qry.filter_by(subnet_id=subnet['id']): # Create a set of all addresses in the pool - poolset = netaddr.IPSet(netaddr.iter_iprange(pool['first_ip'], - pool['last_ip'])) + poolset = netaddr.IPSet(netaddr.IPRange(pool['first_ip'], + pool['last_ip'])) # Use set difference to find free addresses in the pool available = poolset - allocations diff --git a/neutron/tests/unit/test_db_plugin.py b/neutron/tests/unit/test_db_plugin.py index f1f54c3a1..ac98d7d8a 100644 --- a/neutron/tests/unit/test_db_plugin.py +++ b/neutron/tests/unit/test_db_plugin.py @@ -4062,22 +4062,8 @@ class TestNeutronDbPluginV2(base.BaseTestCase): self.assertEqual(2, generate.call_count) rebuild.assert_called_once_with('c', 's') - def test_rebuild_availability_ranges(self): - pools = [{'id': 'a', - 'first_ip': '192.168.1.3', - 'last_ip': '192.168.1.10'}, - {'id': 'b', - 'first_ip': '192.168.1.100', - 'last_ip': '192.168.1.120'}] - - allocations = [{'ip_address': '192.168.1.3'}, - {'ip_address': '192.168.1.78'}, - {'ip_address': '192.168.1.7'}, - {'ip_address': '192.168.1.110'}, - {'ip_address': '192.168.1.11'}, - {'ip_address': '192.168.1.4'}, - {'ip_address': '192.168.1.111'}] - + def _validate_rebuild_availability_ranges(self, pools, allocations, + expected): ip_qry = mock.Mock() ip_qry.with_lockmode.return_value = ip_qry ip_qry.filter_by.return_value = allocations @@ -4103,11 +4089,61 @@ class TestNeutronDbPluginV2(base.BaseTestCase): actual = [[args[0].allocation_pool_id, args[0].first_ip, args[0].last_ip] for _name, args, _kwargs in context.session.add.mock_calls] + self.assertEqual(expected, actual) + + def test_rebuild_availability_ranges(self): + pools = [{'id': 'a', + 'first_ip': '192.168.1.3', + 'last_ip': '192.168.1.10'}, + {'id': 'b', + 'first_ip': '192.168.1.100', + 'last_ip': '192.168.1.120'}] + + allocations = [{'ip_address': '192.168.1.3'}, + {'ip_address': '192.168.1.78'}, + {'ip_address': '192.168.1.7'}, + {'ip_address': '192.168.1.110'}, + {'ip_address': '192.168.1.11'}, + {'ip_address': '192.168.1.4'}, + {'ip_address': '192.168.1.111'}] - self.assertEqual([['a', '192.168.1.5', '192.168.1.6'], - ['a', '192.168.1.8', '192.168.1.10'], - ['b', '192.168.1.100', '192.168.1.109'], - ['b', '192.168.1.112', '192.168.1.120']], actual) + expected = [['a', '192.168.1.5', '192.168.1.6'], + ['a', '192.168.1.8', '192.168.1.10'], + ['b', '192.168.1.100', '192.168.1.109'], + ['b', '192.168.1.112', '192.168.1.120']] + + self._validate_rebuild_availability_ranges(pools, allocations, + expected) + + def test_rebuild_ipv6_availability_ranges(self): + pools = [{'id': 'a', + 'first_ip': '2001::1', + 'last_ip': '2001::50'}, + {'id': 'b', + 'first_ip': '2001::100', + 'last_ip': '2001::ffff:ffff:ffff:fffe'}] + + allocations = [{'ip_address': '2001::10'}, + {'ip_address': '2001::45'}, + {'ip_address': '2001::60'}, + {'ip_address': '2001::111'}, + {'ip_address': '2001::200'}, + {'ip_address': '2001::ffff:ffff:ffff:ff10'}, + {'ip_address': '2001::ffff:ffff:ffff:f2f0'}] + + expected = [['a', '2001::1', '2001::f'], + ['a', '2001::11', '2001::44'], + ['a', '2001::46', '2001::50'], + ['b', '2001::100', '2001::110'], + ['b', '2001::112', '2001::1ff'], + ['b', '2001::201', '2001::ffff:ffff:ffff:f2ef'], + ['b', '2001::ffff:ffff:ffff:f2f1', + '2001::ffff:ffff:ffff:ff0f'], + ['b', '2001::ffff:ffff:ffff:ff11', + '2001::ffff:ffff:ffff:fffe']] + + self._validate_rebuild_availability_ranges(pools, allocations, + expected) class NeutronDbPluginV2AsMixinTestCase(testlib_api.SqlTestCase):