Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,7 @@ BTF, or `bpftool` or `clang` is unavailable.
drops on rejection, so a working guard blocks the ping, proving the
kfunc ran and returned without crashing.

- **xdp percpu**: with the ping pinned to the last online CPU, which is where
the veth runs the receive softirq, the callback of a percpu script reports
that CPU as its instance id, and no other; skipped on a single CPU.

6 changes: 1 addition & 5 deletions tests/runtime/percpu_fail.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@

local lunatik = require("lunatik")

local env = lunatik._ENV
local count = (env.percpu_fail_count or 0) + 1
env.percpu_fail_count = count
if count == 2 then
env.percpu_fail_count = nil
if lunatik.cpu() == 1 then
error("intentional error on the second instance")
end

Expand Down
7 changes: 5 additions & 2 deletions tests/xdp/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: (c) 2026 Ashwani Kumar Kamal <ashwanikamal.im421@gmail.com>
# SPDX-License-Identifier: MIT OR GPL-2.0-only

all: xdp_pass.bpf.o xdp_drop.bpf.o xdp_detach.bpf.o xdp_zerokey.bpf.o
all: xdp_pass.bpf.o xdp_drop.bpf.o xdp_detach.bpf.o xdp_zerokey.bpf.o xdp_percpu.bpf.o

vmlinux.h:
bpftool btf dump file /sys/kernel/btf/vmlinux format c > $@
Expand All @@ -18,6 +18,9 @@ xdp_detach.bpf.o: xdp_detach.bpf.c vmlinux.h
xdp_zerokey.bpf.o: xdp_zerokey.bpf.c vmlinux.h
clang -target bpf -Wall -O2 -c -g $<

xdp_percpu.bpf.o: xdp_percpu.bpf.c vmlinux.h
clang -target bpf -Wall -O2 -c -g $<

clean:
rm -f vmlinux.h xdp_pass.bpf.o xdp_drop.bpf.o xdp_detach.bpf.o xdp_zerokey.bpf.o
rm -f vmlinux.h xdp_pass.bpf.o xdp_drop.bpf.o xdp_detach.bpf.o xdp_zerokey.bpf.o xdp_percpu.bpf.o

29 changes: 29 additions & 0 deletions tests/xdp/percpu.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--
-- SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
-- SPDX-License-Identifier: MIT OR GPL-2.0-only
--
-- Kernel-side script for the xdp percpu dispatch test (see test_xdp.sh).

local lunatik = require("lunatik")
local xdp = require("xdp")
local action = require("linux.xdp")

local ETH_HI <const> = 12 -- ethertype, then IPv4 protocol
local ETH_LO <const> = 13
local IPPROTO <const> = 23
local ICMP <const> = 1

local cpu = lunatik.cpu()

local function test_percpu(ctx)
local packet = ctx:packet()
-- the namespace also emits IPv6 autoconf traffic, from a context the test does not pin
if packet:getuint8(ETH_HI) == 0x08 and packet:getuint8(ETH_LO) == 0x00
and packet:getuint8(IPPROTO) == ICMP then
print("xdp percpu test hit: cpu " .. cpu)
end
ctx:action(action.PASS)
end

xdp.attach(test_percpu)

37 changes: 35 additions & 2 deletions tests/xdp/test_xdp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ DIR="$(dirname "$(readlink -f "$0")")"
source "$DIR/../lib.sh"

ktap_header
ktap_plan 5
ktap_plan 6

skip_all()
{
Expand All @@ -31,6 +31,7 @@ skip_all()
ktap_skip "xdp detach: callback stops firing and traffic resumes"
ktap_skip "xdp attach: refuses a sleepable runtime"
ktap_skip "xdp zero-key: a zero-sized key is rejected without a crash"
ktap_skip "xdp percpu: the callback runs on the instance of the receiving CPU"
ktap_totals
exit 0
}
Expand All @@ -43,11 +44,12 @@ command -v clang > /dev/null 2>&1 || skip_all "clang not available"
cleanup()
{
bpftool net detach xdp dev "$IFACE" 2>/dev/null
rm -f "${PIN}_pass" "${PIN}_drop" "${PIN}_detach" "${PIN}_zerokey"
rm -f "${PIN}_pass" "${PIN}_drop" "${PIN}_detach" "${PIN}_zerokey" "${PIN}_percpu"
lunatik stop tests/xdp/pass > /dev/null 2>&1
lunatik stop tests/xdp/drop > /dev/null 2>&1
lunatik stop tests/xdp/detach > /dev/null 2>&1
lunatik stop tests/xdp/attach_sleepable > /dev/null 2>&1
lunatik stop tests/xdp/percpu > /dev/null 2>&1
ip netns del "$NETNS" 2>/dev/null
ip link del "$IFACE" 2>/dev/null
}
Expand Down Expand Up @@ -150,6 +152,36 @@ zerokey_case()
ktap_pass "xdp zero-key: a zero-sized key is rejected without a crash"
}

# the veth runs the receive softirq on the sending CPU, so the pinned ping picks the instance
percpu_case()
{
local title="xdp percpu: the callback runs on the instance of the receiving CPU"
local cpu hits
cpu=$(sed 's/.*[-,]//' /sys/devices/system/cpu/online)
[ "$cpu" -ge 1 ] || { ktap_skip "$title (needs >1 CPU)"; return 0; }
command -v taskset > /dev/null 2>&1 || { ktap_skip "$title (taskset not available)"; return 0; }

bpftool prog load "$DIR/xdp_percpu.bpf.o" "${PIN}_percpu" type xdp ||
{ ktap_fail "xdp percpu: failed to load XDP program"; return 1; }
bpftool net attach xdp pinned "${PIN}_percpu" dev "$IFACE" ||
{ ktap_fail "xdp percpu: failed to attach XDP program"; bpftool prog unpin "${PIN}_percpu"; return 1; }

mark_dmesg
run_script "tests/xdp/percpu" softirq percpu
check_dmesg || { ktap_fail "xdp percpu: script raised an error"; return 1; }
taskset -c "$cpu" ip netns exec "$NETNS" ping -c 3 -W 2 "$TARGET" > /dev/null 2>&1

bpftool net detach xdp dev "$IFACE" 2>/dev/null
rm -f "${PIN}_percpu"
lunatik stop tests/xdp/percpu > /dev/null 2>&1

hits=$(dmesg_since | grep -o "xdp percpu test hit: cpu [0-9]*" | sort -u)
[ -n "$hits" ] || { ktap_fail "xdp percpu: the callback did not run"; return 1; }
[ "$hits" = "xdp percpu test hit: cpu $cpu" ] ||
{ ktap_fail "xdp percpu: expected the instance of CPU $cpu, got: $(echo $hits)"; return 1; }
ktap_pass "$title"
}

run_case xdp_pass.bpf.o "${PIN}_pass" pass.lua yes "xdp pass" \
"xdp pass: verdict enforced, packet and argument content verified" softirq
run_case xdp_drop.bpf.o "${PIN}_drop" drop.lua no "xdp drop" \
Expand All @@ -163,6 +195,7 @@ lunatik stop tests/xdp/attach_sleepable > /dev/null 2>&1
ktap_pass "xdp attach: refuses a sleepable runtime"

zerokey_case
percpu_case

ktap_totals

23 changes: 23 additions & 0 deletions tests/xdp/xdp_percpu.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: (c) 2026 Ring Zero Desenvolvimento de Software LTDA
* SPDX-License-Identifier: MIT OR GPL-2.0-only
*/

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>

extern int bpf_luaxdp_run(char *key, size_t key__sz, struct xdp_md *ctx,
void *arg, size_t arg__sz) __ksym;

static char runtime[] = "tests/xdp/percpu";

SEC("xdp")
int test_xdp_percpu(struct xdp_md *ctx)
{
int ret;
ret = bpf_luaxdp_run(runtime, sizeof(runtime), ctx, NULL, 0);
return ret < 0 ? XDP_PASS : ret;
}

char _license[] SEC("license") = "Dual MIT/GPL";

Loading