From e8603512c4e7aa976ad29dfaf609505267b8c870 Mon Sep 17 00:00:00 2001 From: Andrew Boik Date: Fri, 27 Mar 2015 16:21:29 -0400 Subject: [PATCH] Consider all address scopes in init_l3 Currently init_l3 retrieves the list of global addresses from the kernel on a specific device in a network namespace. If any of the addresses are not in the ip_cidrs argument to init_l3, they will be deleted. The problem with only listing global addresses is that if a site-local or link-local address is added during a subnet-create, and the user wishes to later delete the address, init_l3 will never consider that address for deletion. To fix this, init_l3 should not limit its scope when listing addresses on an interface. It should, however, ignore the default IPv6 link-local address assigned by the operating system as this address is not known to Neutron and should not be deleted. Change-Id: I3d7a3e318e32acae3836c51e4e2e95ae756e645b Closes-Bug: #1437499 --- neutron/agent/linux/interface.py | 9 ++++++--- neutron/tests/unit/agent/linux/test_interface.py | 13 +++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py index 99654cfc8..0f5741b97 100644 --- a/neutron/agent/linux/interface.py +++ b/neutron/agent/linux/interface.py @@ -89,9 +89,12 @@ class LinuxInterfaceDriver(object): """ device = ip_lib.IPDevice(device_name, namespace=namespace) - previous = set() - for address in device.addr.list(scope='global', filters=['permanent']): - previous.add(address['cidr']) + # The LLA generated by the operating system is not known to + # Neutron, so it would be deleted if we added it to the 'previous' + # list here + default_ipv6_lla = ip_lib.get_ipv6_lladdr(device.link.address) + previous = {addr['cidr'] for addr in device.addr.list( + filters=['permanent'])} - {default_ipv6_lla} # add new addresses for ip_cidr in ip_cidrs: diff --git a/neutron/tests/unit/agent/linux/test_interface.py b/neutron/tests/unit/agent/linux/test_interface.py index df605eb57..bae30a6a9 100644 --- a/neutron/tests/unit/agent/linux/test_interface.py +++ b/neutron/tests/unit/agent/linux/test_interface.py @@ -70,6 +70,11 @@ class TestBase(base.BaseTestCase): class TestABCDriver(TestBase): + def setUp(self): + super(TestABCDriver, self).setUp() + mock_link_addr = mock.PropertyMock(return_value='aa:bb:cc:dd:ee:ff') + type(self.ip_dev().link).address = mock_link_addr + def test_get_device_name(self): bc = BaseChild(self.conf) device_name = bc.get_device_name(FakePort()) @@ -87,7 +92,7 @@ class TestABCDriver(TestBase): extra_subnets=[{'cidr': '172.20.0.0/24'}]) self.ip_dev.assert_has_calls( [mock.call('tap0', namespace=ns), - mock.call().addr.list(scope='global', filters=['permanent']), + mock.call().addr.list(filters=['permanent']), mock.call().addr.add('192.168.1.2/24'), mock.call().addr.delete('172.16.77.240/24'), mock.call().route.list_onlink_routes(constants.IP_VERSION_4), @@ -119,7 +124,7 @@ class TestABCDriver(TestBase): preserve_ips=['192.168.1.3/32']) self.ip_dev.assert_has_calls( [mock.call('tap0', namespace=ns), - mock.call().addr.list(scope='global', filters=['permanent']), + mock.call().addr.list(filters=['permanent']), mock.call().addr.add('192.168.1.2/24')]) self.assertFalse(self.ip_dev().addr.delete.called) @@ -140,7 +145,7 @@ class TestABCDriver(TestBase): bc.init_l3('tap0', [new_cidr], **kwargs) expected_calls = ( [mock.call('tap0', namespace=ns), - mock.call().addr.list(scope='global', filters=['permanent']), + mock.call().addr.list(filters=['permanent']), mock.call().addr.add('2001:db8:a::124/64'), mock.call().addr.delete('2001:db8:a::123/64')]) if include_gw_ip: @@ -172,7 +177,7 @@ class TestABCDriver(TestBase): extra_subnets=[{'cidr': '172.20.0.0/24'}]) self.ip_dev.assert_has_calls( [mock.call('tap0', namespace=ns), - mock.call().addr.list(scope='global', filters=['permanent']), + mock.call().addr.list(filters=['permanent']), mock.call().addr.add('192.168.1.2/24'), mock.call().addr.add('2001:db8:a::124/64'), mock.call().addr.delete('172.16.77.240/24'), -- 2.45.2