Skip to content

Commit fa348ce

Browse files
committed
Add vdpa_utils.py
This patch introduces an OVSHandler class and supporting functions: - check ovs status and retrieve bridge/port information - handle vdpa device integration with ovs - add flow rules to ovs bridge - provide flexible bridge and port info for vm - add vdpa_dpdk case usage: add flows rules to ovs - add netperf case usage: add flows rules to ovs and get vdpa ovs port info Signed-off-by: Wenli Quan <[email protected]>
1 parent 5705527 commit fa348ce

File tree

5 files changed

+197
-48
lines changed

5 files changed

+197
-48
lines changed

generic/tests/cfg/netperf.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#numa configration
3535
numa_node = -1
3636
netperf_with_numa = yes
37+
vdpa_add_flows = yes
3738
# configure netperf test parameters, some seconds will be took to
3839
# wait all the clients work, this wait time should be less than
3940
# 0.5 * l, the wait time will augments if you have move

generic/tests/netperf.py

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from avocado.utils import process
88
from virttest import error_context, remote, utils_misc, utils_net, utils_test, virt_vm
99

10-
from provider import netperf_base, win_driver_utils
10+
from provider import netperf_base, vdpa_utils, win_driver_utils
1111

1212
LOG_JOB = logging.getLogger("avocado.test")
1313

@@ -76,52 +76,13 @@ def mtu_set(mtu):
7676
if netdst in br_in_use:
7777
ifaces_in_use = host_bridges.list_iface()
7878
target_ifaces = list(ifaces_in_use + br_in_use)
79-
if (
80-
process.system(
81-
"which ovs-vsctl && systemctl status openvswitch.service",
82-
ignore_status=True,
83-
shell=True,
84-
)
85-
== 0
86-
):
87-
ovs_br_all = netperf_base.ssh_cmd(host, "ovs-vsctl list-br")
88-
ovs_br = []
89-
if ovs_br_all:
90-
for nic in vm.virtnet:
91-
if nic.netdst in ovs_br_all:
92-
ovs_br.append(nic.netdst)
93-
elif nic.nettype == "vdpa":
94-
vf_pci = netperf_base.ssh_cmd(
95-
host,
96-
"vdpa dev show |grep %s | grep -o 'pci/[^[:space:]]*' | "
97-
"awk -F/ '{print $2}'" % nic.netdst,
98-
)
99-
pf_pci = netperf_base.ssh_cmd(
100-
host,
101-
"grep PCI_SLOT_NAME /sys/bus/pci/devices/%s/physfn/uevent |"
102-
" cut -d'=' -f2" % vf_pci,
103-
)
104-
port = netperf_base.ssh_cmd(
105-
host, "ls /sys/bus/pci/devices/%s/net/ | head -n 1" % pf_pci
106-
)
107-
ovs_br_vdpa = netperf_base.ssh_cmd(
108-
host, "ovs-vsctl port-to-br %s" % port
109-
)
110-
cmd = (
111-
f"ovs-ofctl add-flow {ovs_br_vdpa} '"
112-
"in_port=1,idle_timeout=0 actions=output:2'"
113-
)
114-
cmd += (
115-
f"&& ovs-ofctl add-flow {ovs_br_vdpa} '"
116-
"in_port=2,idle_timeout=0 actions=output:1'"
117-
)
118-
cmd += "&& ovs-ofctl dump-flows {}".format(ovs_br_vdpa)
119-
netperf_base.ssh_cmd(host, cmd)
120-
ovs_br.append(ovs_br_vdpa)
121-
for br in ovs_br:
122-
ovs_list = "ovs-vsctl list-ports %s" % br
123-
ovs_port = netperf_base.ssh_cmd(host, ovs_list)
124-
target_ifaces.extend(ovs_port.split() + [br])
79+
80+
add_flows = params.get("vdpa_ovs_add_flows", "yes") == "yes"
81+
ovs_handler = vdpa_utils.OVSHandler(vm)
82+
target_ifaces.extend(
83+
ovs_handler.get_vdpa_ovs_info(add_flows=add_flows, return_ports=True)
84+
)
85+
12586
if vm.virtnet[0].nettype == "macvtap":
12687
target_ifaces.extend([vm.virtnet[0].netdst, vm.get_ifname(0)])
12788
error_context.context("Change all Bridge NICs MTU to %s" % mtu, test.log.info)

provider/vdpa_utils.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
from avocado.utils import process
2+
3+
4+
def check_ovs_status():
5+
"""
6+
Check if ovs-vsctl and openvswitch service are installed and running.
7+
8+
:return: True if both are available and running, otherwise False
9+
:rtype: bool
10+
"""
11+
cmd = "which ovs-vsctl && systemctl status openvswitch.service"
12+
return process.system(cmd, ignore_status=True, shell=True) == 0
13+
14+
15+
def get_ovs_bridges():
16+
"""
17+
Get all ovs bridges.
18+
19+
:return: List of ovs bridge names
20+
:rtype: list
21+
"""
22+
cmd = "ovs-vsctl list-br"
23+
return process.system_output(cmd, shell=True).decode().split()
24+
25+
26+
def get_vf_pci_address(nic_netdst):
27+
"""
28+
Get vf pci address from a given network destination.
29+
30+
:param nic_netdst: Network destination address
31+
:type nic_netdst: str
32+
33+
:return: VF pci address
34+
:rtype: str
35+
"""
36+
cmd = (
37+
"vdpa dev show | grep {0} | grep -o 'pci/[^[:space:]]*' | "
38+
"awk -F/ '{{print $2}}'"
39+
).format(nic_netdst)
40+
return process.system_output(cmd, shell=True).decode().strip()
41+
42+
43+
def get_pf_pci_address(vf_pci):
44+
"""
45+
Get pf pci address using vf pci address.
46+
47+
:param vf_pci: VF pci address
48+
:type vf_pci: str
49+
50+
:return: VF pci address
51+
:rtype: str
52+
"""
53+
cmd = (
54+
"grep PCI_SLOT_NAME /sys/bus/pci/devices/{0}/physfn/uevent | cut -d'=' -f2"
55+
).format(vf_pci)
56+
return process.system_output(cmd, shell=True).decode().strip()
57+
58+
59+
def get_pf_port(pf_pci):
60+
"""
61+
Get the port for the pf pci address.
62+
63+
:param pf_pci: PF pci address
64+
:type pf_pci: str
65+
66+
:return: Port name
67+
:rtype: str
68+
"""
69+
cmd = "ls /sys/bus/pci/devices/{0}/net/ | head -n 1".format(pf_pci)
70+
return process.system_output(cmd, shell=True).decode().strip()
71+
72+
73+
def get_ovs_bridge_for_port(port):
74+
"""
75+
Get the ovs bridge name for the given network port.
76+
77+
:param port: Network port name
78+
:type port: str
79+
80+
:return: Bridge name
81+
:rtype: str
82+
"""
83+
cmd = "ovs-vsctl port-to-br {0}".format(port)
84+
return process.system_output(cmd, shell=True).decode().strip()
85+
86+
87+
def get_ovs_port_for_bridge(bridge):
88+
"""
89+
Get the ovs port name for the given bridge port.
90+
91+
:param bridge: Bridge name
92+
:type bridge: str
93+
94+
:return: Port name
95+
:rtype: str
96+
"""
97+
cmd = "ovs-vsctl list-ports {0}".format(bridge)
98+
return process.system_output(cmd, shell=True).decode().strip()
99+
100+
101+
def get_vdpa_ovs_bridges(vm):
102+
"""
103+
Get OVS bridge for VDPA devices in the VM.
104+
105+
:param vm: Virtual machine object
106+
:type vm: object
107+
108+
:return: OVS bridge name
109+
:rtype: str or None
110+
"""
111+
for nic in vm.virtnet:
112+
if nic.nettype == "vdpa":
113+
vf_pci = get_vf_pci_address(nic.netdst)
114+
pf_pci = get_pf_pci_address(vf_pci)
115+
port = get_pf_port(pf_pci)
116+
return get_ovs_bridge_for_port(port)
117+
return None
118+
119+
120+
def add_flows_to_ovs_bridge(bridge):
121+
"""
122+
Add flow rules to the given ovs bridge.
123+
124+
:parma bridge: OVS bridge name
125+
:type bridge: str
126+
"""
127+
cmd = "ovs-ofctl add-flow {0} 'in_port=1,idle_timeout=0 actions=output:2'".format(
128+
bridge
129+
)
130+
cmd += (
131+
" && ovs-ofctl add-flow {0} 'in_port=2,idle_timeout=0 actions=output:1'".format(
132+
bridge
133+
)
134+
)
135+
cmd += " && ovs-ofctl dump-flows {0}".format(bridge)
136+
process.run(cmd, shell=True)
137+
138+
139+
class OVSHandler:
140+
def __init__(self, vm):
141+
self.vm = vm
142+
143+
def get_vdpa_ovs_info(self, add_flows=True, return_ports=True):
144+
"""
145+
Get OVS bridge and port information.
146+
147+
:param add_flows: Whether to add flows rules to the ovs bridge
148+
:type add_flows: bool
149+
:param return_ports: Whether to return port names
150+
:type return_port:bool
151+
152+
:return: list of target interfaces(bridges and ports) if return_port is Ture,
153+
else empty list
154+
155+
:rtype: list
156+
"""
157+
if check_ovs_status():
158+
ovs_br_all = get_ovs_bridges()
159+
ovs_br = []
160+
target_ifaces = []
161+
162+
vdpa_br = get_vdpa_ovs_bridges(self.vm)
163+
if vdpa_br:
164+
if add_flows:
165+
add_flows_to_ovs_bridge(vdpa_br)
166+
ovs_br.append(vdpa_br)
167+
168+
for nic in self.vm.virtnet:
169+
if nic.netdst in ovs_br_all:
170+
ovs_br.append(nic.netdst)
171+
172+
for br in ovs_br:
173+
ovs_port = get_ovs_port_for_bridge(br)
174+
if return_ports:
175+
target_ifaces.extend(ovs_port.split() + [br])
176+
177+
if return_ports:
178+
return target_ifaces
179+
else:
180+
return []
181+
else:
182+
return []

qemu/tests/cfg/vdpa_dpdk.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
enable_guest_iommu = yes
3131
guest_iommu_option = pt
3232
kernel_extra_params_ad = "default_hugepagesz=1G hugepagesz=1G hugepages=10"
33+
vdpa_ovs_add_flows = yes
3334
# Packet Sending Host Configuration
3435
#dsthost = The IP address of the packet sending host
3536
#username_dsthost = Username for the host

qemu/tests/vdpa_dpdk.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from avocado.utils import process
77
from virttest import remote, utils_misc, utils_net, utils_sriov
88

9-
from provider import dpdk_utils
9+
from provider import dpdk_utils, vdpa_utils
1010

1111
LOG_JOB = logging.getLogger("avocado.test")
1212

@@ -62,6 +62,7 @@ def run(test, params, env):
6262
guest_ver_cmd = params["guest_ver_cmd"]
6363
base = params.get("format_base", "12")
6464
fbase = params.get("format_fbase", "2")
65+
add_flows = params.get("vdpa_ovs_add_flows", "yes") == "yes"
6566

6667
session = vm.wait_for_login(timeout=login_timeout, restart_network=True)
6768

@@ -75,6 +76,9 @@ def run(test, params, env):
7576
result_file.write("### kvm_version : %s\n" % host_ver)
7677
result_file.write("### guest-kernel-ver :%s" % guest_ver)
7778

79+
ovs_handler = vdpa_utils.OVSHandler(vm)
80+
ovs_handler.get_vdpa_ovs_info(add_flows=add_flows, return_ports=False)
81+
7882
dpdk_utils.install_dpdk(params, session)
7983
dpdk_ver = session.cmd_output("rpm -qa |grep dpdk | head -n 1")
8084
result_file.write("### guest-dpdk-ver :%s" % dpdk_ver)

0 commit comments

Comments
 (0)