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