| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import logging |
| import time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.cros import dhcp_handling_rule |
| from autotest_lib.client.cros import dhcp_packet |
| from autotest_lib.client.cros import dhcp_test_base |
| |
| # dhcpcd has a 20 second minimal accepted lease time |
| LEASE_TIME_SECONDS = 20 |
| # dhcpcd should request a renewal after this many seconds. |
| LEASE_T1_TIME = 10 |
| # dhcpcd will broadcast a REQUEST after this many seconds. |
| LEASE_T2_TIME = 15 |
| # We had better have lost the lease 25 seconds after we gained it. |
| DHCP_RENEWAL_TIMEOUT_SECONDS = 25 |
| # We'll fill in the subnet and give this address to the client. |
| INTENDED_IP_SUFFIX = "0.0.0.101" |
| # How far off the expected deadlines we'll accept the T1/T2 packets. |
| RENEWAL_TIME_DELTA_SECONDS = 2.0 |
| # Time by which we are sure shill will give up on the DHCP client. |
| DHCP_ATTEMPT_TIMEOUT_SECONDS = 40 |
| |
| class network_DhcpRenew(dhcp_test_base.DhcpTestBase): |
| """Tests DHCP renewal process in the connection manager.""" |
| def test_body(self): |
| subnet_mask = self.ethernet_pair.interface_subnet_mask |
| intended_ip = dhcp_test_base.DhcpTestBase.rewrite_ip_suffix( |
| subnet_mask, |
| self.server_ip, |
| INTENDED_IP_SUFFIX) |
| # Two real name servers, and a bogus one to be unpredictable. |
| dns_servers = ["8.8.8.8", "8.8.4.4", "192.168.87.88"] |
| domain_name = "corp.google.com" |
| dns_search_list = [ |
| "corgie.google.com", |
| "lies.google.com", |
| "that.is.a.tasty.burger.google.com", |
| ] |
| # This is the pool of information the server will give out to the client |
| # upon request. |
| dhcp_options = { |
| dhcp_packet.OPTION_SERVER_ID : self.server_ip, |
| dhcp_packet.OPTION_SUBNET_MASK : subnet_mask, |
| dhcp_packet.OPTION_IP_LEASE_TIME : LEASE_TIME_SECONDS, |
| dhcp_packet.OPTION_REQUESTED_IP : intended_ip, |
| dhcp_packet.OPTION_DNS_SERVERS : dns_servers, |
| dhcp_packet.OPTION_DOMAIN_NAME : domain_name, |
| dhcp_packet.OPTION_DNS_DOMAIN_SEARCH_LIST : dns_search_list, |
| dhcp_packet.OPTION_RENEWAL_T1_TIME_VALUE : LEASE_T1_TIME, |
| dhcp_packet.OPTION_REBINDING_T2_TIME_VALUE : LEASE_T2_TIME, |
| } |
| self.negotiate_and_check_lease(dhcp_options) |
| # This is very imprecise, since there is some built in delay in |
| # negotiate_new_lease() for settings propagations, but we're not |
| # interested in microsecond timings anyway. |
| lease_start_time = time.time() |
| t1_deadline = lease_start_time + LEASE_T1_TIME |
| t2_deadline = lease_start_time + LEASE_T2_TIME |
| # Ignore the T1 deadline packet. |
| t1_handler = dhcp_handling_rule.DhcpHandlingRule_RespondToRequest( |
| intended_ip, |
| self.server_ip, |
| dhcp_options, |
| {}, |
| should_respond=False) |
| t1_handler.target_time_seconds = t1_deadline |
| t1_handler.allowable_time_delta_seconds = RENEWAL_TIME_DELTA_SECONDS |
| t2_handler = dhcp_handling_rule.DhcpHandlingRule_RespondToPostT2Request( |
| intended_ip, |
| self.server_ip, |
| dhcp_options, |
| {}, |
| should_respond=False) |
| t2_handler.target_time_seconds = t2_deadline |
| t2_handler.allowable_time_delta_seconds = RENEWAL_TIME_DELTA_SECONDS |
| discovery_handler = \ |
| dhcp_handling_rule.DhcpHandlingRule_RespondToDiscovery( |
| intended_ip, |
| self.server_ip, |
| dhcp_options, |
| {}, |
| should_respond=False) |
| rules = [t1_handler, t2_handler, discovery_handler] |
| rules[-1].is_final_handler = True |
| self.server.start_test(rules, DHCP_RENEWAL_TIMEOUT_SECONDS) |
| self.server.wait_for_test_to_finish() |
| if not self.server.last_test_passed: |
| raise error.TestFail("Test server didn't get all the messages it " |
| "was told to expect for renewal.") |
| |
| # The service should leave the connected state after shill attempts |
| # one last DHCP attempt from scratch. We may miss the transition to the |
| # "idle" state since the system immediately attempts to re-connect, so |
| # we also test for the "configuration" state. |
| service = self.find_ethernet_service( |
| self.ethernet_pair.peer_interface_name) |
| (successful, state, duration) = self.shill_proxy.wait_for_property_in( |
| service, |
| self.shill_proxy.SERVICE_PROPERTY_STATE, |
| ('failure', 'idle', 'configuration'), |
| DHCP_ATTEMPT_TIMEOUT_SECONDS) |
| if not successful: |
| raise error.TestFail('Service failed to go idle in %ds (state %s)' % |
| (duration, state)) |
| logging.info('In state "%s" after %d seconds', state, duration) |