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