Path: blob/master/tools/testing/selftests/drivers/net/hw/xdp_metadata.py
171056 views
#!/usr/bin/env python31# SPDX-License-Identifier: GPL-2.023"""4Tests for XDP metadata kfuncs (e.g. bpf_xdp_metadata_rx_hash).56These tests load device-bound XDP programs from xdp_metadata.bpf.o7that call metadata kfuncs, send traffic, and verify the extracted8metadata via BPF maps.9"""10from lib.py import ksft_run, ksft_eq, ksft_exit, ksft_ge, ksft_ne, ksft_pr11from lib.py import KsftNamedVariant, ksft_variants12from lib.py import CmdExitFailure, KsftSkipEx, NetDrvEpEnv13from lib.py import NetdevFamily14from lib.py import bkg, cmd, rand_port, wait_port_listen15from lib.py import ip, bpftool, defer16from lib.py import bpf_map_set, bpf_map_dump, bpf_prog_map_ids171819def _load_xdp_metadata_prog(cfg, prog_name, bpf_file="xdp_metadata.bpf.o"):20"""Load a device-bound XDP metadata program and return prog/map info.2122Returns:23dict with 'id', 'name', and 'maps' (name -> map_id).24"""25abs_path = cfg.net_lib_dir / bpf_file26pin_dir = "/sys/fs/bpf/xdp_metadata_test"2728cmd(f"rm -rf {pin_dir}", shell=True, fail=False)29cmd(f"mkdir -p {pin_dir}", shell=True)3031try:32bpftool(f"prog loadall {abs_path} {pin_dir} type xdp "33f"xdpmeta_dev {cfg.ifname}")34except CmdExitFailure as e:35cmd(f"rm -rf {pin_dir}", shell=True, fail=False)36raise KsftSkipEx(37f"Failed to load device-bound XDP program '{prog_name}'"38) from e39defer(cmd, f"rm -rf {pin_dir}", shell=True, fail=False)4041pin_path = f"{pin_dir}/{prog_name}"42ip(f"link set dev {cfg.ifname} xdpdrv pinned {pin_path}")43defer(ip, f"link set dev {cfg.ifname} xdpdrv off")4445xdp_info = ip(f"-d link show dev {cfg.ifname}", json=True)[0]46prog_id = xdp_info["xdp"]["prog"]["id"]4748return {"id": prog_id,49"name": xdp_info["xdp"]["prog"]["name"],50"maps": bpf_prog_map_ids(prog_id)}515253def _send_probe(cfg, port, proto="tcp"):54"""Send a single payload from the remote end using socat.5556Args:57cfg: Configuration object containing network settings.58port: Port number for the exchange.59proto: Protocol to use, either "tcp" or "udp".60"""61cfg.require_cmd("socat", remote=True)6263if proto == "tcp":64rx_cmd = f"socat -{cfg.addr_ipver} -T 2 TCP-LISTEN:{port},reuseport STDOUT"65tx_cmd = f"echo -n rss_hash_test | socat -t 2 -u STDIN TCP:{cfg.baddr}:{port}"66else:67rx_cmd = f"socat -{cfg.addr_ipver} -T 2 -u UDP-RECV:{port},reuseport STDOUT"68tx_cmd = f"echo -n rss_hash_test | socat -t 2 -u STDIN UDP:{cfg.baddr}:{port}"6970with bkg(rx_cmd, exit_wait=True):71wait_port_listen(port, proto=proto)72cmd(tx_cmd, host=cfg.remote, shell=True)737475# BPF map keys matching the enums in xdp_metadata.bpf.c76_SETUP_KEY_PORT = 17778_RSS_KEY_HASH = 079_RSS_KEY_TYPE = 180_RSS_KEY_PKT_CNT = 281_RSS_KEY_ERR_CNT = 38283XDP_RSS_L4 = 0x8 # BIT(3) from enum xdp_rss_hash_type848586@ksft_variants([87KsftNamedVariant("tcp", "tcp"),88KsftNamedVariant("udp", "udp"),89])90def test_xdp_rss_hash(cfg, proto):91"""Test RSS hash metadata extraction via bpf_xdp_metadata_rx_hash().9293This test will only run on devices that support xdp-rx-metadata-features.9495Loads the xdp_rss_hash program from xdp_metadata, sends a packet using96the specified protocol, and verifies that the program extracted a non-zero97hash with an L4 hash type.98"""99dev_info = cfg.netnl.dev_get({"ifindex": cfg.ifindex})100rx_meta = dev_info.get("xdp-rx-metadata-features", [])101if "hash" not in rx_meta:102raise KsftSkipEx("device does not support XDP rx hash metadata")103104prog_info = _load_xdp_metadata_prog(cfg, "xdp_rss_hash")105106port = rand_port()107bpf_map_set("map_xdp_setup", _SETUP_KEY_PORT, port)108109rss_map_id = prog_info["maps"]["map_rss"]110111_send_probe(cfg, port, proto=proto)112113rss = bpf_map_dump(rss_map_id)114115pkt_cnt = rss.get(_RSS_KEY_PKT_CNT, 0)116err_cnt = rss.get(_RSS_KEY_ERR_CNT, 0)117hash_val = rss.get(_RSS_KEY_HASH, 0)118hash_type = rss.get(_RSS_KEY_TYPE, 0)119120ksft_ge(pkt_cnt, 1, comment="should have received at least one packet")121ksft_eq(err_cnt, 0, comment=f"RSS hash error count: {err_cnt}")122123ksft_ne(hash_val, 0,124f"RSS hash should be non-zero for {proto.upper()} traffic")125ksft_pr(f" RSS hash: {hash_val:#010x}")126127ksft_pr(f" RSS hash type: {hash_type:#06x}")128ksft_ne(hash_type & XDP_RSS_L4, 0,129f"RSS hash type should include L4 for {proto.upper()} traffic")130131132def main():133"""Run XDP metadata kfunc tests against a real device."""134with NetDrvEpEnv(__file__) as cfg:135cfg.netnl = NetdevFamily()136ksft_run(137[138test_xdp_rss_hash,139],140args=(cfg,))141ksft_exit()142143144if __name__ == "__main__":145main()146147148