selftests: netfilter: nft_queue.sh: avoid flakes on debug kernels

Jakub reports test flakes on debug kernels:
 FAIL: test_udp_gro_ct: Expected software segmentation to occur, had 23 and 17

This test assumes that the kernels nfnetlink_queue module sees N GSO
packets, segments them into M skbs and queues them to userspace for
reinjection.

Hence, if M >= N, no segmentation occurred.

However, its possible that this happens:
- nfnetlink_queue gets GSO packet
- segments that into n skbs
- userspace buffer is full, kernel drops the segmented skbs

-> "toqueue" counter incremented by 1, "fromqueue" is unchanged.

If this happens often enough in a single run, M >= N check triggers
incorrectly.

To solve this, allow the nf_queue.c test program to set the FAIL_OPEN
flag so that the segmented skbs bypass the queueing step in the kernel
if the receive buffer is full.

Also, reduce number of sending socat instances, decrease their priority
and increase nice value for the nf_queue program itself to reduce the
probability of overruns happening in the first place.

Fixes: 59ecffa399 ("selftests: netfilter: nft_queue.sh: add udp fraglist gro test case")
Reported-by: Jakub Kicinski <kuba@kernel.org>
Closes: https://lore.kernel.org/netdev/20260218184114.0b405b72@kernel.org/
Signed-off-by: Florian Westphal <fw@strlen.de>
Link: https://patch.msgid.link/20260226161920.1205-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Florian Westphal 2026-02-26 17:19:17 +01:00 committed by Jakub Kicinski
parent 71347b9d8c
commit ba14798653
2 changed files with 17 additions and 6 deletions

View file

@ -18,6 +18,7 @@
struct options {
bool count_packets;
bool gso_enabled;
bool failopen;
int verbose;
unsigned int queue_num;
unsigned int timeout;
@ -30,7 +31,7 @@ static struct options opts;
static void help(const char *p)
{
printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
printf("Usage: %s [-c|-v [-vv] ] [-o] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
}
static int parse_attr_cb(const struct nlattr *attr, void *data)
@ -236,6 +237,8 @@ struct mnl_socket *open_queue(void)
flags = opts.gso_enabled ? NFQA_CFG_F_GSO : 0;
flags |= NFQA_CFG_F_UID_GID;
if (opts.failopen)
flags |= NFQA_CFG_F_FAIL_OPEN;
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(flags));
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(flags));
@ -329,7 +332,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
while ((c = getopt(argc, argv, "chvt:q:Q:d:G")) != -1) {
while ((c = getopt(argc, argv, "chvot:q:Q:d:G")) != -1) {
switch (c) {
case 'c':
opts.count_packets = true;
@ -366,6 +369,9 @@ static void parse_opts(int argc, char **argv)
case 'G':
opts.gso_enabled = false;
break;
case 'o':
opts.failopen = true;
break;
case 'v':
opts.verbose++;
break;

View file

@ -591,6 +591,7 @@ EOF
test_udp_gro_ct()
{
local errprefix="FAIL: test_udp_gro_ct:"
local timeout=5
ip netns exec "$nsrouter" conntrack -F 2>/dev/null
@ -630,10 +631,10 @@ table inet udpq {
}
}
EOF
timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12346,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc &
timeout "$timeout" ip netns exec "$ns2" socat UDP-LISTEN:12346,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc &
local rpid=$!
ip netns exec "$nsrouter" ./nf_queue -G -c -q 1 -t 2 > "$TMPFILE2" &
ip netns exec "$nsrouter" nice -n -19 ./nf_queue -G -c -q 1 -o -t 2 > "$TMPFILE2" &
local nfqpid=$!
ip netns exec "$nsrouter" ethtool -K "veth0" rx-udp-gro-forwarding on rx-gro-list on generic-receive-offload on
@ -643,8 +644,12 @@ EOF
local bs=512
local count=$(((32 * 1024 * 1024) / bs))
dd if=/dev/zero bs="$bs" count="$count" 2>/dev/null | for i in $(seq 1 16); do
timeout 5 ip netns exec "$ns1" \
local nprocs=$(nproc)
[ $nprocs -gt 1 ] && nprocs=$((nprocs - 1))
dd if=/dev/zero bs="$bs" count="$count" 2>/dev/null | for i in $(seq 1 $nprocs); do
timeout "$timeout" nice -n 19 ip netns exec "$ns1" \
socat -u -b 512 STDIN UDP-DATAGRAM:10.0.2.99:12346,reuseport,bind=0.0.0.0:55221 &
done