1# Copyright (c) 2010 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 5import logging 6import os 7import time 8from autotest_lib.client.bin import test 9from autotest_lib.client.common_lib import error, utils 10 11def GetInterfaceList(): 12 """Gets the list of network interfaces on this host. 13 14 @return List containing a string for each interface name 15 """ 16 return os.listdir('/sys/class/net') 17 18 19def FindInterface(typelist=('wlan','mlan')): 20 """Finds an interface that we can unload the driver for. 21 22 Retrieves the name of a network interface that can be 23 removed by unbinding/rebinding its device. 24 25 @param typelist An iterable of interface prefixes to filter from. Only 26 return an interface that matches one of these prefixes 27 @return string The name of the interface 28 29 """ 30 interface_list = GetInterfaceList() 31 # Slice through the interfaces on a per-prefix basis priority order. 32 for prefix in typelist: 33 for intf in interface_list: 34 if intf.startswith(prefix): 35 return intf 36 37 logging.debug('Could not find an interface') 38 39 40def RestartInterface(): 41 """Find and restart a network interface by unbinding and rebinding the device. 42 43 This function simulates a device eject and re-insert. 44 45 @return True if successful, or if nothing was done 46 """ 47 interface = FindInterface() 48 if interface is None: 49 logging.debug('No interface available for test') 50 # We return success although we haven't done anything! 51 return True 52 53 logging.debug('Using %s for restart', str(interface)) 54 55 devicePath = '/sys/class/net/%s/device' % interface 56 deviceRealPath = os.path.realpath(devicePath) 57 58 payload = os.path.basename(deviceRealPath) 59 60 driverPath = os.path.join(devicePath, 'driver') 61 driverRealPath = os.path.realpath(driverPath) 62 63 # Unbind the wireless device 64 try: 65 utils.open_write_close(os.path.join(driverRealPath, 'unbind'), payload) 66 except Exception, e: 67 raise error.TestFail('Could not unbind %s driver: %s' % (interface, e)) 68 69 # Rebind the wireless device 70 try: 71 utils.open_write_close(os.path.join(driverRealPath, 'bind'), payload) 72 except Exception, e: 73 raise error.TestFail('Could not bind %s driver: %s' % (interface, e)) 74 75 return True 76 77def Upstart(service, action='status'): 78 """Front-end to the 'initctl' command. 79 80 Accepts arguments to initctl and executes them, raising an exception 81 if it fails. 82 83 @param service Service name to call initctl with. 84 @param action Action to perform on the service 85 86 @return The returned service status from initctl 87 """ 88 if action not in ('status', 'start', 'stop'): 89 logging.debug('Bad action') 90 return None 91 92 try: 93 status_str = utils.system_output('initctl %s %s' % (action, service)) 94 status_list = status_str.split(' ') 95 except error.CmdError, e: 96 logging.debug(e) 97 raise error.TestFail('Failed to perform %s on service %s' % 98 (action, service)) 99 100 if status_list[0] != service: 101 return None 102 103 return status_list[1].rstrip(',\n') 104 105 106def RestartUdev(): 107 """Restarts the udev service. 108 109 Stops and then restarts udev 110 111 @return True if successful 112 """ 113 if Upstart('udev') != 'start/running': 114 raise error.TestFail('udev not running') 115 116 if Upstart('udev', 'stop') != 'stop/waiting': 117 raise error.TestFail('could not stop udev') 118 119 if Upstart('udev', 'start') != 'start/running': 120 raise error.TestFail('could not restart udev') 121 122 if Upstart('udev') != 'start/running': 123 raise error.TestFail('udev failed to stay running') 124 125 return True 126 127 128def TestUdevDeviceList(restart_fn): 129 """Test interface list. 130 131 Performs an operation, then compares the network interface list between 132 a time before the test and after. Raises an exception if the list changes. 133 134 @param restart_fn The function that performs the operation of interest 135 """ 136 iflist_pre = GetInterfaceList() 137 if not restart_fn(): 138 raise error.TestFail('Reset function failed') 139 140 # Debugging for crbug.com/418983,423741,424605,425066 added the loop to see 141 # if it takes more than 3 attempts for all of the interfaces to come back up. 142 for i in range(3): 143 # We need to wait for udev to rename (or not) the interface! 144 time.sleep(10) 145 146 iflist_post = GetInterfaceList() 147 148 if iflist_post == iflist_pre: 149 logging.debug('Interfaces remain the same after %s; number of tries: %d', 150 restart_fn.__name__, i) 151 return 152 153 raise error.TestFail('Interfaces changed after %s (%s != %s)' % 154 (restart_fn.__name__, str(iflist_pre), 155 str(iflist_post))) 156 157 158class network_UdevRename(test.test): 159 """Test that network devices are not renamed unexpectedly""" 160 version = 1 161 162 def run_once(self): 163 """Run the tests""" 164 TestUdevDeviceList(RestartUdev) 165 TestUdevDeviceList(RestartInterface) 166