diff --git a/generic/tests/cfg/netperf.cfg b/generic/tests/cfg/netperf.cfg index f1fc7a9b3b..3ec3471292 100644 --- a/generic/tests/cfg/netperf.cfg +++ b/generic/tests/cfg/netperf.cfg @@ -34,6 +34,7 @@ #numa configration numa_node = -1 netperf_with_numa = yes + vdpa_add_flows = yes # configure netperf test parameters, some seconds will be took to # wait all the clients work, this wait time should be less than # 0.5 * l, the wait time will augments if you have move diff --git a/generic/tests/netperf.py b/generic/tests/netperf.py index 9cf50218f8..f0b61a3806 100644 --- a/generic/tests/netperf.py +++ b/generic/tests/netperf.py @@ -7,7 +7,7 @@ from avocado.utils import process from virttest import error_context, remote, utils_misc, utils_net, utils_test, virt_vm -from provider import netperf_base, win_driver_utils +from provider import netperf_base, vdpa_utils, win_driver_utils LOG_JOB = logging.getLogger("avocado.test") @@ -76,52 +76,13 @@ def mtu_set(mtu): if netdst in br_in_use: ifaces_in_use = host_bridges.list_iface() target_ifaces = list(ifaces_in_use + br_in_use) - if ( - process.system( - "which ovs-vsctl && systemctl status openvswitch.service", - ignore_status=True, - shell=True, - ) - == 0 - ): - ovs_br_all = netperf_base.ssh_cmd(host, "ovs-vsctl list-br") - ovs_br = [] - if ovs_br_all: - for nic in vm.virtnet: - if nic.netdst in ovs_br_all: - ovs_br.append(nic.netdst) - elif nic.nettype == "vdpa": - vf_pci = netperf_base.ssh_cmd( - host, - "vdpa dev show |grep %s | grep -o 'pci/[^[:space:]]*' | " - "awk -F/ '{print $2}'" % nic.netdst, - ) - pf_pci = netperf_base.ssh_cmd( - host, - "grep PCI_SLOT_NAME /sys/bus/pci/devices/%s/physfn/uevent |" - " cut -d'=' -f2" % vf_pci, - ) - port = netperf_base.ssh_cmd( - host, "ls /sys/bus/pci/devices/%s/net/ | head -n 1" % pf_pci - ) - ovs_br_vdpa = netperf_base.ssh_cmd( - host, "ovs-vsctl port-to-br %s" % port - ) - cmd = ( - f"ovs-ofctl add-flow {ovs_br_vdpa} '" - "in_port=1,idle_timeout=0 actions=output:2'" - ) - cmd += ( - f"&& ovs-ofctl add-flow {ovs_br_vdpa} '" - "in_port=2,idle_timeout=0 actions=output:1'" - ) - cmd += "&& ovs-ofctl dump-flows {}".format(ovs_br_vdpa) - netperf_base.ssh_cmd(host, cmd) - ovs_br.append(ovs_br_vdpa) - for br in ovs_br: - ovs_list = "ovs-vsctl list-ports %s" % br - ovs_port = netperf_base.ssh_cmd(host, ovs_list) - target_ifaces.extend(ovs_port.split() + [br]) + + add_flows = params.get("vdpa_ovs_add_flows", "yes") == "yes" + ovs_handler = vdpa_utils.OVSHandler(vm) + target_ifaces.extend( + ovs_handler.get_vdpa_ovs_info(add_flows=add_flows, return_ports=True) + ) + if vm.virtnet[0].nettype == "macvtap": target_ifaces.extend([vm.virtnet[0].netdst, vm.get_ifname(0)]) error_context.context("Change all Bridge NICs MTU to %s" % mtu, test.log.info) diff --git a/provider/vdpa_utils.py b/provider/vdpa_utils.py new file mode 100644 index 0000000000..6cc222854e --- /dev/null +++ b/provider/vdpa_utils.py @@ -0,0 +1,132 @@ +import logging + +from avocado.utils import process +from virttest import openvswitch, utils_net + +LOG_JOB = logging.getLogger("avocado.test") + + +def check_ovs_status(): + """ + Check if ovs-vsctl and openvswitch service are installed and running. + :return: True if both are available and running, otherwise False + :rtype: bool + """ + cmd = "which ovs-vsctl && systemctl status openvswitch.service" + return process.system(cmd, ignore_status=True, shell=True) == 0 + + +def get_vf_pci_address(nic_netdst): + """ + Get vf pci address from a given network destination. + + :param nic_netdst: Network destination address + :type nic_netdst: str + + :return: VF pci address + :rtype: str + """ + cmd = ( + "vdpa dev show | grep {0} | grep -o 'pci/[^[:space:]]*' | " + "awk -F/ '{{print $2}}'" + ).format(nic_netdst) + return process.system_output(cmd, shell=True).decode().strip() + + +def get_pf_pci_address(vf_pci): + """ + Get pf pci address using vf pci address. + + :param vf_pci: VF pci address + :type vf_pci: str + + :return: VF pci address + :rtype: str + """ + cmd = ( + "grep PCI_SLOT_NAME /sys/bus/pci/devices/{0}/physfn/uevent | cut -d'=' -f2" + ).format(vf_pci) + return process.system_output(cmd, shell=True).decode().strip() + + +def get_pf_port(pf_pci): + """ + Get the port for the pf pci address. + + :param pf_pci: PF pci address + :type pf_pci: str + + :return: Port name + :rtype: str + """ + cmd = "ls /sys/bus/pci/devices/{0}/net/ | head -n 1".format(pf_pci) + return process.system_output(cmd, shell=True).decode().strip() + + +def add_flows_to_ovs_bridge(bridge, ovs): + """ + Add flow rules to the given ovs bridge. + + :parma bridge: OVS bridge name + :type bridge: str + :param ovs: OVS instance + :type ovs: OpenVSwitch + """ + utils_net.openflow_manager( + bridge, "add-flow", flow_options="in_port=1,idle_timeout=0,actions=output:2" + ) + utils_net.openflow_manager( + bridge, "add-flow", flow_options="in_port=2,idle_timeout=0,actions=output:1" + ) + utils_net.openflow_manager(bridge, "dump-flows") + + +class OVSHandler: + def __init__(self, vm): + self.vm = vm + if check_ovs_status(): + self.ovs = openvswitch.OpenVSwitchControl() + else: + self.ovs = None + + def get_vdpa_ovs_info(self, add_flows=True, return_ports=True): + """ + Get OVS bridge and port information. + + :param add_flows: Whether to add flows rules to the ovs bridge + :type add_flows: bool + :param return_ports: Whether to return port names + :type return_ports: bool + + :return: list of target interfaces(bridges and ports) if return_port is Ture, + else empty list + :rtype: list + """ + if not self.ovs: + LOG_JOB.error("Could not find existing Open vSwitch service") + return [] + + target_ifaces = [] + + for nic in self.vm.virtnet: + ovs_br = None + if nic.nettype == "vdpa": + vf_pci = get_vf_pci_address(nic.netdst) + pf_pci = get_pf_pci_address(vf_pci) + port = get_pf_port(pf_pci) + manager, ovs_br = utils_net.find_current_bridge(port) + else: + try: + manager, ovs_br = utils_net.find_current_bridge(nic.netdst) + except NotImplementedError: + ovs_br = None + if ovs_br: + if add_flows: + add_flows_to_ovs_bridge(ovs_br, self.ovs) + if return_ports: + if manager: + ports = set(manager.list_ports(ovs_br)) + target_ifaces.extend(ports) + target_ifaces.append(ovs_br) + + return target_ifaces diff --git a/qemu/tests/cfg/vdpa_dpdk.cfg b/qemu/tests/cfg/vdpa_dpdk.cfg index b083294b9c..a2f6f57fe5 100644 --- a/qemu/tests/cfg/vdpa_dpdk.cfg +++ b/qemu/tests/cfg/vdpa_dpdk.cfg @@ -30,6 +30,7 @@ enable_guest_iommu = yes guest_iommu_option = pt kernel_extra_params_ad = "default_hugepagesz=1G hugepagesz=1G hugepages=10" + vdpa_ovs_add_flows = yes # Packet Sending Host Configuration #dsthost = The IP address of the packet sending host #username_dsthost = Username for the host diff --git a/qemu/tests/vdpa_dpdk.py b/qemu/tests/vdpa_dpdk.py index d4496a70ea..e8580b2095 100644 --- a/qemu/tests/vdpa_dpdk.py +++ b/qemu/tests/vdpa_dpdk.py @@ -6,7 +6,7 @@ from avocado.utils import process from virttest import remote, utils_misc, utils_net, utils_sriov -from provider import dpdk_utils +from provider import dpdk_utils, vdpa_utils LOG_JOB = logging.getLogger("avocado.test") @@ -62,6 +62,7 @@ def run(test, params, env): guest_ver_cmd = params["guest_ver_cmd"] base = params.get("format_base", "12") fbase = params.get("format_fbase", "2") + add_flows = params.get("vdpa_ovs_add_flows", "yes") == "yes" session = vm.wait_for_login(timeout=login_timeout, restart_network=True) @@ -75,6 +76,9 @@ def run(test, params, env): result_file.write("### kvm_version : %s\n" % host_ver) result_file.write("### guest-kernel-ver :%s" % guest_ver) + ovs_handler = vdpa_utils.OVSHandler(vm) + ovs_handler.get_vdpa_ovs_info(add_flows=add_flows, return_ports=False) + dpdk_utils.install_dpdk(params, session) dpdk_ver = session.cmd_output("rpm -qa |grep dpdk | head -n 1") result_file.write("### guest-dpdk-ver :%s" % dpdk_ver)