(
port, # a DictModel instance representing the port.
alloc, # a DictModel instance of the allocated ip and subnet.
+ # if alloc is None, it means there is no need to allocate
+ # an IPv6 address because of stateless DHCPv6 network.
host_name, # Host name.
name, # Canonical hostname in the format 'hostname[.domain]'.
)
# dhcp agent
if alloc.subnet_id in v6_nets:
addr_mode = v6_nets[alloc.subnet_id].ipv6_address_mode
- if addr_mode != constants.DHCPV6_STATEFUL:
+ if addr_mode == constants.IPV6_SLAAC:
continue
+ elif addr_mode == constants.DHCPV6_STATELESS:
+ alloc = hostname = fqdn = None
+ yield (port, alloc, hostname, fqdn)
+ continue
+
hostname = 'host-%s' % alloc.ip_address.replace(
'.', '-').replace(':', '-')
fqdn = hostname
dhcp_enabled_subnet_ids = [s.id for s in self.network.subnets
if s.enable_dhcp]
for (port, alloc, hostname, name) in self._iter_hosts():
+ if not alloc:
+ if getattr(port, 'extra_dhcp_opts', False):
+ buf.write('%s,%s%s\n' %
+ (port.mac_address, 'set:', port.id))
+ LOG.debug('Adding %(mac)s : set:%(tag)s',
+ {"mac": port.mac_address, "tag": port.id})
+ continue
+
# don't write ip address which belongs to a dhcp disabled subnet.
if alloc.subnet_id not in dhcp_enabled_subnet_ids:
continue
if netaddr.valid_ipv6(ip_address):
ip_address = '[%s]' % ip_address
- LOG.debug('Adding %(mac)s : %(name)s : %(ip)s',
- {"mac": port.mac_address, "name": name,
- "ip": ip_address})
-
if getattr(port, 'extra_dhcp_opts', False):
buf.write('%s,%s,%s,%s%s\n' %
(port.mac_address, name, ip_address,
'set:', port.id))
+ LOG.debug('Adding %(mac)s : %(name)s : %(ip)s : '
+ 'set:%(tag)s',
+ {"mac": port.mac_address, "name": name,
+ "ip": ip_address, "tag": port.id})
else:
buf.write('%s,%s,%s\n' %
(port.mac_address, name, ip_address))
+ LOG.debug('Adding %(mac)s : %(name)s : %(ip)s',
+ {"mac": port.mac_address, "name": name,
+ "ip": ip_address})
utils.replace_file(filename, buf.getvalue())
LOG.debug('Done building host file %s', filename)
for (port, alloc, hostname, fqdn) in self._iter_hosts():
# It is compulsory to write the `fqdn` before the `hostname` in
# order to obtain it in PTR responses.
- buf.write('%s\t%s %s\n' % (alloc.ip_address, fqdn, hostname))
+ if alloc:
+ buf.write('%s\t%s %s\n' % (alloc.ip_address, fqdn, hostname))
addn_hosts = self.get_conf_file_name('addn_hosts')
utils.replace_file(addn_hosts, buf.getvalue())
return addn_hosts
self.extra_dhcp_opts = []
+class FakeV6PortExtraOpt(object):
+ id = 'hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh'
+ admin_state_up = True
+ device_owner = 'foo3'
+ fixed_ips = [FakeIPAllocation('ffea:3ba5:a17a:4ba3:0216:3eff:fec2:771d',
+ 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee')]
+ mac_address = '00:16:3e:c2:77:1d'
+
+ def __init__(self):
+ self.extra_dhcp_opts = [
+ DhcpOpt(opt_name='dns-server',
+ opt_value='ffea:3ba5:a17a:4ba3::100',
+ ip_version=6)]
+
+
class FakeDualPort(object):
id = 'hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh'
admin_state_up = True
ipv6_ra_mode = None
+class FakeV6SubnetStateless(object):
+ id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
+ ip_version = 6
+ cidr = 'ffea:3ba5:a17a:4ba3::/64'
+ gateway_ip = 'ffea:3ba5:a17a:4ba3::1'
+ enable_dhcp = True
+ dns_nameservers = []
+ host_routes = []
+ ipv6_address_mode = constants.DHCPV6_STATELESS
+ ipv6_ra_mode = None
+
+
class FakeV4SubnetNoGateway(object):
id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
ip_version = 4
DhcpOpt(opt_name='tag:ipxe,bootfile-name', opt_value='pxelinux.0')]
+class FakeV6NetworkStatelessDHCP(object):
+ id = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'
+
+ subnets = [FakeV6SubnetStateless()]
+ ports = [FakeV6PortExtraOpt()]
+ namespace = 'qdhcp-ns'
+
+
class LocalChild(dhcp.DhcpLocalProcess):
PORTS = {4: [4], 6: [6]}
self.safe.assert_has_calls([mock.call(exp_host_name,
exp_host_data)])
+ def test_host_and_opts_file_on_stateless_dhcpv6_network(self):
+ exp_host_name = '/dhcp/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb/host'
+ exp_host_data = ('00:16:3e:c2:77:1d,'
+ 'set:hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh\n').lstrip()
+ exp_opt_name = '/dhcp/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb/opts'
+ exp_opt_data = ('tag:tag0,option6:domain-search,openstacklocal\n'
+ 'tag:hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh,'
+ 'option6:dns-server,ffea:3ba5:a17a:4ba3::100').lstrip()
+ dm = self._get_dnsmasq(FakeV6NetworkStatelessDHCP())
+ dm._output_hosts_file()
+ dm._output_opts_file()
+ self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
+ mock.call(exp_opt_name, exp_opt_data)])
+
def test_should_enable_metadata_namespaces_disabled_returns_false(self):
self.conf.set_override('use_namespaces', False)
self.assertFalse(dhcp.Dnsmasq.should_enable_metadata(self.conf,