Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Gary Kotton committed Nov 28, 2012
1 parent abb2bd3 commit aeabb42
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
5 changes: 5 additions & 0 deletions quantum/agent/dhcp_agent.py
Expand Up @@ -444,6 +444,11 @@ def setup(self, network, reuse_existing=False):
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):
Expand Down
40 changes: 40 additions & 0 deletions quantum/agent/linux/ip_lib.py
Expand Up @@ -327,6 +327,46 @@ def get_gateway(self, scope=None, filters=None):

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'
Expand Down
35 changes: 35 additions & 0 deletions quantum/tests/unit/test_linux_ip_lib.py
Expand Up @@ -72,6 +72,13 @@
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):
Expand Down Expand Up @@ -543,6 +550,34 @@ def test_get_gateway(self):
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):
Expand Down

0 comments on commit aeabb42

Please sign in to comment.