mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
selftests: drv-net: Use Iperf3Runner in devlink_rate_tc_bw.py
Replace the inline iperf3 subprocess and JSON parsing with Iperf3Runner. Signed-off-by: Carolina Jubran <cjubran@nvidia.com> Reviewed-by: Cosmin Ratiu <cratiu@nvidia.com> Reviewed-by: Nimrod Oren <noren@nvidia.com> Link: https://patch.msgid.link/20251130091938.4109055-4-cjubran@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
2a60ce94c6
commit
cb1acbd30a
@@ -64,6 +64,7 @@ from lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx
|
|||||||
from lib.py import NetDrvEpEnv, DevlinkFamily
|
from lib.py import NetDrvEpEnv, DevlinkFamily
|
||||||
from lib.py import NlError
|
from lib.py import NlError
|
||||||
from lib.py import cmd, defer, ethtool, ip
|
from lib.py import cmd, defer, ethtool, ip
|
||||||
|
from lib.py import Iperf3Runner
|
||||||
|
|
||||||
|
|
||||||
class BandwidthValidator:
|
class BandwidthValidator:
|
||||||
@@ -139,8 +140,8 @@ def setup_vlans_on_vf(vf_ifc):
|
|||||||
Sets up two VLAN interfaces on the given VF, each mapped to a different TC.
|
Sets up two VLAN interfaces on the given VF, each mapped to a different TC.
|
||||||
"""
|
"""
|
||||||
vlan_configs = [
|
vlan_configs = [
|
||||||
{"vlan_id": 101, "tc": 3, "ip": "198.51.100.2"},
|
{"vlan_id": 101, "tc": 3, "ip": "198.51.100.1"},
|
||||||
{"vlan_id": 102, "tc": 4, "ip": "198.51.100.10"},
|
{"vlan_id": 102, "tc": 4, "ip": "198.51.100.9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
for config in vlan_configs:
|
for config in vlan_configs:
|
||||||
@@ -224,13 +225,13 @@ def setup_devlink_rate(cfg):
|
|||||||
raise KsftFailEx(f"rate_set failed on VF port {port_index}") from exc
|
raise KsftFailEx(f"rate_set failed on VF port {port_index}") from exc
|
||||||
|
|
||||||
|
|
||||||
def setup_remote_server(cfg):
|
def setup_remote_vlans(cfg):
|
||||||
"""
|
"""
|
||||||
Sets up VLAN interfaces and starts iperf3 servers on the remote side.
|
Sets up VLAN interfaces on the remote side.
|
||||||
"""
|
"""
|
||||||
remote_dev = cfg.remote_ifname
|
remote_dev = cfg.remote_ifname
|
||||||
vlan_ids = [101, 102]
|
vlan_ids = [101, 102]
|
||||||
remote_ips = ["198.51.100.1", "198.51.100.9"]
|
remote_ips = ["198.51.100.2", "198.51.100.10"]
|
||||||
|
|
||||||
for vlan_id, ip_addr in zip(vlan_ids, remote_ips):
|
for vlan_id, ip_addr in zip(vlan_ids, remote_ips):
|
||||||
vlan_dev = f"{remote_dev}.{vlan_id}"
|
vlan_dev = f"{remote_dev}.{vlan_id}"
|
||||||
@@ -238,14 +239,13 @@ def setup_remote_server(cfg):
|
|||||||
f"type vlan id {vlan_id}", host=cfg.remote)
|
f"type vlan id {vlan_id}", host=cfg.remote)
|
||||||
cmd(f"ip addr add {ip_addr}/29 dev {vlan_dev}", host=cfg.remote)
|
cmd(f"ip addr add {ip_addr}/29 dev {vlan_dev}", host=cfg.remote)
|
||||||
cmd(f"ip link set dev {vlan_dev} up", host=cfg.remote)
|
cmd(f"ip link set dev {vlan_dev} up", host=cfg.remote)
|
||||||
cmd(f"iperf3 -s -1 -B {ip_addr}",background=True, host=cfg.remote)
|
|
||||||
defer(cmd, f"ip link del {vlan_dev}", host=cfg.remote)
|
defer(cmd, f"ip link del {vlan_dev}", host=cfg.remote)
|
||||||
|
|
||||||
|
|
||||||
def setup_test_environment(cfg, set_tc_mapping=True):
|
def setup_test_environment(cfg, set_tc_mapping=True):
|
||||||
"""
|
"""
|
||||||
Sets up the complete test environment including VF creation, VLANs,
|
Sets up the complete test environment including VF creation, VLANs,
|
||||||
bridge configuration, devlink rate setup, and the remote server.
|
bridge configuration and devlink rate setup.
|
||||||
"""
|
"""
|
||||||
vf_ifc = setup_vf(cfg, set_tc_mapping)
|
vf_ifc = setup_vf(cfg, set_tc_mapping)
|
||||||
ksft_pr(f"Created VF interface: {vf_ifc}")
|
ksft_pr(f"Created VF interface: {vf_ifc}")
|
||||||
@@ -256,51 +256,39 @@ def setup_test_environment(cfg, set_tc_mapping=True):
|
|||||||
setup_bridge(cfg)
|
setup_bridge(cfg)
|
||||||
|
|
||||||
setup_devlink_rate(cfg)
|
setup_devlink_rate(cfg)
|
||||||
setup_remote_server(cfg)
|
setup_remote_vlans(cfg)
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
|
|
||||||
def run_iperf_client(server_ip, local_ip, barrier, min_expected_gbps=0.1):
|
def measure_bandwidth(cfg, server_ip, client_ip, barrier):
|
||||||
"""
|
"""
|
||||||
Runs a single iperf3 client instance, binding to the given local IP.
|
Synchronizes with peers and runs an iperf3-based bandwidth measurement
|
||||||
Waits on a barrier to synchronize with other threads.
|
between the given endpoints. Returns average Gbps.
|
||||||
"""
|
"""
|
||||||
|
runner = Iperf3Runner(cfg, server_ip=server_ip, client_ip=client_ip)
|
||||||
try:
|
try:
|
||||||
barrier.wait(timeout=10)
|
barrier.wait(timeout=10)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
raise KsftFailEx("iperf3 barrier wait timed") from exc
|
raise KsftFailEx("iperf3 barrier wait timed") from exc
|
||||||
|
|
||||||
iperf_cmd = ["iperf3", "-c", server_ip, "-B", local_ip, "-J"]
|
|
||||||
result = subprocess.run(iperf_cmd, capture_output=True, text=True,
|
|
||||||
check=True)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
output = json.loads(result.stdout)
|
bw_gbps = runner.measure_bandwidth(reverse=True)
|
||||||
bits_per_second = output["end"]["sum_received"]["bits_per_second"]
|
except Exception as exc:
|
||||||
gbps = bits_per_second / 1e9
|
raise KsftFailEx("iperf3 bandwidth measurement failed") from exc
|
||||||
if gbps < min_expected_gbps:
|
|
||||||
ksft_pr(
|
return bw_gbps
|
||||||
f"iperf3 bandwidth too low: {gbps:.2f} Gbps "
|
|
||||||
f"(expected ≥ {min_expected_gbps} Gbps)"
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
return gbps
|
|
||||||
except json.JSONDecodeError as exc:
|
|
||||||
ksft_pr(f"Failed to parse iperf3 JSON output: {exc}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def run_bandwidth_test():
|
def run_bandwidth_test(cfg):
|
||||||
"""
|
"""
|
||||||
Launches iperf3 client threads for each VLAN/TC pair and collects results.
|
Runs parallel bandwidth measurements for each VLAN/TC pair and collects results.
|
||||||
"""
|
"""
|
||||||
def _run_iperf_client_thread(server_ip, local_ip, results, barrier, tc_ix):
|
def _run_measure_bandwidth_thread(local_ip, remote_ip, results, barrier, tc_ix):
|
||||||
results[tc_ix] = run_iperf_client(server_ip, local_ip, barrier)
|
results[tc_ix] = measure_bandwidth(cfg, local_ip, remote_ip, barrier)
|
||||||
|
|
||||||
vf_vlan_data = [
|
vf_vlan_data = [
|
||||||
# (local_ip, remote_ip, TC)
|
# (local_ip, remote_ip, TC)
|
||||||
("198.51.100.2", "198.51.100.1", 3),
|
("198.51.100.1", "198.51.100.2", 3),
|
||||||
("198.51.100.10", "198.51.100.9", 4),
|
("198.51.100.9", "198.51.100.10", 4),
|
||||||
]
|
]
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
@@ -309,8 +297,8 @@ def run_bandwidth_test():
|
|||||||
|
|
||||||
for local_ip, remote_ip, tc_ix in vf_vlan_data:
|
for local_ip, remote_ip, tc_ix in vf_vlan_data:
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=_run_iperf_client_thread,
|
target=_run_measure_bandwidth_thread,
|
||||||
args=(remote_ip, local_ip, results, start_barrier, tc_ix)
|
args=(local_ip, remote_ip, results, start_barrier, tc_ix)
|
||||||
)
|
)
|
||||||
thread.start()
|
thread.start()
|
||||||
threads.append(thread)
|
threads.append(thread)
|
||||||
@@ -320,10 +308,11 @@ def run_bandwidth_test():
|
|||||||
|
|
||||||
for tc_ix, tc_bw in results.items():
|
for tc_ix, tc_bw in results.items():
|
||||||
if tc_bw is None:
|
if tc_bw is None:
|
||||||
raise KsftFailEx("iperf3 client failed; cannot evaluate bandwidth")
|
raise KsftFailEx("iperf3 failed; cannot evaluate bandwidth")
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def calculate_bandwidth_percentages(results):
|
def calculate_bandwidth_percentages(results):
|
||||||
"""
|
"""
|
||||||
Calculates the percentage of total bandwidth received by TC3 and TC4.
|
Calculates the percentage of total bandwidth received by TC3 and TC4.
|
||||||
@@ -398,10 +387,10 @@ def check_bandwidth_distribution(bw_data, validator):
|
|||||||
|
|
||||||
def run_bandwidth_distribution_test(cfg, set_tc_mapping):
|
def run_bandwidth_distribution_test(cfg, set_tc_mapping):
|
||||||
"""
|
"""
|
||||||
Runs parallel iperf3 tests for both TCs and collects results.
|
Runs parallel bandwidth measurements for both TCs and collects results.
|
||||||
"""
|
"""
|
||||||
setup_test_environment(cfg, set_tc_mapping)
|
setup_test_environment(cfg, set_tc_mapping)
|
||||||
bandwidths = run_bandwidth_test()
|
bandwidths = run_bandwidth_test(cfg)
|
||||||
bw_data = calculate_bandwidth_percentages(bandwidths)
|
bw_data = calculate_bandwidth_percentages(bandwidths)
|
||||||
test_name = "with TC mapping" if set_tc_mapping else "without TC mapping"
|
test_name = "with TC mapping" if set_tc_mapping else "without TC mapping"
|
||||||
print_bandwidth_results(bw_data, test_name)
|
print_bandwidth_results(bw_data, test_name)
|
||||||
@@ -451,7 +440,6 @@ def main() -> None:
|
|||||||
)
|
)
|
||||||
if not cfg.pci:
|
if not cfg.pci:
|
||||||
raise KsftSkipEx("Could not get PCI address of the interface")
|
raise KsftSkipEx("Could not get PCI address of the interface")
|
||||||
cfg.require_cmd("iperf3", local=True, remote=True)
|
|
||||||
|
|
||||||
cfg.bw_validator = BandwidthValidator()
|
cfg.bw_validator = BandwidthValidator()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user