• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from autotest_lib.client.common_lib import error
6from autotest_lib.client.cros import dhcp_handling_rule
7from autotest_lib.client.cros import dhcp_packet
8from autotest_lib.client.cros import dhcp_test_base
9from autotest_lib.client.cros import shill_temporary_profile
10from autotest_lib.client.cros.networking import shill_context
11
12class network_DhcpStaticIP(dhcp_test_base.DhcpTestBase):
13    """DHCP test which confirms static IP functionality"""
14    # Length of time the lease from the DHCP server is valid.
15    LEASE_TIME_SECONDS = 60
16    # We'll fill in the subnet and give this address to the client over DHCP.
17    INTENDED_IP_SUFFIX = '0.0.0.101'
18    # We'll fill in the subnet and supply this as a static IP address.
19    STATIC_IP_SUFFIX = '0.0.0.201'
20    STATIC_IP_NAME_SERVERS = [ '1.1.2.2', '1.1.3.4' ]
21    # Time to wait for the DHCP negotiation protocol to complete.
22    DHCP_NEGOTIATION_TIMEOUT_SECONDS = 10
23    # Time to wait after DHCP negotiation completes until service is marked
24    # as connected.
25    DHCP_SETUP_TIMEOUT_SECONDS = 3
26    # Name given to the temporary shill profile we create for this test.
27    TEST_PROFILE_NAME = 'TestStaticIP'
28    # Various parameters that can be set statically.
29    CONFIGURE_STATIC_IP_ADDRESS = 'ip-address'
30    CONFIGURE_STATIC_IP_DNS_SERVERS = 'dns-servers'
31
32    def create_static_ip_config(self, params):
33        """Creates the configuration dictionary for a StaticIPConfig, given a
34        list of parameters.
35
36        @param params list of static parameters to configure.
37        @return dict containing the relevant StaticIPConfig parameters.
38
39        """
40        self._static_ip_options = {}
41        config = {}
42        if self.CONFIGURE_STATIC_IP_ADDRESS in params:
43            subnet_mask = self.ethernet_pair.interface_subnet_mask
44            static_ip_address = dhcp_test_base.DhcpTestBase.rewrite_ip_suffix(
45                    subnet_mask,
46                    self.server_ip,
47                    self.STATIC_IP_SUFFIX)
48            config['Address'] = static_ip_address
49
50            prefix_len = self.ethernet_pair.interface_prefix
51            config['Prefixlen'] = prefix_len
52
53            self._static_ip_options[dhcp_packet.OPTION_REQUESTED_IP] = (
54                    static_ip_address)
55        if self.CONFIGURE_STATIC_IP_DNS_SERVERS in params:
56            config['NameServers'] = self.STATIC_IP_NAME_SERVERS
57            self._static_ip_options[dhcp_packet.OPTION_DNS_SERVERS] = (
58                    self.STATIC_IP_NAME_SERVERS)
59        return config
60
61
62    def check_saved_ip(self, service, options):
63        """Check the properties of the Ethernet service to make sure that
64        the address provided by the DHCP server is properly added to the
65        SavedIPConfig.
66
67        @param service object the Service DBus interface to clear properties.
68        @param options dict parameters that were used to configure the DHCP
69            server.
70
71        """
72        intended_ip = options[dhcp_packet.OPTION_REQUESTED_IP]
73        properties = service.GetProperties()
74        saved_address = properties['SavedIPConfig']['Address']
75        if intended_ip != saved_address:
76            raise error.TestFail('Saved IP address %s is not DHCP address %s' %
77                                 (saved_address, intended_ip))
78
79
80    def make_lease_negotiation_rules(self, options):
81        """Generate a set of lease negotiation handling rules for a
82        server that will successfully return an IP address to the client.
83
84        @param options dict of options to be negotiated.  In particular,
85            the dhcp_packet.OPTION_REQUESTED_IP element is used to configure
86            the address that will be returned to the client.
87        @return array of DhcpHandlingRule instances which implement the
88            negotiation.
89
90        """
91        intended_ip = options[dhcp_packet.OPTION_REQUESTED_IP]
92        rules = []
93        rules.append(dhcp_handling_rule.DhcpHandlingRule_RespondToDiscovery(
94                intended_ip,
95                self.server_ip,
96                options,
97                {}))
98        rules.append(dhcp_handling_rule.DhcpHandlingRule_RespondToRequest(
99                intended_ip,
100                self.server_ip,
101                options,
102                {}))
103        return rules
104
105
106    def test_dhcp_negotiation(self, rules, service):
107        """Perform a DHCP lease negotiation using handler rules from |rules|,
108        and ensure that |service| becomes connected as a result.
109
110        @param rules array of handling rules that must complete in order for
111            the negotiation to be considered successful.
112        @param service Service DBus object which should become connected as
113            a result of the DHCP negotiation.
114
115        """
116        rules[-1].is_final_handler = True
117        self.server.start_test(rules, self.DHCP_NEGOTIATION_TIMEOUT_SECONDS)
118        self.server.wait_for_test_to_finish()
119        if not self.server.last_test_passed:
120            raise error.TestFail('Test server didn\'t get all the messages it '
121                                 'was told to expect during negotiation.')
122        # Wait for the service to enter a "good" state.
123        connect_result = self.shill_proxy.wait_for_property_in(
124                service,
125                self.shill_proxy.SERVICE_PROPERTY_STATE,
126                self.shill_proxy.SERVICE_CONNECTED_STATES,
127                self.DHCP_SETUP_TIMEOUT_SECONDS)
128        (successful, _, association_time) = connect_result
129        if not successful:
130            raise error.TestFail('Ethernet service did not become connected.')
131
132
133    def connect_dynamic_ip(self, options, service):
134        """Perform a DHCP negotiation, using |options|.  Then check that
135           the IP information configured on client matches the parameters
136           in |options|.
137
138        @param options dict containing DHCP packet options to be returned
139            to the client during negotiation, and then later checked for
140            consistency.
141        @param service DBus object of the service that should become
142            connected as a result of the negotiation.
143
144        """
145        self.test_dhcp_negotiation(self.make_lease_negotiation_rules(options),
146                                   service)
147        self.check_dhcp_config(options)
148
149
150    def connect_static_ip(self, options, service, params):
151        """Perform a DHCP negotiation, using |options|.  Then check that
152           the IP information configured on client matches the parameters
153           in |options|, except that the client's IP address should be
154           |static_ip_address|.
155
156        @param options dict containing DHCP packet options to be returned
157            to the client during negotiation, and then later checked for
158            consistency.
159        @param service DBus object of the service that should become
160            connected as a result of the negotiation.
161        @param params list of static IP parameters we will be verifying.
162
163        """
164        rules = self.make_lease_negotiation_rules(options)
165        if self.CONFIGURE_STATIC_IP_ADDRESS in params:
166            # Add a rule that expects the client to release the lease.
167            rules.append(dhcp_handling_rule.DhcpHandlingRule_AcceptRelease(
168                    self.server_ip,
169                    options,
170                    {}))
171        self.test_dhcp_negotiation(rules, service)
172
173        # Check to make sure that the configured IP address of the client
174        # matches the configured static IP address.
175        static_ip_options = options.copy()
176        static_ip_options.update(self._static_ip_options)
177        self.check_dhcp_config(static_ip_options)
178        self.check_saved_ip(service, options)
179
180
181    def test_body(self):
182        """The test main body"""
183        subnet_mask = self.ethernet_pair.interface_subnet_mask
184        intended_ip = dhcp_test_base.DhcpTestBase.rewrite_ip_suffix(
185                subnet_mask,
186                self.server_ip,
187                self.INTENDED_IP_SUFFIX)
188        # Two real name servers, and a bogus one to be unpredictable.
189        dns_servers = ['8.8.8.8', '8.8.4.4', '192.168.87.88']
190        domain_name = 'corp.google.com'
191        dns_search_list = [
192                'corgie.google.com',
193                'lies.google.com',
194                'that.is.a.tasty.burger.google.com',
195                ]
196        # This is the pool of information the server will give out to the client
197        # upon request.
198        dhcp_options = {
199                dhcp_packet.OPTION_SERVER_ID : self.server_ip,
200                dhcp_packet.OPTION_SUBNET_MASK : subnet_mask,
201                dhcp_packet.OPTION_IP_LEASE_TIME : self.LEASE_TIME_SECONDS,
202                dhcp_packet.OPTION_REQUESTED_IP : intended_ip,
203                dhcp_packet.OPTION_DNS_SERVERS : dns_servers,
204                dhcp_packet.OPTION_DOMAIN_NAME : domain_name,
205                dhcp_packet.OPTION_DNS_DOMAIN_SEARCH_LIST : dns_search_list,
206                }
207        service = self.find_ethernet_service(
208                self.ethernet_pair.peer_interface_name)
209
210        manager = self.shill_proxy.manager
211        with shill_temporary_profile.ShillTemporaryProfile(
212                manager, profile_name=self.TEST_PROFILE_NAME):
213
214            self.connect_dynamic_ip(dhcp_options, service)
215
216            for params in self._static_param_list:
217                static_ip_config = self.create_static_ip_config(params)
218                with shill_context.StaticIPContext(service, static_ip_config):
219                    self.connect_static_ip(dhcp_options, service, params)
220
221            self.connect_dynamic_ip(dhcp_options, service)
222
223
224    def run_once(self, static_param_list):
225        """Setup the static parameter list before calling the DhcpTestBase
226        main loop.
227
228        @param static_param_list list of iterable properties to configure
229            for each static IP test.
230
231        """
232        self._static_param_list = static_param_list
233        super(network_DhcpStaticIP, self).run_once()
234