Only add "on-link" routes for L2 adjacent subnets

When multiple subnets exist on a single network, the
DHCP agent adds on-link routes for all of them since
they are in the same L2 network.  If either subnet
has a segment_id it can only be considered as on-link
if they match, else we should not include a subnet
route.

These extra routes are optional anyways according to
RFC 3442, but were added for the use case when all of
the subnets are considered adjacent, which allows
instances to bypass the router and communicate directly.

Closes-Bug: #1668145
Change-Id: Iae889e9226a61059cd4f3d37fbe48d013b7a3482
Implements: blueprint tripleo-routed-networks-deployment
This commit is contained in:
Harald Jensas 2017-02-25 11:05:22 +01:00 committed by Brian Haley
parent ea27e1aa1e
commit 7231692459
2 changed files with 91 additions and 1 deletions

View File

@ -917,7 +917,8 @@ class Dnsmasq(DhcpLocalProcess):
host_routes.extend(["%s,0.0.0.0" % (s.cidr) for s in
self.network.subnets
if (s.ip_version == 4 and
s.cidr != subnet.cidr)])
s.cidr != subnet.cidr and
s.segment_id == subnet.segment_id)])
if host_routes:
if gateway:

View File

@ -316,6 +316,20 @@ class FakeRouterPort2(object):
self.extra_dhcp_opts = []
class FakeRouterPortSegmentID(object):
def __init__(self):
self.id = 'qqqqqqqq-qqqq-qqqq-qqqq-qqqqqqqqqqqq'
self.admin_state_up = True
self.device_owner = constants.DEVICE_OWNER_ROUTER_INTF
self.fixed_ips = [
FakeIPAllocation('192.168.2.1',
'iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii')]
self.dns_assignment = [FakeDNSAssignment('192.168.2.1')]
self.mac_address = '00:00:0f:rr:rr:r3'
self.device_id = 'fake_router_port3'
self.extra_dhcp_opts = []
class FakePortMultipleAgents1(object):
def __init__(self):
self.id = 'rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr'
@ -371,6 +385,7 @@ class FakeV4Subnet(Dictable):
self.enable_dhcp = True
self.host_routes = [FakeV4HostRoute()]
self.dns_nameservers = ['8.8.8.8']
self.segment_id = None
class FakeV4Subnet2(FakeV4Subnet):
@ -381,6 +396,16 @@ class FakeV4Subnet2(FakeV4Subnet):
self.host_routes = []
class FakeV4SubnetSegmentID(FakeV4Subnet):
def __init__(self):
super(FakeV4SubnetSegmentID, self).__init__()
self.id = 'iiiiiiii-iiii-iiii-iiii-iiiiiiiiiiii'
self.cidr = '192.168.2.0/24'
self.gateway_ip = '192.168.2.1'
self.host_routes = []
self.segment_id = 1
class FakeV4MetadataSubnet(FakeV4Subnet):
def __init__(self):
super(FakeV4MetadataSubnet, self).__init__()
@ -474,6 +499,7 @@ class FakeV4SubnetNoDHCP(object):
self.enable_dhcp = False
self.host_routes = []
self.dns_nameservers = []
self.segment_id = None
class FakeV6SubnetDHCPStateful(Dictable):
@ -653,6 +679,24 @@ class FakeDualNetworkDualDHCP(object):
self.namespace = 'qdhcp-ns'
class FakeDualNetworkDualDHCPOnLinkSubnetRoutesDisabled(object):
def __init__(self):
self.id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
self.subnets = [FakeV4Subnet(), FakeV4SubnetSegmentID()]
self.ports = [FakePort1(), FakeRouterPort(), FakeRouterPortSegmentID()]
self.namespace = 'qdhcp-ns'
class FakeDualNetworkTriDHCPOneOnLinkSubnetRoute(object):
def __init__(self):
self.id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
self.subnets = [FakeV4Subnet(), FakeV4Subnet2(),
FakeV4SubnetSegmentID()]
self.ports = [FakePort1(), FakeRouterPort(), FakeRouterPort2(),
FakeRouterPortSegmentID()]
self.namespace = 'qdhcp-ns'
class FakeV4NoGatewayNetwork(object):
def __init__(self):
self.id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
@ -1424,6 +1468,51 @@ class TestDnsmasq(TestBase):
self._test_output_opts_file(expected, FakeDualNetworkDualDHCP())
def test_output_opts_file_dual_dhcp_rfc3442_no_on_link_subnet_routes(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,'
'169.254.169.254/32,192.168.0.1,0.0.0.0/0,192.168.0.1\n'
'tag:tag0,249,20.0.0.1/24,20.0.0.1,'
'169.254.169.254/32,192.168.0.1,0.0.0.0/0,192.168.0.1\n'
'tag:tag0,option:router,192.168.0.1\n'
'tag:tag1,option:dns-server,8.8.8.8\n'
'tag:tag1,option:classless-static-route,'
'169.254.169.254/32,192.168.2.1,0.0.0.0/0,192.168.2.1\n'
'tag:tag1,249,169.254.169.254/32,192.168.2.1,'
'0.0.0.0/0,192.168.2.1\n'
'tag:tag1,option:router,192.168.2.1').lstrip()
self._test_output_opts_file(expected,
FakeDualNetworkDualDHCPOnLinkSubnetRoutesDisabled())
def test_output_opts_file_dual_dhcp_rfc3442_one_on_link_subnet_route(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,'
'169.254.169.254/32,192.168.0.1,'
'192.168.1.0/24,0.0.0.0,0.0.0.0/0,192.168.0.1\n'
'tag:tag0,249,20.0.0.1/24,20.0.0.1,'
'169.254.169.254/32,192.168.0.1,192.168.1.0/24,0.0.0.0,'
'0.0.0.0/0,192.168.0.1\n'
'tag:tag0,option:router,192.168.0.1\n'
'tag:tag1,option:dns-server,8.8.8.8\n'
'tag:tag1,option:classless-static-route,'
'169.254.169.254/32,192.168.1.1,'
'192.168.0.0/24,0.0.0.0,0.0.0.0/0,192.168.1.1\n'
'tag:tag1,249,169.254.169.254/32,192.168.1.1,'
'192.168.0.0/24,0.0.0.0,0.0.0.0/0,192.168.1.1\n'
'tag:tag1,option:router,192.168.1.1\n'
'tag:tag2,option:dns-server,8.8.8.8\n'
'tag:tag2,option:classless-static-route,'
'169.254.169.254/32,192.168.2.1,0.0.0.0/0,192.168.2.1\n'
'tag:tag2,249,169.254.169.254/32,192.168.2.1,'
'0.0.0.0/0,192.168.2.1\n'
'tag:tag2,option:router,192.168.2.1').lstrip()
self._test_output_opts_file(expected,
FakeDualNetworkTriDHCPOneOnLinkSubnetRoute())
def test_output_opts_file_no_gateway(self):
expected = (
'tag:tag0,option:classless-static-route,'