• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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