2019-08-20 23:41:18

by Branden Bonaby

[permalink] [raw]
Subject: [PATCH v3 0/3] hv: vmbus: add fuzz testing to hv device

This patchset introduces a testing framework for Hyper-V drivers.
This framework allows us to introduce delays in the packet receive
path on a per-device basis. While the current code only supports
introducing arbitrary delays in the host/guest communication path,
we intend to expand this to support error injection in the future.

changes in v3:
patch 2: change call to IS_ERR_OR_NULL, to IS_ERR.

patch 3: Align python tool to match Linux coding style.

Changes in v2:
Patch 1: As per Vitaly's suggestion, wrapped the test code under an
#ifdef and updated the Kconfig file, so that the test code
will only be used when the config option is set to true.
(default is false).

Updated hyperv_vmbus header to contain new #ifdef with new
new functions for the test code.

Patch 2: Moved code from under sysfs to debugfs and wrapped it under
the new ifdef.

Updated MAINTAINERS file with new debugfs-hyperv file under
the section for hyperv.

Patch 3: Updated testing tool with new debugfs location.

Branden Bonaby (3):
drivers: hv: vmbus: Introduce latency testing
drivers: hv: vmbus: add fuzz test attributes to debugfs
tools: hv: add vmbus testing tool

Documentation/ABI/testing/debugfs-hyperv | 21 ++
MAINTAINERS | 1 +
drivers/hv/Kconfig | 7 +
drivers/hv/connection.c | 3 +
drivers/hv/hyperv_vmbus.h | 20 ++
drivers/hv/ring_buffer.c | 7 +
drivers/hv/vmbus_drv.c | 167 +++++++++++
include/linux/hyperv.h | 21 ++
tools/hv/vmbus_testing | 342 +++++++++++++++++++++++
9 files changed, 589 insertions(+)
create mode 100644 Documentation/ABI/testing/debugfs-hyperv
create mode 100644 tools/hv/vmbus_testing

--
2.17.1


2019-08-20 23:41:45

by Branden Bonaby

[permalink] [raw]
Subject: [PATCH v3 3/3] tools: hv: add vmbus testing tool

This is a userspace tool to drive the testing. Currently it supports
introducing user specified delay in the host to guest communication
path on a per-channel basis.

Signed-off-by: Branden Bonaby <[email protected]>
---
Changes in v3:
- Align python tool to match Linux coding style.

Changes in v2:
- Move testing location to new location in debugfs.

tools/hv/vmbus_testing | 342 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 342 insertions(+)
create mode 100644 tools/hv/vmbus_testing

diff --git a/tools/hv/vmbus_testing b/tools/hv/vmbus_testing
new file mode 100644
index 000000000000..0f249f6ee698
--- /dev/null
+++ b/tools/hv/vmbus_testing
@@ -0,0 +1,342 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Program to allow users to fuzz test Hyper-V drivers
+# by interfacing with Hyper-V debugfs directories
+# author: Branden Bonaby
+
+import os
+import cmd
+import argparse
+from collections import defaultdict
+from argparse import RawDescriptionHelpFormatter
+
+# debugfs paths for vmbus must exist (same as in lsvmbus)
+debugfs_sys_path = "/sys/kernel/debug/hyperv"
+if not os.path.isdir(debugfs_sys_path):
+ print("{} doesn't exist/check permissions".format(debugfs_sys_path))
+ exit(-1)
+# Do not change unless, you change the debugfs attributes
+# in "/sys/kernel/debug/hyperv/<UUID>/". All fuzz testing
+# attributes will start with "fuzz_test".
+pathlen = len(debugfs_sys_path)
+fuzz_state_location = "fuzz_test_state"
+fuzz_states = {
+ 0 : "Disable",
+ 1 : "Enable"
+}
+
+fuzz_methods = {
+ 1 : "Delay_testing"
+}
+
+fuzz_delay_types = {
+ 1 : "fuzz_test_buffer_interrupt_delay",
+ 2 : "fuzz_test_message_delay"
+}
+
+def parse_args():
+ parser = argparse.ArgumentParser(description = "vmbus_testing "
+ "[-s] [0|1] [-q] [-p] <debugfs-path>\n""vmbus_testing [-s]"
+ " [0|1] [-q][-p] <debugfs-path> delay [-d] [val][val] [-E|-D]\n"
+ "vmbus_testing [-q] disable-all\n"
+ "vmbus_testing [-q] view [-v|-V]\n"
+ "vmbus_testing --version",
+ epilog = "Current testing options {}".format(fuzz_methods),
+ prog = 'vmbus_testing',
+ formatter_class = RawDescriptionHelpFormatter)
+ subparsers = parser.add_subparsers(dest = "action")
+ parser.add_argument("--version", action = "version",
+ version = '%(prog)s 1.0')
+ parser.add_argument("-q","--quiet", action = "store_true",
+ help = "silence none important test messages")
+ parser.add_argument("-s","--state", metavar = "", type = int,
+ choices = range(0, 2),
+ help = "Turn testing ON or OFF for a single device."
+ " The value (1) will turn testing ON. The value"
+ " of (0) will turn testing OFF with the default set"
+ " to (0).")
+ parser.add_argument("-p","--path", metavar = "",
+ help = "Refers to the debugfs path to a vmbus device."
+ " If the path is not a valid path to a vmbus device,"
+ " the program will exit. The path must be the"
+ " absolute path; use the lsvmbus command to find"
+ " the path.")
+ parser_delay = subparsers.add_parser("delay",
+ help = "Delay buffer/message reads in microseconds.",
+ description = "vmbus_testing -s [0|1] [-q] -p "
+ "<debugfs-path> delay -d "
+ "[buffer-delay-value] [message-delay-value]\n"
+ "vmbus_testing [-q] delay [buffer-delay-value] "
+ "[message-delay-value] -E\n"
+ "vmbus_testing [-q] delay [buffer-delay-value] "
+ "[message-delay-value] -D",
+ formatter_class = RawDescriptionHelpFormatter)
+ delay_group = parser_delay.add_mutually_exclusive_group()
+ delay_group.add_argument("-E", "--en_all", action = "store_true",
+ help = "Enable Buffer/Message Delay testing on ALL"
+ " devices. Use -d option with this to set the values"
+ " for both the buffer delay and the message delay. No"
+ " value can be (0) or less than (-1). If testing is"
+ " disabled on a device prior to running this command,"
+ " testing will be enabled on the device as a result"
+ " of this command.")
+ delay_group.add_argument("-D", "--dis_all", action = "store_true",
+ help = "Disable Buffer/Message delay testing on ALL"
+ " devices. A value equal to (-1) will keep the"
+ " current delay value, and a value equal to (0) will"
+ " remove delay testing for the specfied delay column."
+ " only values (-1) and (0) will be accepted but at"
+ " least one value must be a (0) or a (-1).")
+ parser_delay.add_argument("-d", "--delay_time", metavar = "", nargs = 2,
+ type = check_range, default = [0, 0], required = (True),
+ help = "Buffer/message delay time. A value of (0) will"
+ "disable delay testing on the specified delay column,"
+ " while a value of (-1) will ignore the specified"
+ " delay column. The default values are [0] & [0]."
+ " The first column represents the buffer delay value"
+ " and the second represents the message delay value."
+ " Value constraints: -1 <= value <= 1000.")
+ parser_dis_all = subparsers.add_parser("disable-all",
+ help = "Disable ALL testing on all vmbus devices.",
+ description = "vmbus_testing disable-all",
+ formatter_class = RawDescriptionHelpFormatter)
+ parser_view = subparsers.add_parser("view",
+ help = "View testing on vmbus devices.",
+ description = "vmbus_testing view -V\n"
+ "vmbus_testing -p <debugfs-path> view -v",
+ formatter_class = RawDescriptionHelpFormatter)
+ view_group = parser_view.add_mutually_exclusive_group()
+ view_group.add_argument("-V", "--view_all", action = "store_true",
+ help = "View the test status for all vmbus devices.")
+ view_group.add_argument("-v", "--view_single", action = "store_true",
+ help = "View test values for a single vmbus device.")
+
+ return parser.parse_args()
+
+# value checking for range checking input in parser
+def check_range(arg1):
+ try:
+ val = int(arg1)
+ except ValueError as err:
+ raise argparse.ArgumentTypeError(str(err))
+ if val < -1 or val > 1000:
+ message = ("\n\nExpected -1 <= value <= 1000, got value"
+ " {}\n").format(val)
+ raise argparse.ArgumentTypeError(message)
+ return val
+
+def main():
+ try:
+ dev_list = []
+ for dir in os.listdir(debugfs_sys_path):
+ dev_list.append(os.path.join(debugfs_sys_path, dir))
+ #key value, pairs
+ #key = debugfs device path
+ #value = list of fuzz testing attributes.
+ dev_files = defaultdict(list)
+ for dev in dev_list:
+ path = os.path.join(dev, "delay")
+ for f in os.listdir(path):
+ if (f.startswith("fuzz_test")):
+ dev_files[path].append(f)
+
+ dev_files.default_factory = None
+ args = parse_args()
+ path = args.path
+ state = args.state
+ quiet = args.quiet
+ if (not quiet):
+ print("*** Use lsvmbus to get vmbus device type"
+ " information.*** ")
+ if (state is not None and validate_args_path(path, dev_list)):
+ if (state is not get_test_state(path)):
+ change_test_state(path, quiet)
+ state = get_test_state(path)
+ if (state == 0 and path is not None):
+ disable_testing_single_device(path, 0, quiet)
+ return
+ #Use subparsers as the key for different fuzz testing methods
+ if (args.action == "delay"):
+ delay = args.delay_time
+ if (validate_delay_values(args, delay)):
+ delay_test_all_devices(dev_list, delay, quiet)
+ elif (validate_args_path(path, dev_list)):
+ if(get_test_state(path) == 1):
+ delay_test_store(path, delay, quiet)
+ return
+ print("device testing OFF, use -s 1 to turn ON")
+ elif (args.action == "disable-all"):
+ disable_all_testing(dev_list, quiet)
+ elif (args.action == "view"):
+ if (args.view_all):
+ all_devices_test_status(dev_list)
+ elif (args.view_single):
+ if (validate_args_path(path, dev_list)):
+ device_test_values(dev_files, path)
+ return
+ print("Error,(check path) usage: -p"\
+ " <debugfs device path> view -v")
+ except AttributeError:
+ print("check usage, 1 or more elements not provided")
+ exit(-1)
+
+# Validate delay values to make sure they are acceptable to
+# to either enable all delays on a device or disable all
+# delays on a device
+def validate_delay_values(args, delay):
+ if (args.en_all):
+ for i in delay:
+ if (i < -1 or i == 0):
+ print("\nError, Values must be"
+ " equal to -1 or be > 0, use"
+ " -d option")
+ exit(-1)
+ return True
+ elif (args.dis_all):
+ for i in delay:
+ if (i < -1 or i > 0):
+ print("\nError, at least 1 value"
+ " is not a (0) or a (-1)")
+ exit(-1)
+ return True
+ else:
+ return False
+
+
+# Validate argument path
+def validate_args_path(path, dev_list):
+ if (path in dev_list):
+ return True
+ else:
+ return False
+
+# display Testing status of single device
+def device_test_values(dev_files, path):
+
+ delay_path = os.path.join(path, 'delay')
+ for test in dev_files.get(delay_path):
+ print("{}".format(test), end = '')
+ print((" value = {}")\
+ .format(read_test_files(os.path.join(delay_path, test))))
+
+# display Testing state of devices
+def all_devices_test_status(dev_list):
+ for device in dev_list:
+ if (get_test_state(device) is 1):
+ print("Testing = ON for: {}".format(device.split("/")[5]))
+ else:
+ print("Testing = OFF for: {}".format(device.split("/")[5]))
+
+# read the vmbus device files, path must be absolute path before calling
+def read_test_files(path):
+ try:
+ with open(path,"r") as f:
+ state = f.readline().strip()
+ if (state == 'N'):
+ state = 0
+ elif (state == 'Y'):
+ state = 1
+ return int(state)
+
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on file {2}"
+ .format(errno, strerror, path))
+ exit(-1)
+ except ValueError:
+ print ("Element to int conversion error in: \n{}".format(path))
+ exit(-1)
+
+# writing to vmbus device files, path must be absolute path before calling
+def write_test_files(path, value):
+ try:
+ with open(path,"w") as f:
+ f.write("{}".format(value))
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on file {2}"
+ .format(errno, strerror, path))
+ exit(-1)
+
+# change testing state of device
+def change_test_state(device, quiet):
+ state_path = os.path.join(device, fuzz_state_location)
+ if (get_test_state(device) is 0):
+ write_test_files(state_path, 1)
+ if (not quiet):
+ print("Testing = ON for device: {}"
+ .format(state_path.split("/")[5]))
+ else:
+ write_test_files(state_path, 0)
+ if (not quiet):
+ print("Testing = OFF for device: {}"
+ .format(state_path.split("/")[5]))
+
+# get testing state of device
+def get_test_state(device):
+ #state == 1 - test = ON
+ #state == 0 - test = OFF
+ return read_test_files(os.path.join(device, fuzz_state_location))
+
+# Enter 1 - 1000 microseconds, into a single device using the
+# fuzz_test_buffer_interrupt_delay and fuzz_test_message_delay
+# debugfs attributes
+def delay_test_store(device,delay_length, quiet):
+
+ try:
+ # delay[0]- buffer delay, delay[1]- message delay
+ buff_test = os.path.join(os.path.sep,device, 'delay',
+ fuzz_delay_types.get(1))
+ mess_test = os.path.join(os.path.sep,device, 'delay',
+ fuzz_delay_types.get(2))
+
+ if (delay_length[0] >= 0):
+ write_test_files(buff_test, delay_length[0])
+ if (delay_length[1] >= 0):
+ write_test_files(mess_test, delay_length[1])
+ if (not quiet):
+ print("Buffer delay testing = {} for: {}"
+ .format(read_test_files(buff_test),
+ buff_test.split("/")[5]))
+ print("Message delay testing = {} for: {}"
+ .format(read_test_files(mess_test),
+ mess_test.split("/")[5]))
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on files {2}{3}"
+ .format(errno, strerror, buff_test, mess_test))
+ exit(-1)
+
+#enabling/disabling delay testing on all devices
+def delay_test_all_devices(dev_list,delay,quiet):
+
+ for device in (dev_list):
+ if (get_test_state(device) is 0):
+ change_test_state(device,quiet)
+ delay_test_store(device, delay, quiet)
+
+#disabling testing on single device
+def disable_testing_single_device(device,test_type,quiet):
+
+ #test_type represents corresponding key
+ #delay method in delay_methods dict.
+ #special type 0 , used to disable all
+ #testing on SINGLE device.
+
+ if (test_type is 1 or test_type is 0):
+ #disable list [buffer,message]
+ disable_delay = [0, 0]
+ if (get_test_state(device) is 1):
+ change_test_state(device, quiet)
+ delay_test_store(device, disable_delay, quiet)
+
+#disabling testing on ALL devices
+def disable_all_testing(dev_list,quiet):
+
+ #delay disable list [buffer,message]
+ for device in dev_list:
+ disable_testing_single_device(device, 0, quiet)
+
+if __name__ == "__main__":
+ main()
--
2.17.1

2019-08-22 02:47:53

by Harry Zhang

[permalink] [raw]
Subject: RE: [PATCH v3 3/3] tools: hv: add vmbus testing tool

Tool function issues: Please validate args errors for '-p' and '--path', in or following validate_args_path().

Comments of functionality:
- it's confusing when fuzz_testing are all OFF, then user run ' python3 /home/lisa/vmbus_testing -p /sys/kernel/debug/hyperv/000d3a6e-4548-000d-3a6e-4548000d3a6e delay -d 0 0 -D ' which will enable all delay testing state ('Y' in state files). even I used "-D", "--dis_all" param.
- if we have subparsers of "disable-all" for the testing tool, then probably we don't need the mutually_exclusive_group under subparsers of "delay"
- the path argument (-p) could be an argument for subparsers of "delay" and "view" only.

Regards,
Harry

-----Original Message-----
From: [email protected] <[email protected]> On Behalf Of Branden Bonaby
Sent: Tuesday, August 20, 2019 4:40 PM
To: KY Srinivasan <[email protected]>; Haiyang Zhang <[email protected]>; Stephen Hemminger <[email protected]>; [email protected]
Cc: brandonbonaby94 <[email protected]>; [email protected]; [email protected]
Subject: [PATCH v3 3/3] tools: hv: add vmbus testing tool

This is a userspace tool to drive the testing. Currently it supports introducing user specified delay in the host to guest communication path on a per-channel basis.

Signed-off-by: Branden Bonaby <[email protected]>
---
Changes in v3:
- Align python tool to match Linux coding style.

Changes in v2:
- Move testing location to new location in debugfs.

tools/hv/vmbus_testing | 342 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 342 insertions(+)
create mode 100644 tools/hv/vmbus_testing

diff --git a/tools/hv/vmbus_testing b/tools/hv/vmbus_testing new file mode 100644 index 000000000000..0f249f6ee698
--- /dev/null
+++ b/tools/hv/vmbus_testing
@@ -0,0 +1,342 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Program to allow users to fuzz test Hyper-V drivers # by interfacing
+with Hyper-V debugfs directories # author: Branden Bonaby
+
+import os
+import cmd
+import argparse
+from collections import defaultdict
+from argparse import RawDescriptionHelpFormatter
+
+# debugfs paths for vmbus must exist (same as in lsvmbus)
+debugfs_sys_path = "/sys/kernel/debug/hyperv"
+if not os.path.isdir(debugfs_sys_path):
+ print("{} doesn't exist/check permissions".format(debugfs_sys_path))
+ exit(-1)
+# Do not change unless, you change the debugfs attributes # in
+"/sys/kernel/debug/hyperv/<UUID>/". All fuzz testing # attributes will
+start with "fuzz_test".
+pathlen = len(debugfs_sys_path)
+fuzz_state_location = "fuzz_test_state"
+fuzz_states = {
+ 0 : "Disable",
+ 1 : "Enable"
+}
+
+fuzz_methods = {
+ 1 : "Delay_testing"
+}
+
+fuzz_delay_types = {
+ 1 : "fuzz_test_buffer_interrupt_delay",
+ 2 : "fuzz_test_message_delay"
+}
+
+def parse_args():
+ parser = argparse.ArgumentParser(description = "vmbus_testing "
+ "[-s] [0|1] [-q] [-p] <debugfs-path>\n""vmbus_testing [-s]"
+ " [0|1] [-q][-p] <debugfs-path> delay [-d] [val][val] [-E|-D]\n"
+ "vmbus_testing [-q] disable-all\n"
+ "vmbus_testing [-q] view [-v|-V]\n"
+ "vmbus_testing --version",
+ epilog = "Current testing options {}".format(fuzz_methods),
+ prog = 'vmbus_testing',
+ formatter_class = RawDescriptionHelpFormatter)
+ subparsers = parser.add_subparsers(dest = "action")
+ parser.add_argument("--version", action = "version",
+ version = '%(prog)s 1.0')
+ parser.add_argument("-q","--quiet", action = "store_true",
+ help = "silence none important test messages")
+ parser.add_argument("-s","--state", metavar = "", type = int,
+ choices = range(0, 2),
+ help = "Turn testing ON or OFF for a single device."
+ " The value (1) will turn testing ON. The value"
+ " of (0) will turn testing OFF with the default set"
+ " to (0).")
+ parser.add_argument("-p","--path", metavar = "",
+ help = "Refers to the debugfs path to a vmbus device."
+ " If the path is not a valid path to a vmbus device,"
+ " the program will exit. The path must be the"
+ " absolute path; use the lsvmbus command to find"
+ " the path.")
+ parser_delay = subparsers.add_parser("delay",
+ help = "Delay buffer/message reads in microseconds.",
+ description = "vmbus_testing -s [0|1] [-q] -p "
+ "<debugfs-path> delay -d "
+ "[buffer-delay-value] [message-delay-value]\n"
+ "vmbus_testing [-q] delay [buffer-delay-value] "
+ "[message-delay-value] -E\n"
+ "vmbus_testing [-q] delay [buffer-delay-value] "
+ "[message-delay-value] -D",
+ formatter_class = RawDescriptionHelpFormatter)
+ delay_group = parser_delay.add_mutually_exclusive_group()
+ delay_group.add_argument("-E", "--en_all", action = "store_true",
+ help = "Enable Buffer/Message Delay testing on ALL"
+ " devices. Use -d option with this to set the values"
+ " for both the buffer delay and the message delay. No"
+ " value can be (0) or less than (-1). If testing is"
+ " disabled on a device prior to running this command,"
+ " testing will be enabled on the device as a result"
+ " of this command.")
+ delay_group.add_argument("-D", "--dis_all", action = "store_true",
+ help = "Disable Buffer/Message delay testing on ALL"
+ " devices. A value equal to (-1) will keep the"
+ " current delay value, and a value equal to (0) will"
+ " remove delay testing for the specfied delay column."
+ " only values (-1) and (0) will be accepted but at"
+ " least one value must be a (0) or a (-1).")
+ parser_delay.add_argument("-d", "--delay_time", metavar = "", nargs = 2,
+ type = check_range, default = [0, 0], required = (True),
+ help = "Buffer/message delay time. A value of (0) will"
+ "disable delay testing on the specified delay column,"
+ " while a value of (-1) will ignore the specified"
+ " delay column. The default values are [0] & [0]."
+ " The first column represents the buffer delay value"
+ " and the second represents the message delay value."
+ " Value constraints: -1 <= value <= 1000.")
+ parser_dis_all = subparsers.add_parser("disable-all",
+ help = "Disable ALL testing on all vmbus devices.",
+ description = "vmbus_testing disable-all",
+ formatter_class = RawDescriptionHelpFormatter)
+ parser_view = subparsers.add_parser("view",
+ help = "View testing on vmbus devices.",
+ description = "vmbus_testing view -V\n"
+ "vmbus_testing -p <debugfs-path> view -v",
+ formatter_class = RawDescriptionHelpFormatter)
+ view_group = parser_view.add_mutually_exclusive_group()
+ view_group.add_argument("-V", "--view_all", action = "store_true",
+ help = "View the test status for all vmbus devices.")
+ view_group.add_argument("-v", "--view_single", action = "store_true",
+ help = "View test values for a single vmbus
+device.")
+
+ return parser.parse_args()
+
+# value checking for range checking input in parser def
+check_range(arg1):
+ try:
+ val = int(arg1)
+ except ValueError as err:
+ raise argparse.ArgumentTypeError(str(err))
+ if val < -1 or val > 1000:
+ message = ("\n\nExpected -1 <= value <= 1000, got value"
+ " {}\n").format(val)
+ raise argparse.ArgumentTypeError(message)
+ return val
+
+def main():
+ try:
+ dev_list = []
+ for dir in os.listdir(debugfs_sys_path):
+ dev_list.append(os.path.join(debugfs_sys_path, dir))
+ #key value, pairs
+ #key = debugfs device path
+ #value = list of fuzz testing attributes.
+ dev_files = defaultdict(list)
+ for dev in dev_list:
+ path = os.path.join(dev, "delay")
+ for f in os.listdir(path):
+ if (f.startswith("fuzz_test")):
+ dev_files[path].append(f)
+
+ dev_files.default_factory = None
+ args = parse_args()
+ path = args.path
+ state = args.state
+ quiet = args.quiet
+ if (not quiet):
+ print("*** Use lsvmbus to get vmbus device type"
+ " information.*** ")
+ if (state is not None and validate_args_path(path, dev_list)):
+ if (state is not get_test_state(path)):
+ change_test_state(path, quiet)
+ state = get_test_state(path)
+ if (state == 0 and path is not None):
+ disable_testing_single_device(path, 0, quiet)
+ return
+ #Use subparsers as the key for different fuzz testing methods
+ if (args.action == "delay"):
+ delay = args.delay_time
+ if (validate_delay_values(args, delay)):
+ delay_test_all_devices(dev_list, delay, quiet)
+ elif (validate_args_path(path, dev_list)):
+ if(get_test_state(path) == 1):
+ delay_test_store(path, delay, quiet)
+ return
+ print("device testing OFF, use -s 1 to turn ON")
+ elif (args.action == "disable-all"):
+ disable_all_testing(dev_list, quiet)
+ elif (args.action == "view"):
+ if (args.view_all):
+ all_devices_test_status(dev_list)
+ elif (args.view_single):
+ if (validate_args_path(path, dev_list)):
+ device_test_values(dev_files, path)
+ return
+ print("Error,(check path) usage: -p"\
+ " <debugfs device path> view -v")
+ except AttributeError:
+ print("check usage, 1 or more elements not provided")
+ exit(-1)
+
+# Validate delay values to make sure they are acceptable to # to either
+enable all delays on a device or disable all # delays on a device def
+validate_delay_values(args, delay):
+ if (args.en_all):
+ for i in delay:
+ if (i < -1 or i == 0):
+ print("\nError, Values must be"
+ " equal to -1 or be > 0, use"
+ " -d option")
+ exit(-1)
+ return True
+ elif (args.dis_all):
+ for i in delay:
+ if (i < -1 or i > 0):
+ print("\nError, at least 1 value"
+ " is not a (0) or a (-1)")
+ exit(-1)
+ return True
+ else:
+ return False
+
+
+# Validate argument path
+def validate_args_path(path, dev_list):
+ if (path in dev_list):
+ return True
+ else:
+ return False
+
+# display Testing status of single device def
+device_test_values(dev_files, path):
+
+ delay_path = os.path.join(path, 'delay')
+ for test in dev_files.get(delay_path):
+ print("{}".format(test), end = '')
+ print((" value = {}")\
+
+ .format(read_test_files(os.path.join(delay_path, test))))
+
+# display Testing state of devices
+def all_devices_test_status(dev_list):
+ for device in dev_list:
+ if (get_test_state(device) is 1):
+ print("Testing = ON for: {}".format(device.split("/")[5]))
+ else:
+ print("Testing = OFF for:
+{}".format(device.split("/")[5]))
+
+# read the vmbus device files, path must be absolute path before
+calling def read_test_files(path):
+ try:
+ with open(path,"r") as f:
+ state = f.readline().strip()
+ if (state == 'N'):
+ state = 0
+ elif (state == 'Y'):
+ state = 1
+ return int(state)
+
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on file {2}"
+ .format(errno, strerror, path))
+ exit(-1)
+ except ValueError:
+ print ("Element to int conversion error in: \n{}".format(path))
+ exit(-1)
+
+# writing to vmbus device files, path must be absolute path before
+calling def write_test_files(path, value):
+ try:
+ with open(path,"w") as f:
+ f.write("{}".format(value))
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on file {2}"
+ .format(errno, strerror, path))
+ exit(-1)
+
+# change testing state of device
+def change_test_state(device, quiet):
+ state_path = os.path.join(device, fuzz_state_location)
+ if (get_test_state(device) is 0):
+ write_test_files(state_path, 1)
+ if (not quiet):
+ print("Testing = ON for device: {}"
+ .format(state_path.split("/")[5]))
+ else:
+ write_test_files(state_path, 0)
+ if (not quiet):
+ print("Testing = OFF for device: {}"
+ .format(state_path.split("/")[5]))
+
+# get testing state of device
+def get_test_state(device):
+ #state == 1 - test = ON
+ #state == 0 - test = OFF
+ return read_test_files(os.path.join(device,
+fuzz_state_location))
+
+# Enter 1 - 1000 microseconds, into a single device using the #
+fuzz_test_buffer_interrupt_delay and fuzz_test_message_delay # debugfs
+attributes def delay_test_store(device,delay_length, quiet):
+
+ try:
+ # delay[0]- buffer delay, delay[1]- message delay
+ buff_test = os.path.join(os.path.sep,device, 'delay',
+ fuzz_delay_types.get(1))
+ mess_test = os.path.join(os.path.sep,device, 'delay',
+ fuzz_delay_types.get(2))
+
+ if (delay_length[0] >= 0):
+ write_test_files(buff_test, delay_length[0])
+ if (delay_length[1] >= 0):
+ write_test_files(mess_test, delay_length[1])
+ if (not quiet):
+ print("Buffer delay testing = {} for: {}"
+ .format(read_test_files(buff_test),
+ buff_test.split("/")[5]))
+ print("Message delay testing = {} for: {}"
+ .format(read_test_files(mess_test),
+ mess_test.split("/")[5]))
+ except IOError as e:
+ errno, strerror = e.args
+ print("I/O error({0}): {1} on files {2}{3}"
+ .format(errno, strerror, buff_test, mess_test))
+ exit(-1)
+
+#enabling/disabling delay testing on all devices def
+delay_test_all_devices(dev_list,delay,quiet):
+
+ for device in (dev_list):
+ if (get_test_state(device) is 0):
+ change_test_state(device,quiet)
+ delay_test_store(device, delay, quiet)
+
+#disabling testing on single device
+def disable_testing_single_device(device,test_type,quiet):
+
+ #test_type represents corresponding key
+ #delay method in delay_methods dict.
+ #special type 0 , used to disable all
+ #testing on SINGLE device.
+
+ if (test_type is 1 or test_type is 0):
+ #disable list [buffer,message]
+ disable_delay = [0, 0]
+ if (get_test_state(device) is 1):
+ change_test_state(device, quiet)
+ delay_test_store(device, disable_delay, quiet)
+
+#disabling testing on ALL devices
+def disable_all_testing(dev_list,quiet):
+
+ #delay disable list [buffer,message]
+ for device in dev_list:
+ disable_testing_single_device(device, 0, quiet)
+
+if __name__ == "__main__":
+ main()
--
2.17.1

2019-08-22 06:48:32

by Branden Bonaby

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] tools: hv: add vmbus testing tool

On Thu, Aug 22, 2019 at 01:36:09AM +0000, Harry Zhang wrote:
> Tool function issues: Please validate args errors for '-p' and '--path', in or following validate_args_path().
>
> Comments of functionality:
> - it's confusing when fuzz_testing are all OFF, then user run ' python3 /home/lisa/vmbus_testing -p /sys/kernel/debug/hyperv/000d3a6e-4548-000d-3a6e-4548000d3a6e delay -d 0 0 -D ' which will enable all delay testing state ('Y' in state files). even I used "-D", "--dis_all" param.
> - if we have subparsers of "disable-all" for the testing tool, then probably we don't need the mutually_exclusive_group under subparsers of "delay"
> - the path argument (-p) could be an argument for subparsers of "delay" and "view" only.
>
> Regards,
> Harry
>

So I made the choice to keep disabling the state and disabling delay
testing seperate, because once we start adding other testing options
you wouldn't want to inadvertently disable all testing especially
if you were doing more than one type of test at a time.
So with your configuration

'python3 /home/lisa/vmbus_testing -p /sys/kernel/debug/hyperv/000d3a6e-4548-000d-3a6e-4548000d3a6e delay -d 0 0 -D '

this would stop all delay testing on all the devices but wouldn't change
their test state to OFF 'N'.So thats why I have the option -s --state to
change the state to Off with a -s 0. Then to disable all types of testing
and change the state to OFF thats where the 'disable-all' subparser comes in.
with:

'python3 /home/lisa/vmbus_testing disable-all

For that last point I don't understand what you mean, are you saying it would be
better to have something like this using delay as an example?

'python3 /home/lisa/vmbus_testing delay -p /sys/kernel/debug/hyperv/000d3a6e-4548-000d-3a6e-4548000d3a6e'

If thats what you mean I figured it was better to make the -p accessible
to all test type so I made it apart of the main parser. This would allow
us to just have it there once instead of having to make a -p for every
subparser.

Also maybe I need to change the examples and the help text
because with the -D option for delay you wouldnt actually need to put in
the path. As

'python3 /home/lisa/vmbus_testing delay -d 0 0 -D '

would suffice to stop delay testing on all devices; -E would enable
it for all devices and change the state to On 'Y' if it wasn't already.

let me know your thoughts

branden bonaby