From 30d6c8e7d4cde542942719f0ca46fe05ac262791 Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Mon, 26 Nov 2012 17:07:12 +0000 Subject: [PATCH] Fixes order of route entries. Fixes bug 1083238 This patch makes sure that a route entry for dnsmasq is placed first before any others (for example the l3-agent one). This makes DHCP work when network namespaces are disabled. Change-Id: I241a8e30127d614f7582e10d999521f6486e5255 --- quantum/agent/dhcp_agent.py | 5 ++++ quantum/agent/linux/ip_lib.py | 40 +++++++++++++++++++++++++ quantum/tests/unit/test_linux_ip_lib.py | 35 ++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/quantum/agent/dhcp_agent.py b/quantum/agent/dhcp_agent.py index 773b90fcc..ffa8d1043 100644 --- a/quantum/agent/dhcp_agent.py +++ b/quantum/agent/dhcp_agent.py @@ -443,6 +443,11 @@ class DeviceManager(object): self.driver.init_l3(interface_name, ip_cidrs, namespace=namespace) + # ensure that the dhcp interface is first in the list + if namespace is None: + device = ip_lib.IPDevice(interface_name, self.conf.root_helper) + device.route.pullup_route(interface_name) + return interface_name def destroy(self, network, device_name): diff --git a/quantum/agent/linux/ip_lib.py b/quantum/agent/linux/ip_lib.py index 510dcec61..78157d39e 100644 --- a/quantum/agent/linux/ip_lib.py +++ b/quantum/agent/linux/ip_lib.py @@ -327,6 +327,46 @@ class IpRouteCommand(IpDeviceCommandBase): return retval + def pullup_route(self, interface_name): + """ + Ensures that the route entry for the interface is before all + others on the same subnet. + """ + device_list = [] + device_route_list_lines = self._run('list', 'proto', 'kernel', + 'dev', interface_name).split('\n') + for device_route_line in device_route_list_lines: + try: + subnet = device_route_line.split()[0] + except: + continue + subnet_route_list_lines = self._run('list', 'proto', 'kernel', + 'match', subnet).split('\n') + for subnet_route_line in subnet_route_list_lines: + i = iter(subnet_route_line.split()) + while(i.next() != 'dev'): + pass + device = i.next() + try: + while(i.next() != 'src'): + pass + src = i.next() + except: + src = '' + if device != interface_name: + device_list.append((device, src)) + else: + break + + for (device, src) in device_list: + self._as_root('del', subnet, 'dev', device) + if (src != ''): + self._as_root('append', subnet, 'proto', 'kernel', + 'src', src, 'dev', device) + else: + self._as_root('append', subnet, 'proto', 'kernel', + 'dev', device) + class IpNetnsCommand(IpCommandBase): COMMAND = 'netns' diff --git a/quantum/tests/unit/test_linux_ip_lib.py b/quantum/tests/unit/test_linux_ip_lib.py index c7f96918a..502c0ca88 100644 --- a/quantum/tests/unit/test_linux_ip_lib.py +++ b/quantum/tests/unit/test_linux_ip_lib.py @@ -72,6 +72,13 @@ GATEWAY_SAMPLE4 = (""" default via 10.35.19.254 """) +DEVICE_ROUTE_SAMPLE = ("10.0.0.0/24 scope link src 10.0.0.2") + +SUBNET_SAMPLE1 = ("10.0.0.0/24 dev qr-23380d11-d2 scope link src 10.0.0.1\n" + "10.0.0.0/24 dev tap1d7888a7-10 scope link src 10.0.0.2") +SUBNET_SAMPLE2 = ("10.0.0.0/24 dev tap1d7888a7-10 scope link src 10.0.0.2\n" + "10.0.0.0/24 dev qr-23380d11-d2 scope link src 10.0.0.1") + class TestSubProcessBase(unittest.TestCase): def setUp(self): @@ -543,6 +550,34 @@ class TestIpRouteCommand(TestIPCmdBase): self.assertEquals(self.route_cmd.get_gateway(), test_case['expected']) + def test_pullup_route(self): + # interface is not the first in the list - requires + # deleting and creating existing entries + output = [DEVICE_ROUTE_SAMPLE, SUBNET_SAMPLE1] + + def pullup_side_effect(self, *args): + result = output.pop(0) + return result + + self.parent._run = mock.Mock(side_effect=pullup_side_effect) + self.route_cmd.pullup_route('tap1d7888a7-10') + self._assert_sudo([], ('del', '10.0.0.0/24', 'dev', 'qr-23380d11-d2')) + self._assert_sudo([], ('append', '10.0.0.0/24', 'proto', 'kernel', + 'src', '10.0.0.1', 'dev', 'qr-23380d11-d2')) + + def test_pullup_route_first(self): + # interface is first in the list - no changes + output = [DEVICE_ROUTE_SAMPLE, SUBNET_SAMPLE2] + + def pullup_side_effect(self, *args): + result = output.pop(0) + return result + + self.parent._run = mock.Mock(side_effect=pullup_side_effect) + self.route_cmd.pullup_route('tap1d7888a7-10') + # Check two calls - device get and subnet get + self.assertEqual(len(self.parent._run.mock_calls), 2) + class TestIpNetnsCommand(TestIPCmdBase): def setUp(self): -- 2.45.2