Home | History | Annotate | Download | only in tests
      1 import logging, re, random
      2 from autotest_lib.client.common_lib import error
      3 from autotest_lib.client.virt import aexpect
      4 
      5 
      6 def run_iofuzz(test, params, env):
      7     """
      8     KVM iofuzz test:
      9     1) Log into a guest
     10     2) Enumerate all IO port ranges through /proc/ioports
     11     3) On each port of the range:
     12         * Read it
     13         * Write 0 to it
     14         * Write a random value to a random port on a random order
     15 
     16     If the guest SSH session hangs, the test detects the hang and the guest
     17     is then rebooted. The test fails if we detect the qemu process to terminate
     18     while executing the process.
     19 
     20     @param test: kvm test object
     21     @param params: Dictionary with the test parameters
     22     @param env: Dictionary with test environment.
     23     """
     24     def outb(session, port, data):
     25         """
     26         Write data to a given port.
     27 
     28         @param session: SSH session stablished to a VM
     29         @param port: Port where we'll write the data
     30         @param data: Integer value that will be written on the port. This
     31                 value will be converted to octal before its written.
     32         """
     33         logging.debug("outb(0x%x, 0x%x)", port, data)
     34         outb_cmd = ("echo -e '\\%s' | dd of=/dev/port seek=%d bs=1 count=1" %
     35                     (oct(data), port))
     36         try:
     37             session.cmd(outb_cmd)
     38         except aexpect.ShellError, e:
     39             logging.debug(e)
     40 
     41 
     42     def inb(session, port):
     43         """
     44         Read from a given port.
     45 
     46         @param session: SSH session stablished to a VM
     47         @param port: Port where we'll read data
     48         """
     49         logging.debug("inb(0x%x)", port)
     50         inb_cmd = "dd if=/dev/port seek=%d of=/dev/null bs=1 count=1" % port
     51         try:
     52             session.cmd(inb_cmd)
     53         except aexpect.ShellError, e:
     54             logging.debug(e)
     55 
     56 
     57     def fuzz(session, inst_list):
     58         """
     59         Executes a series of read/write/randwrite instructions.
     60 
     61         If the guest SSH session hangs, an attempt to relogin will be made.
     62         If it fails, the guest will be reset. If during the process the VM
     63         process abnormally ends, the test fails.
     64 
     65         @param inst_list: List of instructions that will be executed.
     66         @raise error.TestFail: If the VM process dies in the middle of the
     67                 fuzzing procedure.
     68         """
     69         for (op, operand) in inst_list:
     70             if op == "read":
     71                 inb(session, operand[0])
     72             elif op == "write":
     73                 outb(session, operand[0], operand[1])
     74             else:
     75                 raise error.TestError("Unknown command %s" % op)
     76 
     77             if not session.is_responsive():
     78                 logging.debug("Session is not responsive")
     79                 if vm.process.is_alive():
     80                     logging.debug("VM is alive, try to re-login")
     81                     try:
     82                         session = vm.wait_for_login(timeout=10)
     83                     except:
     84                         logging.debug("Could not re-login, reboot the guest")
     85                         session = vm.reboot(method="system_reset")
     86                 else:
     87                     raise error.TestFail("VM has quit abnormally during "
     88                                          "%s: %s" % (op, operand))
     89 
     90 
     91     login_timeout = float(params.get("login_timeout", 240))
     92     vm = env.get_vm(params["main_vm"])
     93     vm.verify_alive()
     94     session = vm.wait_for_login(timeout=login_timeout)
     95 
     96     try:
     97         ports = {}
     98         r = random.SystemRandom()
     99 
    100         logging.info("Enumerate guest devices through /proc/ioports")
    101         ioports = session.cmd_output("cat /proc/ioports")
    102         logging.debug(ioports)
    103         devices = re.findall("(\w+)-(\w+)\ : (.*)", ioports)
    104 
    105         skip_devices = params.get("skip_devices","")
    106         fuzz_count = int(params.get("fuzz_count", 10))
    107 
    108         for (beg, end, name) in devices:
    109             ports[(int(beg, base=16), int(end, base=16))] = name.strip()
    110 
    111         for (beg, end) in ports.keys():
    112             name = ports[(beg, end)]
    113             if name in skip_devices:
    114                 logging.info("Skipping device %s", name)
    115                 continue
    116 
    117             logging.info("Fuzzing %s, port range 0x%x-0x%x", name, beg, end)
    118             inst = []
    119 
    120             # Read all ports of the range
    121             for port in range(beg, end + 1):
    122                 inst.append(("read", [port]))
    123 
    124             # Write 0 to all ports of the range
    125             for port in range(beg, end + 1):
    126                 inst.append(("write", [port, 0]))
    127 
    128             # Write random values to random ports of the range
    129             for seq in range(fuzz_count * (end - beg + 1)):
    130                 inst.append(("write",
    131                              [r.randint(beg, end), r.randint(0,255)]))
    132 
    133             fuzz(session, inst)
    134 
    135     finally:
    136         session.close()
    137