Add a test to check if the NIC reorders packets if the hit GRO. Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/lib/gro.c | 38 +++++++++++++++++-- .../selftests/drivers/net/hw/gro_hw.py | 29 ++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/lib/gro.c b/tools/testing/selftests/net/lib/gro.c index d37676c009e8..3d3312b37248 100644 --- a/tools/testing/selftests/net/lib/gro.c +++ b/tools/testing/selftests/net/lib/gro.c @@ -131,6 +131,7 @@ static int ethhdr_proto = -1; static bool ipip; static uint64_t txtime_ns; static int num_flows = 4; +static bool order_check; #define CAPACITY_PAYLOAD_LEN 200 @@ -1134,6 +1135,7 @@ static void check_capacity_pkts(int fd) static char buffer[IP_MAXPACKET + ETH_HLEN + 1]; struct iphdr *iph = (struct iphdr *)(buffer + ETH_HLEN); struct ipv6hdr *ip6h = (struct ipv6hdr *)(buffer + ETH_HLEN); + int num_pkt = 0, num_coal = 0, pkt_idx; const char *fail_reason = NULL; int flow_order[num_flows * 2]; int coalesced[num_flows]; @@ -1142,8 +1144,6 @@ static void check_capacity_pkts(int fd) int total_data = 0; int pkt_size = -1; int data_len = 0; - int num_pkt = 0; - int num_coal = 0; int flow_id; int sport; @@ -1201,6 +1201,34 @@ static void check_capacity_pkts(int fd) total_data += data_len; } + /* Check flow ordering. We expect to see all non-coalesced first segs + * then interleaved coalesced and non-coalesced second frames. + */ + pkt_idx = 0; + for (flow_id = 0; order_check && flow_id < num_flows; flow_id++) { + bool coaled = coalesced[flow_id] > CAPACITY_PAYLOAD_LEN; + + if (coaled) + continue; + + if (flow_order[pkt_idx] != flow_id) { + vlog("Flow order mismatch (non-coalesced) at position %d: expected flow %d, got flow %d\n", + pkt_idx, flow_id, flow_order[pkt_idx]); + fail_reason = fail_reason ?: "bad packet order (1)"; + } + pkt_idx++; + } + for (flow_id = 0; order_check && flow_id < num_flows; flow_id++) { + bool coaled = coalesced[flow_id] > CAPACITY_PAYLOAD_LEN; + + if (flow_order[pkt_idx] != flow_id) { + vlog("Flow order mismatch at position %d: expected flow %d, got flow %d, coalesced: %d\n", + pkt_idx, flow_id, flow_order[pkt_idx], coaled); + fail_reason = fail_reason ?: "bad packet order (2)"; + } + pkt_idx++; + } + if (!fail_reason) { vlog("All %d flows coalesced correctly\n", num_flows); printf("Test succeeded\n\n"); @@ -1614,12 +1642,13 @@ static void parse_args(int argc, char **argv) { "saddr", required_argument, NULL, 's' }, { "smac", required_argument, NULL, 'S' }, { "test", required_argument, NULL, 't' }, + { "order-check", no_argument, NULL, 'o' }, { "verbose", no_argument, NULL, 'v' }, { 0, 0, 0, 0 } }; int c; - while ((c = getopt_long(argc, argv, "46d:D:ei:n:rs:S:t:v", opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "46d:D:ei:n:rs:S:t:ov", opts, NULL)) != -1) { switch (c) { case '4': proto = PF_INET; @@ -1658,6 +1687,9 @@ static void parse_args(int argc, char **argv) case 't': testname = optarg; break; + case 'o': + order_check = true; + break; case 'v': verbose = true; break; diff --git a/tools/testing/selftests/drivers/net/hw/gro_hw.py b/tools/testing/selftests/drivers/net/hw/gro_hw.py index 3bca19e8f339..18a3b1bceefd 100755 --- a/tools/testing/selftests/drivers/net/hw/gro_hw.py +++ b/tools/testing/selftests/drivers/net/hw/gro_hw.py @@ -10,7 +10,7 @@ import glob import re from lib.py import ksft_run, ksft_exit, ksft_pr -from lib.py import ksft_eq, ksft_ge +from lib.py import ksft_eq, ksft_ge, ksft_variants from lib.py import NetDrvEpEnv, NetdevFamily from lib.py import KsftSkipEx from lib.py import bkg, cmd, defer, ethtool, ip @@ -78,7 +78,8 @@ GRO_DPORT = 8000 return test_queue -def _run_gro_test(cfg, test_name, num_flows=None, ignore_fail=False): +def _run_gro_test(cfg, test_name, num_flows=None, ignore_fail=False, + order_check=False): """Run gro binary with given test and return output.""" if not hasattr(cfg, "bin_remote"): cfg.bin_local = cfg.net_lib_dir / "gro" @@ -98,6 +99,8 @@ GRO_DPORT = 8000 ] if num_flows: base_args.append(f"--num-flows {num_flows}") + if order_check: + base_args.append("--order-check") args = " ".join(base_args) @@ -257,13 +260,33 @@ def _check_gro_stats(cfg, test_queue, stats_before, expect_wire=gro_coalesced * 2) +@ksft_variants([4, 32, 512]) +def test_gro_order(cfg, num_flows): + """ + Test that HW GRO preserves packet ordering between flows. + + Packets may get delayed until the aggreate is released, + but reordering between aggregates and packet terminating + the aggregate and normal packets should not happen. + + Note that this test is stricter than truly required. + Reordering packets between flows should not cause issues. + This test will also fail if traffic is run over an ECMP fabric. + """ + _setup_hw_gro(cfg) + _setup_isolated_queue(cfg) + + _run_gro_test(cfg, "capacity", num_flows=num_flows, order_check=True) + + def main() -> None: """ Ksft boiler plate main """ with NetDrvEpEnv(__file__, nsim_test=False) as cfg: cfg.netnl = NetdevFamily() ksft_run([test_gro_stats_single, - test_gro_stats_full], args=(cfg,)) + test_gro_stats_full, + test_gro_order], args=(cfg,)) ksft_exit() -- 2.53.0