xref: /aosp_15_r20/external/autotest/client/cros/dhcpv6_test_server.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright 2015 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Li"""
7*9c5db199SXin LiEncapsulate functionality of the dhcpd Daemon. Support writing out a
8*9c5db199SXin Liconfiguration file as well as starting and stopping the service.
9*9c5db199SXin Li"""
10*9c5db199SXin Li
11*9c5db199SXin Liimport os
12*9c5db199SXin Liimport signal
13*9c5db199SXin Li
14*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
15*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils
16*9c5db199SXin Li
17*9c5db199SXin Li# Filenames used for execution.
18*9c5db199SXin LiDHCPV6_SERVER_EXECUTABLE = '/usr/local/sbin/dhcpd'
19*9c5db199SXin LiDHCPV6_SERVER_CONFIG_FILE = '/tmp/dhcpv6_test.conf'
20*9c5db199SXin LiDHCPV6_SERVER_PID_FILE = '/tmp/dhcpv6_test.pid'
21*9c5db199SXin Li
22*9c5db199SXin LiDHCPV6_SERVER_ADDRESS = '2001:db8:0:1::1'
23*9c5db199SXin LiDHCPV6_SERVER_SUBNET_PREFIX = '2001:db8:0:1::'
24*9c5db199SXin LiDHCPV6_SERVER_SUBNET_PREFIX_LENGTH = 64
25*9c5db199SXin LiDHCPV6_ADDRESS_RANGE_LOW = 0x100
26*9c5db199SXin LiDHCPV6_ADDRESS_RANGE_HIGH = 0x1ff
27*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_INDEX_LOW = 0x1
28*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_INDEX_HIGH = 0xf
29*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_RANGE_FORMAT = '2001:db8:0:%x00::'
30*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_RANGE_LOW = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT %
31*9c5db199SXin Li                                      (DHCPV6_PREFIX_DELEGATION_INDEX_LOW))
32*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_RANGE_HIGH = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT %
33*9c5db199SXin Li                                       (DHCPV6_PREFIX_DELEGATION_INDEX_HIGH))
34*9c5db199SXin LiDHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH = 56
35*9c5db199SXin LiDHCPV6_DEFAULT_LEASE_TIME = 600
36*9c5db199SXin LiDHCPV6_MAX_LEASE_TIME = 7200
37*9c5db199SXin LiDHCPV6_NAME_SERVERS = 'fec0:0:0:1::1'
38*9c5db199SXin LiDHCPV6_DOMAIN_SEARCH = 'domain.example'
39*9c5db199SXin Li
40*9c5db199SXin LiCONFIG_DEFAULT_LEASE_TIME = 'default_lease_time'
41*9c5db199SXin LiCONFIG_MAX_LEASE_TIME = 'max_lease_time'
42*9c5db199SXin LiCONFIG_SUBNET = 'subnet'
43*9c5db199SXin LiCONFIG_RANGE = 'range'
44*9c5db199SXin LiCONFIG_NAME_SERVERS = 'name_servers'
45*9c5db199SXin LiCONFIG_DOMAIN_SEARCH = 'domain_search'
46*9c5db199SXin LiCONFIG_PREFIX_RANGE = 'prefix_range'
47*9c5db199SXin Li
48*9c5db199SXin Liclass Dhcpv6TestServer(object):
49*9c5db199SXin Li    """
50*9c5db199SXin Li    This is an embodiment of the DHCPv6 server (dhcpd) process.  It converts an
51*9c5db199SXin Li    config dict into parameters for the dhcpd configuration file and
52*9c5db199SXin Li    manages startup and cleanup of the process.
53*9c5db199SXin Li    """
54*9c5db199SXin Li
55*9c5db199SXin Li    def __init__(self, interface = None):
56*9c5db199SXin Li        if not os.path.exists(DHCPV6_SERVER_EXECUTABLE):
57*9c5db199SXin Li            raise error.TestNAError('Could not find executable %s; '
58*9c5db199SXin Li                                    'this is likely an old version of '
59*9c5db199SXin Li                                    'ChromiumOS' %
60*9c5db199SXin Li                                    DHCPV6_SERVER_EXECUTABLE)
61*9c5db199SXin Li        self._interface = interface
62*9c5db199SXin Li        # "2001:db8:0:1::/64"
63*9c5db199SXin Li        subnet = '%s/%d' % (DHCPV6_SERVER_SUBNET_PREFIX,
64*9c5db199SXin Li                            DHCPV6_SERVER_SUBNET_PREFIX_LENGTH)
65*9c5db199SXin Li        # "2001:db8:0:1::100 2001:db8:1::1ff"
66*9c5db199SXin Li        range = '%s%x %s%x' % (DHCPV6_SERVER_SUBNET_PREFIX,
67*9c5db199SXin Li                               DHCPV6_ADDRESS_RANGE_LOW,
68*9c5db199SXin Li                               DHCPV6_SERVER_SUBNET_PREFIX,
69*9c5db199SXin Li                               DHCPV6_ADDRESS_RANGE_HIGH)
70*9c5db199SXin Li        # "2001:db8:0:100:: 2001:db8:1:f00:: /56"
71*9c5db199SXin Li        prefix_range = '%s %s /%d' % (DHCPV6_PREFIX_DELEGATION_RANGE_LOW,
72*9c5db199SXin Li                                      DHCPV6_PREFIX_DELEGATION_RANGE_HIGH,
73*9c5db199SXin Li                                      DHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH)
74*9c5db199SXin Li        self._config = {
75*9c5db199SXin Li            CONFIG_DEFAULT_LEASE_TIME: DHCPV6_DEFAULT_LEASE_TIME,
76*9c5db199SXin Li            CONFIG_MAX_LEASE_TIME: DHCPV6_MAX_LEASE_TIME,
77*9c5db199SXin Li            CONFIG_SUBNET: subnet,
78*9c5db199SXin Li            CONFIG_RANGE: range,
79*9c5db199SXin Li            CONFIG_NAME_SERVERS: DHCPV6_NAME_SERVERS,
80*9c5db199SXin Li            CONFIG_DOMAIN_SEARCH: DHCPV6_DOMAIN_SEARCH,
81*9c5db199SXin Li            CONFIG_PREFIX_RANGE: prefix_range
82*9c5db199SXin Li        }
83*9c5db199SXin Li
84*9c5db199SXin Li
85*9c5db199SXin Li    def _write_config_file(self):
86*9c5db199SXin Li        """
87*9c5db199SXin Li        Write out a configuration file for DHCPv6 server to use.
88*9c5db199SXin Li        """
89*9c5db199SXin Li        config = '\n'.join([
90*9c5db199SXin Li                     'default-lease-time %(default_lease_time)d;',
91*9c5db199SXin Li                     'max-lease-time %(max_lease_time)d;',
92*9c5db199SXin Li                     'subnet6 %(subnet)s {',
93*9c5db199SXin Li                     '  range6 %(range)s;',
94*9c5db199SXin Li                     '  option dhcp6.name-servers %(name_servers)s;',
95*9c5db199SXin Li                     '  option dhcp6.domain-search \"%(domain_search)s\";',
96*9c5db199SXin Li                     '  prefix6 %(prefix_range)s;',
97*9c5db199SXin Li                     '}'
98*9c5db199SXin Li                     '']) % self._config
99*9c5db199SXin Li        with open(DHCPV6_SERVER_CONFIG_FILE, 'w') as f:
100*9c5db199SXin Li            f.write(config)
101*9c5db199SXin Li
102*9c5db199SXin Li
103*9c5db199SXin Li    def _cleanup(self):
104*9c5db199SXin Li        """
105*9c5db199SXin Li        Cleanup temporary files.  If PID file exists, also kill the
106*9c5db199SXin Li        associated process.
107*9c5db199SXin Li        """
108*9c5db199SXin Li        if os.path.exists(DHCPV6_SERVER_PID_FILE):
109*9c5db199SXin Li            with open(DHCPV6_SERVER_PID_FILE) as rf:
110*9c5db199SXin Li                pid = int(rf.read())
111*9c5db199SXin Li            os.remove(DHCPV6_SERVER_PID_FILE)
112*9c5db199SXin Li            try:
113*9c5db199SXin Li                os.kill(pid, signal.SIGTERM)
114*9c5db199SXin Li            except OSError:
115*9c5db199SXin Li                pass
116*9c5db199SXin Li        if os.path.exists(DHCPV6_SERVER_CONFIG_FILE):
117*9c5db199SXin Li            os.remove(DHCPV6_SERVER_CONFIG_FILE)
118*9c5db199SXin Li
119*9c5db199SXin Li
120*9c5db199SXin Li    def start(self):
121*9c5db199SXin Li        """
122*9c5db199SXin Li        Start the DHCPv6 server.  The server will daemonize itself and
123*9c5db199SXin Li        run in the background.
124*9c5db199SXin Li        """
125*9c5db199SXin Li        self._cleanup()
126*9c5db199SXin Li        self._write_config_file()
127*9c5db199SXin Li        utils.system('%s -6 -pf %s -cf %s %s' %
128*9c5db199SXin Li                     (DHCPV6_SERVER_EXECUTABLE,
129*9c5db199SXin Li                      DHCPV6_SERVER_PID_FILE,
130*9c5db199SXin Li                      DHCPV6_SERVER_CONFIG_FILE,
131*9c5db199SXin Li                      self._interface))
132*9c5db199SXin Li
133*9c5db199SXin Li
134*9c5db199SXin Li    def stop(self):
135*9c5db199SXin Li        """
136*9c5db199SXin Li        Halt the DHCPv6 server.
137*9c5db199SXin Li        """
138*9c5db199SXin Li        self._cleanup()
139