]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Support Stateful and Stateless DHCPv6 by dnsmasq
authorXu Han Peng <xuhanp@cn.ibm.com>
Fri, 11 Jul 2014 07:30:00 +0000 (15:30 +0800)
committerXu Han Peng <xuhanp@cn.ibm.com>
Wed, 20 Aug 2014 05:04:48 +0000 (13:04 +0800)
* This patch adds support for subnets created with 'ipv6_address_mode'
  set to 'dhcpv6-stateful' or 'dhcpv6-stateless' by dnsmasq.
* If no dnsmasq process for subnet's network is launched, Neutron
  will launch new dnsmasq process on subnet's dhcp port in 'qdhcp-'
  namespace. If previous dnsmasq process is already launched,
  restart dnsmasq with new configuration.
* Neutron will update dnsmasq process and restart it when subnet
  gets updated.
* This patch enforces the version check of dnsmasq. dhcp-agent will
  fail to start if version of dnsmasq<2.63.

DocImpact
UpgradeImpact
Blueprint dnsmasq-ipv6-dhcpv6-stateful
Blueprint dnsmasq-ipv6-dhcpv6-stateless

Change-Id: I30e9950bbc5a89f01ccb9c561471f155a9fd1d11

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

index c4b39ab781e4085ea7b84d54f519a3440b3a983e..59452732ee11f2d60d1010a1db111ce6107862ee 100644 (file)
@@ -313,10 +313,11 @@ class Dnsmasq(DhcpLocalProcess):
             ver = re.findall("\d+.\d+", out)[0]
             is_valid_version = float(ver) >= cls.MINIMUM_VERSION
             if not is_valid_version:
-                LOG.warning(_('FAILED VERSION REQUIREMENT FOR DNSMASQ. '
-                              'DHCP AGENT MAY NOT RUN CORRECTLY! '
-                              'Please ensure that its version is %s '
-                              'or above!'), cls.MINIMUM_VERSION)
+                LOG.error(_('FAILED VERSION REQUIREMENT FOR DNSMASQ. '
+                            'DHCP AGENT MAY NOT RUN CORRECTLY! '
+                            'Please ensure that its version is %s '
+                            'or above!'), cls.MINIMUM_VERSION)
+                raise SystemExit(1)
         except (OSError, RuntimeError, IndexError, ValueError):
             LOG.error(_('Unable to determine dnsmasq version. '
                         'Please ensure that its version is %s '
@@ -368,17 +369,12 @@ class Dnsmasq(DhcpLocalProcess):
             else:
                 # 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)):
+                addr_mode = getattr(subnet, 'ipv6_address_mode', None)
+                ra_mode = getattr(subnet, 'ipv6_ra_mode', None)
+                if (addr_mode in [constants.DHCPV6_STATEFUL,
+                                  constants.DHCPV6_STATELESS] or
+                        not addr_mode and not ra_mode):
                     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:
-                set_tag = ''
 
             cidr = netaddr.IPNetwork(subnet.cidr)
 
@@ -390,14 +386,9 @@ class Dnsmasq(DhcpLocalProcess):
             # mode is optional and is not set - skip it
             if mode:
                 cmd.append('--dhcp-range=%s%s,%s,%s,%s' %
-                           (set_tag, self._TAG_PREFIX % i,
+                           ('set:', self._TAG_PREFIX % i,
                             cidr.network, mode, lease))
-            else:
-                cmd.append('--dhcp-range=%s%s,%s,%s' %
-                           (set_tag, self._TAG_PREFIX % i,
-                            cidr.network, lease))
-
-            possible_leases += cidr.size
+                possible_leases += cidr.size
 
         # Cap the limit because creating lots of subnets can inflate
         # this possible lease cap.
@@ -465,9 +456,8 @@ class Dnsmasq(DhcpLocalProcess):
                 # 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):
+                    if addr_mode != constants.DHCPV6_STATEFUL:
                         continue
                 hostname = 'host-%s' % alloc.ip_address.replace(
                     '.', '-').replace(':', '-')
@@ -497,7 +487,6 @@ class Dnsmasq(DhcpLocalProcess):
 
         LOG.debug(_('Building host file: %s'), filename)
         for (port, alloc, hostname, name) in self._iter_hosts():
-            set_tag = ''
             # (dzyu) Check if it is legal ipv6 address, if so, need wrap
             # it with '[]' to let dnsmasq to distinguish MAC address from
             # IPv6 address.
@@ -510,12 +499,9 @@ class Dnsmasq(DhcpLocalProcess):
                        "ip": ip_address})
 
             if getattr(port, 'extra_dhcp_opts', False):
-                if self.version >= self.MINIMUM_VERSION:
-                    set_tag = 'set:'
-
                 buf.write('%s,%s,%s,%s%s\n' %
                           (port.mac_address, name, ip_address,
-                           set_tag, port.id))
+                           'set:', port.id))
             else:
                 buf.write('%s,%s,%s\n' %
                           (port.mac_address, name, ip_address))
@@ -575,17 +561,27 @@ class Dnsmasq(DhcpLocalProcess):
         dhcp_ips = collections.defaultdict(list)
         subnet_idx_map = {}
         for i, subnet in enumerate(self.network.subnets):
-            if not subnet.enable_dhcp:
+            if (not subnet.enable_dhcp or
+                (subnet.ip_version == 6 and
+                 getattr(subnet, 'ipv6_address_mode', None)
+                 in [None, constants.IPV6_SLAAC])):
                 continue
             if subnet.dns_nameservers:
                 options.append(
-                    self._format_option(i, 'dns-server',
-                                        ','.join(subnet.dns_nameservers)))
+                    self._format_option(
+                        subnet.ip_version, i, 'dns-server',
+                        ','.join(
+                            Dnsmasq._convert_to_literal_addrs(
+                                subnet.ip_version, subnet.dns_nameservers))))
             else:
                 # use the dnsmasq ip as nameservers only if there is no
                 # dns-server submitted by the server
                 subnet_idx_map[subnet.id] = i
 
+            if self.conf.dhcp_domain and subnet.ip_version == 6:
+                options.append('tag:tag%s,option6:domain-search,%s' %
+                               (i, ''.join(self.conf.dhcp_domain)))
+
             gateway = subnet.gateway_ip
             host_routes = []
             for hr in subnet.host_routes:
@@ -603,27 +599,42 @@ class Dnsmasq(DhcpLocalProcess):
                     '%s/32,%s' % (METADATA_DEFAULT_IP, subnet_dhcp_ip)
                 )
 
-            if host_routes:
-                if gateway and subnet.ip_version == 4:
-                    host_routes.append("%s,%s" % ("0.0.0.0/0", gateway))
-                options.append(
-                    self._format_option(i, 'classless-static-route',
-                                        ','.join(host_routes)))
-                options.append(
-                    self._format_option(i, WIN2k3_STATIC_DNS,
-                                        ','.join(host_routes)))
-
             if subnet.ip_version == 4:
+                if host_routes:
+                    if gateway:
+                        host_routes.append("%s,%s" % ("0.0.0.0/0", gateway))
+                    options.append(
+                        self._format_option(subnet.ip_version, i,
+                                            'classless-static-route',
+                                            ','.join(host_routes)))
+                    options.append(
+                        self._format_option(subnet.ip_version, i,
+                                            WIN2k3_STATIC_DNS,
+                                            ','.join(host_routes)))
+
                 if gateway:
-                    options.append(self._format_option(i, 'router', gateway))
+                    options.append(self._format_option(subnet.ip_version,
+                                                       i, 'router',
+                                                       gateway))
                 else:
-                    options.append(self._format_option(i, 'router'))
+                    options.append(self._format_option(subnet.ip_version,
+                                                       i, 'router'))
 
         for port in self.network.ports:
             if getattr(port, 'extra_dhcp_opts', False):
-                options.extend(
-                    self._format_option(port.id, opt.opt_name, opt.opt_value)
-                    for opt in port.extra_dhcp_opts)
+                for ip_version in (4, 6):
+                    if any(
+                        netaddr.IPAddress(ip.ip_address).version == ip_version
+                            for ip in port.fixed_ips):
+                        options.extend(
+                            # TODO(xuhanp):Instead of applying extra_dhcp_opts
+                            # to both DHCPv4 and DHCPv6, we need to find a new
+                            # way to specify options for v4 and v6
+                            # respectively. We also need to validate the option
+                            # before applying it.
+                            self._format_option(ip_version, port.id,
+                                                opt.opt_name, opt.opt_value)
+                            for opt in port.extra_dhcp_opts)
 
             # provides all dnsmasq ip as dns-server if there is more than
             # one dnsmasq for a subnet and there is no dns-server submitted
@@ -636,10 +647,16 @@ class Dnsmasq(DhcpLocalProcess):
                     dhcp_ips[i].append(ip.ip_address)
 
         for i, ips in dhcp_ips.items():
-            if len(ips) > 1:
-                options.append(self._format_option(i,
-                                                   'dns-server',
-                                                   ','.join(ips)))
+            for ip_version in (4, 6):
+                vx_ips = [ip for ip in ips
+                          if netaddr.IPAddress(ip).version == ip_version]
+                if vx_ips:
+                    options.append(
+                        self._format_option(
+                            ip_version, i, 'dns-server',
+                            ','.join(
+                                Dnsmasq._convert_to_literal_addrs(ip_version,
+                                                                  vx_ips))))
 
         name = self.get_conf_file_name('opts')
         utils.replace_file(name, '\n'.join(options))
@@ -667,22 +684,26 @@ class Dnsmasq(DhcpLocalProcess):
 
         return retval
 
-    def _format_option(self, tag, option, *args):
+    def _format_option(self, ip_version, tag, option, *args):
         """Format DHCP option by option name or code."""
-        if self.version >= self.MINIMUM_VERSION:
-            set_tag = 'tag:'
-        else:
-            set_tag = ''
-
         option = str(option)
 
         if isinstance(tag, int):
             tag = self._TAG_PREFIX % tag
 
         if not option.isdigit():
-            option = 'option:%s' % option
+            if ip_version == 4:
+                option = 'option:%s' % option
+            else:
+                option = 'option6:%s' % option
+
+        return ','.join(('tag:' + tag, '%s' % option) + args)
 
-        return ','.join((set_tag + tag, '%s' % option) + args)
+    @staticmethod
+    def _convert_to_literal_addrs(ip_version, ips):
+        if ip_version == 4:
+            return ips
+        return ['[' + ip + ']' for ip in ips]
 
     def _enable_metadata(self, subnet):
         '''Determine if the metadata route will be pushed to hosts on subnet.
index 98f06decfc7c06100590854fdc5a2fd9c08a5771..cbe345ee38af80ac1409f1ce9643fda4579a53ba 100644 (file)
@@ -17,6 +17,7 @@ import contextlib
 import os
 
 import mock
+import netaddr
 from oslo.config import cfg
 import testtools
 
@@ -60,8 +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',
-                                  'ffffffff-ffff-ffff-ffff-ffffffffffff')]
+    fixed_ips = [FakeIPAllocation('192.168.0.3',
+                                  'dddddddd-dddd-dddd-dddd-dddddddddddd')]
     mac_address = '00:00:f3:aa:bb:cc'
 
     def __init__(self):
@@ -72,10 +73,10 @@ class FakePort3:
     id = '44444444-4444-4444-4444-444444444444'
     admin_state_up = True
     device_owner = 'foo3'
-    fixed_ips = [FakeIPAllocation('192.168.0.3',
+    fixed_ips = [FakeIPAllocation('192.168.0.4',
                                   'dddddddd-dddd-dddd-dddd-dddddddddddd'),
-                 FakeIPAllocation('fdca:3ba5:a17a:4ba3::3',
-                                  'ffffffff-ffff-ffff-ffff-ffffffffffff')]
+                 FakeIPAllocation('192.168.1.2',
+                                  'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee')]
     mac_address = '00:00:0f:aa:bb:cc'
 
     def __init__(self):
@@ -95,6 +96,32 @@ class FakePort4:
         self.extra_dhcp_opts = []
 
 
+class FakeV6Port:
+    id = 'hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh'
+    admin_state_up = True
+    device_owner = 'foo3'
+    fixed_ips = [FakeIPAllocation('fdca:3ba5:a17a:4ba3::2',
+                                  'ffffffff-ffff-ffff-ffff-ffffffffffff')]
+    mac_address = '00:00:f3:aa:bb:cc'
+
+    def __init__(self):
+        self.extra_dhcp_opts = []
+
+
+class FakeDualPort:
+    id = 'hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh'
+    admin_state_up = True
+    device_owner = 'foo3'
+    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 FakeRouterPort:
     id = 'rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr'
     admin_state_up = True
@@ -224,6 +251,18 @@ class FakeV4SubnetNoDHCP:
     dns_nameservers = []
 
 
+class FakeV6SubnetDHCPStateful:
+    id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
+    ip_version = 6
+    cidr = 'fdca:3ba5:a17a:4ba3::/64'
+    gateway_ip = 'fdca:3ba5:a17a:4ba3::1'
+    enable_dhcp = True
+    host_routes = [FakeV6HostRoute]
+    dns_nameservers = ['2001:0200:feed:7ac0::1']
+    ipv6_ra_mode = None
+    ipv6_address_mode = constants.DHCPV6_STATEFUL
+
+
 class FakeV6SubnetSlaac:
     id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
     ip_version = 6
@@ -271,14 +310,14 @@ class FakeV6Network:
 
 class FakeDualNetwork:
     id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
-    subnets = [FakeV4Subnet(), FakeV6Subnet()]
-    ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
+    subnets = [FakeV4Subnet(), FakeV6SubnetDHCPStateful()]
+    ports = [FakePort1(), FakeV6Port(), FakeDualPort(), FakeRouterPort()]
     namespace = 'qdhcp-ns'
 
 
 class FakeDualNetworkGatewayRoute:
     id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
-    subnets = [FakeV4SubnetGatewayRoute(), FakeV6Subnet()]
+    subnets = [FakeV4SubnetGatewayRoute(), FakeV6SubnetDHCPStateful()]
     ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
     namespace = 'qdhcp-ns'
 
@@ -724,11 +763,16 @@ class TestDnsmasq(TestBase):
             prefix = '--dhcp-range=set:tag%d,%s,static,%s%s'
         else:
             prefix = '--dhcp-range=set:tag%d,%s,%s%s'
-        expected.extend(prefix %
-                        (i, s.cidr.split('/')[0], lease_duration, seconds)
-                        for i, s in enumerate(network.subnets))
-
-        expected.append('--dhcp-lease-max=%d' % max_leases)
+        possible_leases = 0
+        for i, s in enumerate(network.subnets):
+            if (s.ip_version != 6
+                or s.ipv6_address_mode == constants.DHCPV6_STATEFUL):
+                expected.extend([prefix % (
+                    i, s.cidr.split('/')[0], lease_duration, seconds)])
+                possible_leases += netaddr.IPNetwork(s.cidr).size
+
+        expected.append('--dhcp-lease-max=%d' % min(
+            possible_leases, max_leases))
         expected.extend(extra_options)
 
         self.execute.return_value = ('', '')
@@ -775,10 +819,9 @@ class TestDnsmasq(TestBase):
         self.safe.assert_has_calls([mock.call(exp_host_name, exp_host_data),
                                     mock.call(exp_addn_name, exp_addn_data)])
 
-    def test_spawn_no_dnsmasq_ipv6_mode(self):
+    def test_spawn_no_dhcp_range(self):
         network = FakeV6Network()
-        subnet = FakeV6Subnet()
-        subnet.ipv6_ra_mode = True
+        subnet = FakeV6SubnetSlaac()
         network.subnets = [subnet]
         self._test_spawn(['--conf-file=', '--domain=openstacklocal'],
                          network, has_static=False)
@@ -805,18 +848,15 @@ class TestDnsmasq(TestBase):
 
     def test_output_opts_file(self):
         fake_v6 = '2001:0200:feed:7ac0::1'
-        fake_v6_cidr = '2001:0200:feed:7ac0::/64'
         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\n'
-            'tag:tag1,option:dns-server,%s\n'
-            'tag:tag1,option:classless-static-route,%s,%s\n'
-            'tag:tag1,249,%s,%s').lstrip() % (fake_v6,
-                                              fake_v6_cidr, fake_v6,
-                                              fake_v6_cidr, fake_v6)
+            'tag:tag1,option6:dns-server,%s\n'
+            'tag:tag1,option6:domain-search,openstacklocal').lstrip() % (
+                '[' + fake_v6 + ']')
 
         with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
             conf_fn.return_value = '/foo/opts'
@@ -828,15 +868,12 @@ class TestDnsmasq(TestBase):
 
     def test_output_opts_file_gateway_route(self):
         fake_v6 = '2001:0200:feed:7ac0::1'
-        fake_v6_cidr = '2001:0200:feed:7ac0::/64'
         expected = """
 tag:tag0,option:dns-server,8.8.8.8
 tag:tag0,option:router,192.168.0.1
-tag:tag1,option:dns-server,%s
-tag:tag1,option:classless-static-route,%s,%s
-tag:tag1,249,%s,%s""".lstrip() % (fake_v6,
-                                  fake_v6_cidr, fake_v6,
-                                  fake_v6_cidr, fake_v6)
+tag:tag1,option6:dns-server,%s
+tag:tag1,option6:domain-search,openstacklocal""".lstrip() % (
+            '[' + fake_v6 + ']')
 
         with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
             conf_fn.return_value = '/foo/opts'
@@ -885,21 +922,6 @@ tag:tag0,option:router,192.168.0.1""".lstrip()
 
         self.safe.assert_called_once_with('/foo/opts', expected)
 
-    def test_output_opts_file_single_dhcp_ver2_48(self):
-        expected = (
-            'tag0,option:dns-server,8.8.8.8\n'
-            'tag0,option:classless-static-route,20.0.0.1/24,20.0.0.1,'
-            '0.0.0.0/0,192.168.0.1\n'
-            'tag0,249,20.0.0.1/24,20.0.0.1,0.0.0.0/0,192.168.0.1\n'
-            '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, FakeDualNetworkSingleDHCP(),
-                              version=float(2.48))
-            dm._output_opts_file()
-
-        self.safe.assert_called_once_with('/foo/opts', expected)
-
     def test_output_opts_file_no_gateway(self):
         expected = """
 tag:tag0,option:classless-static-route,169.254.169.254/32,192.168.1.1
@@ -997,42 +1019,6 @@ tag:tag0,option:router""".lstrip()
 
         self.safe.assert_called_once_with('/foo/opts', expected)
 
-    def test_output_opts_file_pxe_3port_1net_diff_details(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\n'
-            'tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,'
-            'option:tftp-server,192.168.0.3\n'
-            'tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,'
-            'option:server-ip-address,192.168.0.2\n'
-            'tag:eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,'
-            'option:bootfile-name,pxelinux.0\n'
-            'tag:ffffffff-ffff-ffff-ffff-ffffffffffff,'
-            'option:tftp-server,192.168.0.5\n'
-            'tag:ffffffff-ffff-ffff-ffff-ffffffffffff,'
-            'option:server-ip-address,192.168.0.5\n'
-            'tag:ffffffff-ffff-ffff-ffff-ffffffffffff,'
-            'option:bootfile-name,pxelinux2.0\n'
-            'tag:44444444-4444-4444-4444-444444444444,'
-            'option:tftp-server,192.168.0.7\n'
-            'tag:44444444-4444-4444-4444-444444444444,'
-            'option:server-ip-address,192.168.0.7\n'
-            'tag:44444444-4444-4444-4444-444444444444,'
-            'option:bootfile-name,pxelinux3.0')
-        expected = expected.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,
-                              FakeV4NetworkPxe3Ports("portsDifferent"),
-                              version=dhcp.Dnsmasq.MINIMUM_VERSION)
-            dm._output_opts_file()
-
-        self.safe.assert_called_once_with('/foo/opts', expected)
-
     def test_output_opts_file_pxe_3port_2net(self):
         expected = (
             'tag:tag0,option:dns-server,8.8.8.8\n'
@@ -1131,18 +1117,15 @@ tag:tag0,option:router""".lstrip()
         ).lstrip()
         exp_opt_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts'
         fake_v6 = '2001:0200:feed:7ac0::1'
-        fake_v6_cidr = '2001:0200:feed:7ac0::/64'
         exp_opt_data = (
             '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\n'
-            'tag:tag1,option:dns-server,%s\n'
-            'tag:tag1,option:classless-static-route,%s,%s\n'
-            'tag:tag1,249,%s,%s').lstrip() % (fake_v6,
-                                              fake_v6_cidr, fake_v6,
-                                              fake_v6_cidr, fake_v6)
+            'tag:tag1,option6:dns-server,%s\n'
+            'tag:tag1,option6:domain-search,openstacklocal').lstrip() % (
+            '[' + fake_v6 + ']')
         return (exp_host_name, exp_host_data,
                 exp_addn_name, exp_addn_data,
                 exp_opt_name, exp_opt_data,)
@@ -1333,8 +1316,8 @@ tag:tag0,option:router""".lstrip()
                             float(2.65))
 
     def test_check_fail_version(self):
-        self._check_version('Dnsmasq version 2.48 Copyright (c)...',
-                            float(2.48))
+        with testtools.ExpectedException(SystemExit):
+            self._check_version('Dnsmasq version 2.62 Copyright (c)...', 0)
 
     def test_check_version_failed_cmd_execution(self):
         with testtools.ExpectedException(SystemExit):