summaryrefslogtreecommitdiff
path: root/0005-Add-vmbus_testing-tool-build-files.patch
diff options
context:
space:
mode:
Diffstat (limited to '0005-Add-vmbus_testing-tool-build-files.patch')
-rw-r--r--0005-Add-vmbus_testing-tool-build-files.patch401
1 files changed, 401 insertions, 0 deletions
diff --git a/0005-Add-vmbus_testing-tool-build-files.patch b/0005-Add-vmbus_testing-tool-build-files.patch
new file mode 100644
index 0000000..92f2717
--- /dev/null
+++ b/0005-Add-vmbus_testing-tool-build-files.patch
@@ -0,0 +1,401 @@
+From a13aa83d1b5bb4b6ce4396aef3457b48695b7c41 Mon Sep 17 00:00:00 2001
+From: Miroslav Rezanina <mrezanin@redhat.com>
+Date: Thu, 6 May 2021 12:53:31 +0200
+Subject: Add vmbus_testing tool build files
+
+Add the vmbus_testing tool to redhat build dirs
+
+(cherry-pick from rhel 8.4.0 commit d8ca5e0)
+Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
+Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
+---
+ .distro/hyperv-daemons.spec.template | 2 +
+ vmbus_testing | 376 +++++++++++++++++++++++++++
+ 2 files changed, 378 insertions(+)
+ create mode 100755 vmbus_testing
+
+diff --git a/vmbus_testing b/vmbus_testing
+new file mode 100755
+index 0000000..e721290
+--- /dev/null
++++ b/vmbus_testing
+@@ -0,0 +1,376 @@
++#!/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 attributes.
++# Current test methods available:
++# 1. delay testing
++#
++# Current file/directory structure of hyper-V debugfs:
++# /sys/kernel/debug/hyperv/UUID
++# /sys/kernel/debug/hyperv/UUID/<test-state filename>
++# /sys/kernel/debug/hyperv/UUID/<test-method sub-directory>
++#
++# author: Branden Bonaby <brandonbonaby94@gmail.com>
++
++import os
++import cmd
++import argparse
++import glob
++from argparse import RawDescriptionHelpFormatter
++from argparse import RawTextHelpFormatter
++from enum import Enum
++
++# Do not change unless, you change the debugfs attributes
++# in /drivers/hv/debugfs.c. All fuzz testing
++# attributes will start with "fuzz_test".
++
++# debugfs path for hyperv must exist before proceeding
++debugfs_hyperv_path = "/sys/kernel/debug/hyperv"
++if not os.path.isdir(debugfs_hyperv_path):
++ print("{} doesn't exist/check permissions".format(debugfs_hyperv_path))
++ exit(-1)
++
++class dev_state(Enum):
++ off = 0
++ on = 1
++
++# File names, that correspond to the files created in
++# /drivers/hv/debugfs.c
++class f_names(Enum):
++ state_f = "fuzz_test_state"
++ buff_f = "fuzz_test_buffer_interrupt_delay"
++ mess_f = "fuzz_test_message_delay"
++
++# Both single_actions and all_actions are used
++# for error checking and to allow for some subparser
++# names to be abbreviated. Do not abbreviate the
++# test method names, as it will become less intuitive
++# as to what the user can do. If you do decide to
++# abbreviate the test method name, make sure the main
++# function reflects this change.
++
++all_actions = [
++ "disable_all",
++ "D",
++ "enable_all",
++ "view_all",
++ "V"
++]
++
++single_actions = [
++ "disable_single",
++ "d",
++ "enable_single",
++ "view_single",
++ "v"
++]
++
++def main():
++
++ file_map = recursive_file_lookup(debugfs_hyperv_path, dict())
++ args = parse_args()
++ if (not args.action):
++ print ("Error, no options selected...exiting")
++ exit(-1)
++ arg_set = { k for (k,v) in vars(args).items() if v and k != "action" }
++ arg_set.add(args.action)
++ path = args.path if "path" in arg_set else None
++ if (path and path[-1] == "/"):
++ path = path[:-1]
++ validate_args_path(path, arg_set, file_map)
++ if (path and "enable_single" in arg_set):
++ state_path = locate_state(path, file_map)
++ set_test_state(state_path, dev_state.on.value, args.quiet)
++
++ # Use subparsers as the key for different actions
++ if ("delay" in arg_set):
++ validate_delay_values(args.delay_time)
++ if (args.enable_all):
++ set_delay_all_devices(file_map, args.delay_time,
++ args.quiet)
++ else:
++ set_delay_values(path, file_map, args.delay_time,
++ args.quiet)
++ elif ("disable_all" in arg_set or "D" in arg_set):
++ disable_all_testing(file_map)
++ elif ("disable_single" in arg_set or "d" in arg_set):
++ disable_testing_single_device(path, file_map)
++ elif ("view_all" in arg_set or "V" in arg_set):
++ get_all_devices_test_status(file_map)
++ elif ("view_single" in arg_set or "v" in arg_set):
++ get_device_test_values(path, file_map)
++
++# Get the state location
++def locate_state(device, file_map):
++ return file_map[device][f_names.state_f.value]
++
++# Validate delay values to make sure they are acceptable to
++# enable delays on a device
++def validate_delay_values(delay):
++
++ if (delay[0] == -1 and delay[1] == -1):
++ print("\nError, At least 1 value must be greater than 0")
++ exit(-1)
++ for i in delay:
++ if (i < -1 or i == 0 or i > 1000):
++ print("\nError, Values must be equal to -1 "
++ "or be > 0 and <= 1000")
++ exit(-1)
++
++# Validate argument path
++def validate_args_path(path, arg_set, file_map):
++
++ if (not path and any(element in arg_set for element in single_actions)):
++ print("Error, path (-p) REQUIRED for the specified option. "
++ "Use (-h) to check usage.")
++ exit(-1)
++ elif (path and any(item in arg_set for item in all_actions)):
++ print("Error, path (-p) NOT REQUIRED for the specified option. "
++ "Use (-h) to check usage." )
++ exit(-1)
++ elif (path not in file_map and any(item in arg_set
++ for item in single_actions)):
++ print("Error, path '{}' not a valid vmbus device".format(path))
++ exit(-1)
++
++# display Testing status of single device
++def get_device_test_values(path, file_map):
++
++ for name in file_map[path]:
++ file_location = file_map[path][name]
++ print( name + " = " + str(read_test_files(file_location)))
++
++# Create a map of the vmbus devices and their associated files
++# [key=device, value = [key = filename, value = file path]]
++def recursive_file_lookup(path, file_map):
++
++ for f_path in glob.iglob(path + '**/*'):
++ if (os.path.isfile(f_path)):
++ if (f_path.rsplit("/",2)[0] == debugfs_hyperv_path):
++ directory = f_path.rsplit("/",1)[0]
++ else:
++ directory = f_path.rsplit("/",2)[0]
++ f_name = f_path.split("/")[-1]
++ if (file_map.get(directory)):
++ file_map[directory].update({f_name:f_path})
++ else:
++ file_map[directory] = {f_name:f_path}
++ elif (os.path.isdir(f_path)):
++ recursive_file_lookup(f_path,file_map)
++ return file_map
++
++# display Testing state of devices
++def get_all_devices_test_status(file_map):
++
++ for device in file_map:
++ if (get_test_state(locate_state(device, file_map)) 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:
++ file_value = f.readline().strip()
++ return int(file_value)
++
++ 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)
++
++# set testing state of device
++def set_test_state(state_path, state_value, quiet):
++
++ write_test_files(state_path, state_value)
++ if (get_test_state(state_path) is 1):
++ if (not quiet):
++ print("Testing = ON for device: {}"
++ .format(state_path.split("/")[5]))
++ else:
++ if (not quiet):
++ print("Testing = OFF for device: {}"
++ .format(state_path.split("/")[5]))
++
++# get testing state of device
++def get_test_state(state_path):
++ #state == 1 - test = ON
++ #state == 0 - test = OFF
++ return read_test_files(state_path)
++
++# write 1 - 1000 microseconds, into a single device using the
++# fuzz_test_buffer_interrupt_delay and fuzz_test_message_delay
++# debugfs attributes
++def set_delay_values(device, file_map, delay_length, quiet):
++
++ try:
++ interrupt = file_map[device][f_names.buff_f.value]
++ message = file_map[device][f_names.mess_f.value]
++
++ # delay[0]- buffer interrupt delay, delay[1]- message delay
++ if (delay_length[0] >= 0 and delay_length[0] <= 1000):
++ write_test_files(interrupt, delay_length[0])
++ if (delay_length[1] >= 0 and delay_length[1] <= 1000):
++ write_test_files(message, delay_length[1])
++ if (not quiet):
++ print("Buffer delay testing = {} for: {}"
++ .format(read_test_files(interrupt),
++ interrupt.split("/")[5]))
++ print("Message delay testing = {} for: {}"
++ .format(read_test_files(message),
++ message.split("/")[5]))
++ except IOError as e:
++ errno, strerror = e.args
++ print("I/O error({0}): {1} on files {2}{3}"
++ .format(errno, strerror, interrupt, message))
++ exit(-1)
++
++# enabling delay testing on all devices
++def set_delay_all_devices(file_map, delay, quiet):
++
++ for device in (file_map):
++ set_test_state(locate_state(device, file_map),
++ dev_state.on.value,
++ quiet)
++ set_delay_values(device, file_map, delay, quiet)
++
++# disable all testing on a SINGLE device.
++def disable_testing_single_device(device, file_map):
++
++ for name in file_map[device]:
++ file_location = file_map[device][name]
++ write_test_files(file_location, dev_state.off.value)
++ print("ALL testing now OFF for {}".format(device.split("/")[-1]))
++
++# disable all testing on ALL devices
++def disable_all_testing(file_map):
++
++ for device in file_map:
++ disable_testing_single_device(device, file_map)
++
++def parse_args():
++ parser = argparse.ArgumentParser(prog = "vmbus_testing",usage ="\n"
++ "%(prog)s [delay] [-h] [-e|-E] -t [-p]\n"
++ "%(prog)s [view_all | V] [-h]\n"
++ "%(prog)s [disable_all | D] [-h]\n"
++ "%(prog)s [disable_single | d] [-h|-p]\n"
++ "%(prog)s [view_single | v] [-h|-p]\n"
++ "%(prog)s --version\n",
++ description = "\nUse lsvmbus to get vmbus device type "
++ "information.\n" "\nThe debugfs root path is "
++ "/sys/kernel/debug/hyperv",
++ formatter_class = RawDescriptionHelpFormatter)
++ subparsers = parser.add_subparsers(dest = "action")
++ parser.add_argument("--version", action = "version",
++ version = '%(prog)s 0.1.0')
++ parser.add_argument("-q","--quiet", action = "store_true",
++ help = "silence none important test messages."
++ " This will only work when enabling testing"
++ " on a device.")
++ # Use the path parser to hold the --path attribute so it can
++ # be shared between subparsers. Also do the same for the state
++ # parser, as all testing methods will use --enable_all and
++ # enable_single.
++ path_parser = argparse.ArgumentParser(add_help=False)
++ path_parser.add_argument("-p","--path", metavar = "",
++ help = "Debugfs path to a vmbus device. The path "
++ "must be the absolute path to the device.")
++ state_parser = argparse.ArgumentParser(add_help=False)
++ state_group = state_parser.add_mutually_exclusive_group(required = True)
++ state_group.add_argument("-E", "--enable_all", action = "store_const",
++ const = "enable_all",
++ help = "Enable the specified test type "
++ "on ALL vmbus devices.")
++ state_group.add_argument("-e", "--enable_single",
++ action = "store_const",
++ const = "enable_single",
++ help = "Enable the specified test type on a "
++ "SINGLE vmbus device.")
++ parser_delay = subparsers.add_parser("delay",
++ parents = [state_parser, path_parser],
++ help = "Delay the ring buffer interrupt or the "
++ "ring buffer message reads in microseconds.",
++ prog = "vmbus_testing",
++ usage = "%(prog)s [-h]\n"
++ "%(prog)s -E -t [value] [value]\n"
++ "%(prog)s -e -t [value] [value] -p",
++ description = "Delay the ring buffer interrupt for "
++ "vmbus devices, or delay the ring buffer message "
++ "reads for vmbus devices (both in microseconds). This "
++ "is only on the host to guest channel.")
++ parser_delay.add_argument("-t", "--delay_time", metavar = "", nargs = 2,
++ type = check_range, default =[0,0], required = (True),
++ help = "Set [buffer] & [message] delay time. "
++ "Value constraints: -1 == value "
++ "or 0 < value <= 1000.\n"
++ "Use -1 to keep the previous value for that delay "
++ "type, or a value > 0 <= 1000 to change the delay "
++ "time.")
++ parser_dis_all = subparsers.add_parser("disable_all",
++ aliases = ['D'], prog = "vmbus_testing",
++ usage = "%(prog)s [disable_all | D] -h\n"
++ "%(prog)s [disable_all | D]\n",
++ help = "Disable ALL testing on ALL vmbus devices.",
++ description = "Disable ALL testing on ALL vmbus "
++ "devices.")
++ parser_dis_single = subparsers.add_parser("disable_single",
++ aliases = ['d'],
++ parents = [path_parser], prog = "vmbus_testing",
++ usage = "%(prog)s [disable_single | d] -h\n"
++ "%(prog)s [disable_single | d] -p\n",
++ help = "Disable ALL testing on a SINGLE vmbus device.",
++ description = "Disable ALL testing on a SINGLE vmbus "
++ "device.")
++ parser_view_all = subparsers.add_parser("view_all", aliases = ['V'],
++ help = "View the test state for ALL vmbus devices.",
++ prog = "vmbus_testing",
++ usage = "%(prog)s [view_all | V] -h\n"
++ "%(prog)s [view_all | V]\n",
++ description = "This shows the test state for ALL the "
++ "vmbus devices.")
++ parser_view_single = subparsers.add_parser("view_single",
++ aliases = ['v'],parents = [path_parser],
++ help = "View the test values for a SINGLE vmbus "
++ "device.",
++ description = "This shows the test values for a SINGLE "
++ "vmbus device.", prog = "vmbus_testing",
++ usage = "%(prog)s [view_single | v] -h\n"
++ "%(prog)s [view_single | v] -p")
++
++ 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\nvalue must be -1 or 0 < value <= 1000. "
++ "Value program received: {}\n").format(val)
++ raise argparse.ArgumentTypeError(message)
++ return val
++
++if __name__ == "__main__":
++ main()
+--
+2.27.0
+