Home | History | Annotate | Download | only in network_UdevRename
      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