Skip to content

Commit 27ba925

Browse files
kuba-mooPaolo Abeni
authored andcommitted
selftests: drv-net: xdp: add test for interface level qstats
Send a non-trivial number of packets and make sure that they are counted correctly in qstats. Per qstats specification XDP is the first layer of the stack so we should see Rx and Tx counters go up for packets which went thru XDP. Reviewed-by: Simon Horman <horms@kernel.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com> Link: https://patch.msgid.link/20251007232653.2099376-6-kuba@kernel.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 1ad3f62 commit 27ba925

1 file changed

Lines changed: 89 additions & 2 deletions

File tree

  • tools/testing/selftests/drivers/net

tools/testing/selftests/drivers/net/xdp.py

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
from dataclasses import dataclass
1212
from enum import Enum
1313

14-
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ne, ksft_pr
15-
from lib.py import KsftFailEx, NetDrvEpEnv, EthtoolFamily, NlError
14+
from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_ne, ksft_pr
15+
from lib.py import KsftFailEx, NetDrvEpEnv
16+
from lib.py import EthtoolFamily, NetdevFamily, NlError
1617
from lib.py import bkg, cmd, rand_port, wait_port_listen
1718
from lib.py import ip, bpftool, defer
1819

@@ -671,6 +672,88 @@ def test_xdp_native_adjst_head_shrnk_data(cfg):
671672
_validate_res(res, offset_lst, pkt_sz_lst)
672673

673674

675+
def _test_xdp_native_ifc_stats(cfg, act):
676+
cfg.require_cmd("socat")
677+
678+
bpf_info = BPFProgInfo("xdp_prog", "xdp_native.bpf.o", "xdp", 1500)
679+
prog_info = _load_xdp_prog(cfg, bpf_info)
680+
port = rand_port()
681+
682+
_set_xdp_map("map_xdp_setup", TestConfig.MODE.value, act.value)
683+
_set_xdp_map("map_xdp_setup", TestConfig.PORT.value, port)
684+
685+
# Discard the input, but we need a listener to avoid ICMP errors
686+
rx_udp = f"socat -{cfg.addr_ipver} -T 2 -u UDP-RECV:{port},reuseport " + \
687+
"/dev/null"
688+
# Listener runs on "remote" in case of XDP_TX
689+
rx_host = cfg.remote if act == XDPAction.TX else None
690+
# We want to spew 2000 packets quickly, bash seems to do a good enough job
691+
tx_udp = f"exec 5<>/dev/udp/{cfg.addr}/{port}; " \
692+
"for i in `seq 2000`; do echo a >&5; done; exec 5>&-"
693+
694+
cfg.wait_hw_stats_settle()
695+
# Qstats have more clearly defined semantics than rtnetlink.
696+
# XDP is the "first layer of the stack" so XDP packets should be counted
697+
# as received and sent as if the decision was made in the routing layer.
698+
before = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
699+
700+
with bkg(rx_udp, host=rx_host, exit_wait=True):
701+
wait_port_listen(port, proto="udp", host=rx_host)
702+
cmd(tx_udp, host=cfg.remote, shell=True)
703+
704+
cfg.wait_hw_stats_settle()
705+
after = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
706+
707+
ksft_ge(after['rx-packets'] - before['rx-packets'], 2000)
708+
if act == XDPAction.TX:
709+
ksft_ge(after['tx-packets'] - before['tx-packets'], 2000)
710+
711+
expected_pkts = 2000
712+
stats = _get_stats(prog_info["maps"]["map_xdp_stats"])
713+
ksft_eq(stats[XDPStats.RX.value], expected_pkts, "XDP RX stats mismatch")
714+
if act == XDPAction.TX:
715+
ksft_eq(stats[XDPStats.TX.value], expected_pkts, "XDP TX stats mismatch")
716+
717+
# Flip the ring count back and forth to make sure the stats from XDP rings
718+
# don't get lost.
719+
chans = cfg.ethnl.channels_get({'header': {'dev-index': cfg.ifindex}})
720+
if chans.get('combined-count', 0) > 1:
721+
cfg.ethnl.channels_set({'header': {'dev-index': cfg.ifindex},
722+
'combined-count': 1})
723+
cfg.ethnl.channels_set({'header': {'dev-index': cfg.ifindex},
724+
'combined-count': chans['combined-count']})
725+
before = after
726+
after = cfg.netnl.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
727+
728+
ksft_ge(after['rx-packets'], before['rx-packets'])
729+
if act == XDPAction.TX:
730+
ksft_ge(after['tx-packets'], before['tx-packets'])
731+
732+
733+
def test_xdp_native_qstats_pass(cfg):
734+
"""
735+
Send 2000 messages, expect XDP_PASS, make sure the packets were counted
736+
to interface level qstats (Rx).
737+
"""
738+
_test_xdp_native_ifc_stats(cfg, XDPAction.PASS)
739+
740+
741+
def test_xdp_native_qstats_drop(cfg):
742+
"""
743+
Send 2000 messages, expect XDP_DROP, make sure the packets were counted
744+
to interface level qstats (Rx).
745+
"""
746+
_test_xdp_native_ifc_stats(cfg, XDPAction.DROP)
747+
748+
749+
def test_xdp_native_qstats_tx(cfg):
750+
"""
751+
Send 2000 messages, expect XDP_TX, make sure the packets were counted
752+
to interface level qstats (Rx and Tx)
753+
"""
754+
_test_xdp_native_ifc_stats(cfg, XDPAction.TX)
755+
756+
674757
def main():
675758
"""
676759
Main function to execute the XDP tests.
@@ -682,6 +765,7 @@ def main():
682765
"""
683766
with NetDrvEpEnv(__file__) as cfg:
684767
cfg.ethnl = EthtoolFamily()
768+
cfg.netnl = NetdevFamily()
685769
ksft_run(
686770
[
687771
test_xdp_native_pass_sb,
@@ -694,6 +778,9 @@ def main():
694778
test_xdp_native_adjst_tail_shrnk_data,
695779
test_xdp_native_adjst_head_grow_data,
696780
test_xdp_native_adjst_head_shrnk_data,
781+
test_xdp_native_qstats_pass,
782+
test_xdp_native_qstats_drop,
783+
test_xdp_native_qstats_tx,
697784
],
698785
args=(cfg,))
699786
ksft_exit()

0 commit comments

Comments
 (0)