Teach DHCP Agent about DVR router interfaces

When DVR is enabled and enable_isolated_metadata=True,
the DHCP agent should only inject a metadata host route
when there is no port with the gateway IP address configured
on the subnet.  Add a check for DEVICE_OWNER_DVR_INTERFACE
when we look at each port's device_owner field, otherwise
it will always add this route to the opts file when DVR
is enabled.

Change-Id: I3ff3bb85105b8215b36535983016d8c0ff3d8cb7
Closes-bug: #1377307
This commit is contained in:
Brian Haley 2014-10-03 17:32:01 -04:00
parent 161aa37bca
commit 88d572e4d9
3 changed files with 79 additions and 7 deletions

View File

@ -730,7 +730,8 @@ class Dnsmasq(DhcpLocalProcess):
subnets = dict((subnet.id, subnet) for subnet in network.subnets) subnets = dict((subnet.id, subnet) for subnet in network.subnets)
for port in network.ports: for port in network.ports:
if port.device_owner != constants.DEVICE_OWNER_ROUTER_INTF: if port.device_owner not in (constants.DEVICE_OWNER_ROUTER_INTF,
constants.DEVICE_OWNER_DVR_INTERFACE):
continue continue
for alloc in port.fixed_ips: for alloc in port.fixed_ips:
if subnets[alloc.subnet_id].gateway_ip == alloc.ip_address: if subnets[alloc.subnet_id].gateway_ip == alloc.ip_address:

View File

@ -72,6 +72,8 @@ fake_meta_subnet = dhcp.DictModel(dict(id='bbbbbbbb-1111-2222-bbbbbbbbbbbb',
fake_fixed_ip1 = dhcp.DictModel(dict(id='', subnet_id=fake_subnet1.id, fake_fixed_ip1 = dhcp.DictModel(dict(id='', subnet_id=fake_subnet1.id,
ip_address='172.9.9.9')) ip_address='172.9.9.9'))
fake_fixed_ip2 = dhcp.DictModel(dict(id='', subnet_id=fake_subnet1.id,
ip_address='172.9.9.10'))
fake_meta_fixed_ip = dhcp.DictModel(dict(id='', subnet=fake_meta_subnet, fake_meta_fixed_ip = dhcp.DictModel(dict(id='', subnet=fake_meta_subnet,
ip_address='169.254.169.254')) ip_address='169.254.169.254'))
fake_allocation_pool_subnet1 = dhcp.DictModel(dict(id='', start='172.9.9.2', fake_allocation_pool_subnet1 = dhcp.DictModel(dict(id='', start='172.9.9.2',
@ -89,7 +91,7 @@ fake_port2 = dhcp.DictModel(dict(id='12345678-1234-aaaa-123456789000',
device_owner='', device_owner='',
mac_address='aa:bb:cc:dd:ee:99', mac_address='aa:bb:cc:dd:ee:99',
network_id='12345678-1234-5678-1234567890ab', network_id='12345678-1234-5678-1234567890ab',
fixed_ips=[])) fixed_ips=[fake_fixed_ip2]))
fake_meta_port = dhcp.DictModel(dict(id='12345678-1234-aaaa-1234567890ab', fake_meta_port = dhcp.DictModel(dict(id='12345678-1234-aaaa-1234567890ab',
mac_address='aa:bb:cc:dd:ee:ff', mac_address='aa:bb:cc:dd:ee:ff',
@ -98,6 +100,13 @@ fake_meta_port = dhcp.DictModel(dict(id='12345678-1234-aaaa-1234567890ab',
device_id='forzanapoli', device_id='forzanapoli',
fixed_ips=[fake_meta_fixed_ip])) fixed_ips=[fake_meta_fixed_ip]))
fake_dist_port = dhcp.DictModel(dict(id='12345678-1234-aaaa-1234567890ab',
mac_address='aa:bb:cc:dd:ee:ff',
network_id='12345678-1234-5678-1234567890ab',
device_owner=const.DEVICE_OWNER_DVR_INTERFACE,
device_id='forzanapoli',
fixed_ips=[fake_meta_fixed_ip]))
fake_network = dhcp.NetModel(True, dict(id='12345678-1234-5678-1234567890ab', fake_network = dhcp.NetModel(True, dict(id='12345678-1234-5678-1234567890ab',
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa', tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa',
admin_state_up=True, admin_state_up=True,
@ -112,6 +121,14 @@ isolated_network = dhcp.NetModel(
subnets=[fake_subnet1], subnets=[fake_subnet1],
ports=[fake_port1])) ports=[fake_port1]))
nonisolated_dist_network = dhcp.NetModel(
True, dict(
id='12345678-1234-5678-1234567890ab',
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa',
admin_state_up=True,
subnets=[fake_subnet1],
ports=[fake_port1, fake_port2]))
empty_network = dhcp.NetModel( empty_network = dhcp.NetModel(
True, dict( True, dict(
id='12345678-1234-5678-1234567890ab', id='12345678-1234-5678-1234567890ab',
@ -127,6 +144,13 @@ fake_meta_network = dhcp.NetModel(
subnets=[fake_meta_subnet], subnets=[fake_meta_subnet],
ports=[fake_meta_port])) ports=[fake_meta_port]))
fake_dist_network = dhcp.NetModel(
True, dict(id='12345678-1234-5678-1234567890ab',
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa',
admin_state_up=True,
subnets=[fake_meta_subnet],
ports=[fake_meta_port, fake_dist_port]))
fake_down_network = dhcp.NetModel( fake_down_network = dhcp.NetModel(
True, dict(id='12345678-dddd-dddd-1234567890ab', True, dict(id='12345678-dddd-dddd-1234567890ab',
tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa', tenant_id='aaaaaaaa-aaaa-aaaa-aaaaaaaaaaaa',
@ -540,13 +564,26 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
def test_enable_dhcp_helper_enable_metadata_nonisolated_network(self): def test_enable_dhcp_helper_enable_metadata_nonisolated_network(self):
nonisolated_network = copy.deepcopy(isolated_network) nonisolated_network = copy.deepcopy(isolated_network)
nonisolated_network.ports[0].device_owner = "network:router_interface" nonisolated_network.ports[0].device_owner = (
const.DEVICE_OWNER_ROUTER_INTF)
nonisolated_network.ports[0].fixed_ips[0].ip_address = '172.9.9.1' nonisolated_network.ports[0].fixed_ips[0].ip_address = '172.9.9.1'
self._enable_dhcp_helper(nonisolated_network, self._enable_dhcp_helper(nonisolated_network,
enable_isolated_metadata=True, enable_isolated_metadata=True,
is_isolated_network=False) is_isolated_network=False)
def test_enable_dhcp_helper_enable_metadata_nonisolated_dist_network(self):
nonisolated_dist_network.ports[0].device_owner = (
const.DEVICE_OWNER_ROUTER_INTF)
nonisolated_dist_network.ports[0].fixed_ips[0].ip_address = '172.9.9.1'
nonisolated_dist_network.ports[1].device_owner = (
const.DEVICE_OWNER_DVR_INTERFACE)
nonisolated_dist_network.ports[1].fixed_ips[0].ip_address = '172.9.9.1'
self._enable_dhcp_helper(nonisolated_dist_network,
enable_isolated_metadata=True,
is_isolated_network=False)
def test_enable_dhcp_helper_enable_metadata_empty_network(self): def test_enable_dhcp_helper_enable_metadata_empty_network(self):
self._enable_dhcp_helper(empty_network, self._enable_dhcp_helper(empty_network,
enable_isolated_metadata=True, enable_isolated_metadata=True,
@ -685,7 +722,7 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
mock.call().disable() mock.call().disable()
]) ])
def test_enable_isolated_metadata_proxy_with_metadata_network(self): def _test_metadata_network(self, network):
cfg.CONF.set_override('enable_metadata_network', True) cfg.CONF.set_override('enable_metadata_network', True)
cfg.CONF.set_override('debug', True) cfg.CONF.set_override('debug', True)
cfg.CONF.set_override('verbose', False) cfg.CONF.set_override('verbose', False)
@ -695,7 +732,7 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
# Ensure the mock is restored if this test fail # Ensure the mock is restored if this test fail
try: try:
with mock.patch(class_path) as ip_wrapper: with mock.patch(class_path) as ip_wrapper:
self.dhcp.enable_isolated_metadata_proxy(fake_meta_network) self.dhcp.enable_isolated_metadata_proxy(network)
ip_wrapper.assert_has_calls([mock.call( ip_wrapper.assert_has_calls([mock.call(
'sudo', 'sudo',
'qdhcp-12345678-1234-5678-1234567890ab'), 'qdhcp-12345678-1234-5678-1234567890ab'),
@ -708,11 +745,17 @@ class TestDhcpAgentEventHandler(base.BaseTestCase):
mock.ANY, mock.ANY,
'--debug', '--debug',
('--log-file=neutron-ns-metadata-proxy-%s.log' % ('--log-file=neutron-ns-metadata-proxy-%s.log' %
fake_meta_network.id)], addl_env=None) network.id)], addl_env=None)
]) ])
finally: finally:
self.external_process_p.start() self.external_process_p.start()
def test_enable_isolated_metadata_proxy_with_metadata_network(self):
self._test_metadata_network(fake_meta_network)
def test_enable_isolated_metadata_proxy_with_dist_network(self):
self._test_metadata_network(fake_dist_network)
def test_network_create_end(self): def test_network_create_end(self):
payload = dict(network=dict(id=fake_network.id)) payload = dict(network=dict(id=fake_network.id))

View File

@ -130,8 +130,9 @@ class FakeRouterPort:
'dddddddd-dddd-dddd-dddd-dddddddddddd')] 'dddddddd-dddd-dddd-dddd-dddddddddddd')]
mac_address = '00:00:0f:rr:rr:rr' mac_address = '00:00:0f:rr:rr:rr'
def __init__(self): def __init__(self, dev_owner=constants.DEVICE_OWNER_ROUTER_INTF):
self.extra_dhcp_opts = [] self.extra_dhcp_opts = []
self.device_owner = dev_owner
class FakePortMultipleAgents1: class FakePortMultipleAgents1:
@ -341,6 +342,13 @@ class FakeV4NetworkNoRouter:
ports = [FakePort1()] ports = [FakePort1()]
class FakeV4NetworkDistRouter:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4Subnet()]
ports = [FakePort1(),
FakeRouterPort(dev_owner=constants.DEVICE_OWNER_DVR_INTERFACE)]
class FakeDualV4Pxe3Ports: class FakeDualV4Pxe3Ports:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc' id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4Subnet(), FakeV4SubnetNoDHCP()] subnets = [FakeV4Subnet(), FakeV4SubnetNoDHCP()]
@ -962,6 +970,26 @@ tag:tag0,option:router""".lstrip()
self.safe.assert_called_once_with('/foo/opts', expected) self.safe.assert_called_once_with('/foo/opts', expected)
def test_output_opts_file_dist_neutron_router_on_subnet(self):
expected = (
'tag:tag0,option:dns-server,8.8.8.8\n'
'tag:tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1,'
'0.0.0.0/0,192.168.0.1\n'
'tag:tag0,249,20.0.0.1/24,20.0.0.1,0.0.0.0/0,192.168.0.1\n'
'tag:tag0,option:router,192.168.0.1').lstrip()
with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
conf_fn.return_value = '/foo/opts'
dm = dhcp.Dnsmasq(self.conf, FakeV4NetworkDistRouter(),
version=dhcp.Dnsmasq.MINIMUM_VERSION)
with mock.patch.object(dm, '_make_subnet_interface_ip_map') as ipm:
ipm.return_value = {FakeV4Subnet.id: '192.168.0.1'}
dm._output_opts_file()
self.assertTrue(ipm.called)
self.safe.assert_called_once_with('/foo/opts', expected)
def test_output_opts_file_pxe_2port_1net(self): def test_output_opts_file_pxe_2port_1net(self):
expected = ( expected = (
'tag:tag0,option:dns-server,8.8.8.8\n' 'tag:tag0,option:dns-server,8.8.8.8\n'