]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Ensure entries in dnsmasq belong to a subnet using DHCP
authorSean M. Collins <sean_collins2@cable.comcast.com>
Tue, 10 Jun 2014 19:20:49 +0000 (15:20 -0400)
committerSean M. Collins <sean_collins2@cable.comcast.com>
Tue, 17 Jun 2014 14:24:36 +0000 (10:24 -0400)
In certain configurations, Neutron calculates SLAAC addresses for IPv6
subnets and adds them to the fixed_ips field of a port. Since those
subnets are not being managed by DHCP, do not add those fixed_ip entries
to the host file.

Closes-bug: #1316190
Related-bug: #1257446

Change-Id: I77dd55063296990c9df385f331f5de5d42402786

neutron/agent/linux/dhcp.py
neutron/tests/unit/test_linux_dhcp.py

index 84de415be400b30c4c0ab666bad1095a070d9ecf..c837fa56643edc55ded88f0fad211d94f01cb56d 100644 (file)
@@ -366,9 +366,14 @@ class Dnsmasq(DhcpLocalProcess):
             if subnet.ip_version == 4:
                 mode = 'static'
             else:
-                # TODO(mark): how do we indicate other options
-                # ra-only, slaac, ra-nameservers, and ra-stateless.
-                mode = 'static'
+                # Note(scollins) If the IPv6 attributes are not set, set it as
+                # static to preserve previous behavior
+                if (not getattr(subnet, 'ipv6_ra_mode', None) and
+                        not getattr(subnet, 'ipv6_address_mode', None)):
+                    mode = 'static'
+                elif getattr(subnet, 'ipv6_ra_mode', None) is None:
+                    # RA mode is not set - do not launch dnsmasq
+                    continue
             if self.version >= self.MINIMUM_VERSION:
                 set_tag = 'set:'
             else:
@@ -445,8 +450,18 @@ class Dnsmasq(DhcpLocalProcess):
             name,  # Host name and domain name in the format 'hostname.domain'.
         )
         """
+        v6_nets = dict((subnet.id, subnet) for subnet in
+                       self.network.subnets if subnet.ip_version == 6)
         for port in self.network.ports:
             for alloc in port.fixed_ips:
+                # Note(scollins) Only create entries that are
+                # associated with the subnet being managed by this
+                # dhcp agent
+                if alloc.subnet_id in v6_nets:
+                    ra_mode = v6_nets[alloc.subnet_id].ipv6_ra_mode
+                    addr_mode = v6_nets[alloc.subnet_id].ipv6_address_mode
+                    if (ra_mode is None and addr_mode == constants.IPV6_SLAAC):
+                        continue
                 hostname = 'host-%s' % alloc.ip_address.replace(
                     '.', '-').replace(':', '-')
                 fqdn = '%s.%s' % (hostname, self.conf.dhcp_domain)
index bedf1755f4430902e283d75ae89cdff2b81aabce..691b27f40298719efaac7639d9a5bc3066fa7d45 100644 (file)
@@ -49,7 +49,8 @@ class FakePort1:
     id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
     admin_state_up = True
     device_owner = 'foo1'
-    fixed_ips = [FakeIPAllocation('192.168.0.2')]
+    fixed_ips = [FakeIPAllocation('192.168.0.2',
+                                  'dddddddd-dddd-dddd-dddd-dddddddddddd')]
     mac_address = '00:00:80:aa:bb:cc'
 
     def __init__(self):
@@ -60,7 +61,8 @@ class FakePort2:
     id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
     admin_state_up = False
     device_owner = 'foo2'
-    fixed_ips = [FakeIPAllocation('fdca:3ba5:a17a:4ba3::2')]
+    fixed_ips = [FakeIPAllocation('fdca:3ba5:a17a:4ba3::2',
+                                  'ffffffff-ffff-ffff-ffff-ffffffffffff')]
     mac_address = '00:00:f3:aa:bb:cc'
 
     def __init__(self):
@@ -71,14 +73,29 @@ class FakePort3:
     id = '44444444-4444-4444-4444-444444444444'
     admin_state_up = True
     device_owner = 'foo3'
-    fixed_ips = [FakeIPAllocation('192.168.0.3'),
-                 FakeIPAllocation('fdca:3ba5:a17a:4ba3::3')]
+    fixed_ips = [FakeIPAllocation('192.168.0.3',
+                                  'dddddddd-dddd-dddd-dddd-dddddddddddd'),
+                 FakeIPAllocation('fdca:3ba5:a17a:4ba3::3',
+                                  'ffffffff-ffff-ffff-ffff-ffffffffffff')]
     mac_address = '00:00:0f:aa:bb:cc'
 
     def __init__(self):
         self.extra_dhcp_opts = []
 
 
+class FakePort4:
+
+    id = 'gggggggg-gggg-gggg-gggg-gggggggggggg'
+    admin_state_up = False
+    device_owner = 'foo3'
+    fixed_ips = [FakeIPAllocation('192.168.0.4',
+                                  'ffda:3ba5:a17a:4ba3:0216:3eff:fec2:771d')]
+    mac_address = '00:16:3E:C2:77:1D'
+
+    def __init__(self):
+        self.extra_dhcp_opts = []
+
+
 class FakeRouterPort:
     id = 'rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr'
     admin_state_up = True
@@ -194,6 +211,8 @@ class FakeV6Subnet:
     enable_dhcp = True
     host_routes = [FakeV6HostRoute]
     dns_nameservers = ['2001:0200:feed:7ac0::1']
+    ipv6_ra_mode = None
+    ipv6_address_mode = None
 
 
 class FakeV4SubnetNoDHCP:
@@ -206,6 +225,17 @@ class FakeV4SubnetNoDHCP:
     dns_nameservers = []
 
 
+class FakeV6SubnetSlaac:
+    id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
+    ip_version = 6
+    cidr = 'ffda:3ba5:a17a:4ba3::/64'
+    gateway_ip = 'ffda:3ba5:a17a:4ba3::1'
+    enable_dhcp = True
+    host_routes = [FakeV6HostRoute]
+    ipv6_address_mode = constants.IPV6_SLAAC
+    ipv6_ra_mode = None
+
+
 class FakeV4SubnetNoGateway:
     id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
     ip_version = 4
@@ -370,6 +400,13 @@ class FakeV4NetworkPxe3Ports:
                 DhcpOpt(opt_name='bootfile-name', opt_value='pxelinux3.0')]
 
 
+class FakeDualStackNetworkSingleDHCP:
+    id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
+
+    subnets = [FakeV4Subnet(), FakeV6SubnetSlaac()]
+    ports = [FakePort1(), FakePort4(), FakeRouterPort()]
+
+
 class LocalChild(dhcp.DhcpLocalProcess):
     PORTS = {4: [4], 6: [6]}
 
@@ -1250,3 +1287,17 @@ tag:tag0,option:router""".lstrip()
 
     def test_check_version_failed_cmd_execution(self):
         self._check_version('Error while executing command', 0)
+
+    def test_only_populates_dhcp_enabled_subnets(self):
+        exp_host_name = '/dhcp/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee/host'
+        exp_host_data = ('00:00:80:aa:bb:cc,host-192-168-0-2.openstacklocal,'
+                         '192.168.0.2\n'
+                         '00:16:3E:C2:77:1D,host-192-168-0-4.openstacklocal,'
+                         '192.168.0.4\n'
+                         '00:00:0f:rr:rr:rr,host-192-168-0-1.openstacklocal,'
+                         '192.168.0.1\n').lstrip()
+        dm = dhcp.Dnsmasq(self.conf, FakeDualStackNetworkSingleDHCP(),
+                          version=float(2.59))
+        dm._output_hosts_file()
+        self.safe.assert_has_calls([mock.call(exp_host_name,
+                                              exp_host_data)])