Support simple XDP

This commit is contained in:
2025-09-13 19:58:01 +05:30
parent 9f858bd159
commit cc5f720406
9 changed files with 148 additions and 18 deletions

23
demo/pybpf0.py Normal file
View File

@ -0,0 +1,23 @@
from pythonbpf import bpf, section, bpfglobal, compile
from ctypes import c_void_p, c_int64
# Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python demo/pybpf0.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf0.o
# 4. Start up any program and watch the output
@bpf
@section("tracepoint/syscalls/sys_enter_execve")
def hello_world(ctx: c_void_p) -> c_int64:
print("Hello, World!")
return c_int64(0)
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
compile()

41
demo/pybpf1.py Normal file
View File

@ -0,0 +1,41 @@
from pythonbpf import bpf, map, section, bpfglobal, compile
from pythonbpf.helpers import XDP_PASS
from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64
# Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python demo/pybpf1.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf1.o
# 4. Attach object file to any network device with something like ./check.sh xdp ../demo/pybpf1.o tailscale0
# 5. send traffic through the device and observe effects
@bpf
@map
def count() -> HashMap:
return HashMap(key_type=c_int64, value_type=c_int64, max_entries=1)
@bpf
@section("xdp")
def hello_world(ctx: c_void_p) -> c_int64:
key = 0
one = 1
prev = count().lookup(key)
if prev:
prevval = prev + 1
print(f"count: {prevval}")
count().update(key, prevval)
return XDP_PASS
else:
count().update(key, one)
return XDP_PASS
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
compile()

View File

@ -1,13 +1,13 @@
from pythonbpf import bpf, map, section, bpfglobal, compile
from pythonbpf.helpers import ktime, deref
from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64, c_uint64
# Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python demo/pybpf.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf.o
# 2. Run the program: python demo/pybpf2.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf2.o
# 4. Start a Python repl and `import os` and then keep entering `os.sync()` to see reponses.
@bpf

52
demo/pybpf3.py Normal file
View File

@ -0,0 +1,52 @@
from pythonbpf import bpf, map, section, bpfglobal, compile
from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64, c_uint64
# Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python demo/pybpf3.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf3.o
# 4. Start up any program and watch the output
@bpf
@map
def last() -> HashMap:
return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=3)
@bpf
@section("tracepoint/syscalls/sys_enter_execve")
def do_trace(ctx: c_void_p) -> c_int64:
key = 0
tsp = last().lookup(key)
if tsp:
kt = ktime()
delta = (kt - tsp)
if delta < 1000000000:
time_ms = (delta // 1000000)
print(f"Execve syscall entered within last second, last {time_ms} ms ago")
last().delete(key)
else:
kt = ktime()
last().update(key, kt)
return c_int64(0)
@bpf
@section("tracepoint/syscalls/sys_exit_execve")
def do_exit(ctx: c_void_p) -> c_int64:
va = 8
nm = 5 ^ va
al = 6 & 3
ru = (nm + al)
print(f"this is a variable {ru}")
return c_int64(0)
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
compile()

View File

@ -1,5 +1,5 @@
BPF_CLANG := clang
CFLAGS := -O0 -emit-llvm -target bpf -c
CFLAGS := -O2 -emit-llvm -target bpf -c
SRC := $(wildcard *.bpf.c)
LL := $(SRC:.bpf.c=.bpf.ll)

View File

@ -3,20 +3,10 @@
#define u64 unsigned long long
#define u32 unsigned int
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, u32);
__type(value, u64);
} last SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_execve")
int hello(struct pt_regs *ctx) {
SEC("xdp")
int hello(struct xdp_md *ctx) {
bpf_printk("Hello, World!\n");
u64 b;
u64 a = 3 * b;
bpf_printk("%d", a);
return 0;
return XDP_PASS;
}
char LICENSE[] SEC("license") = "GPL";

View File

@ -22,11 +22,23 @@ case "$1" in
sudo rm -f "$PIN_PATH"
echo "[+] Stopped"
;;
xdp)
echo "[*] Loading and running $FILE"
sudo bpftool net detach xdp dev $3
sudo bpftool prog load "$FILE" "$PIN_PATH" type xdp
sudo bpftool net attach xdp pinned "$PIN_PATH" dev $3
echo "[+] Program loaded. Press Ctrl+C to stop"
sudo cat /sys/kernel/debug/tracing/trace_pipe
sudo bpftool net detach xdp dev $3
sudo rm -rf "$PIN_PATH"
echo "[+] Stopped"
;;
*)
echo "Usage: $0 <check|run|stop> <file.o>"
echo "Examples:"
echo " $0 check program.bpf.o"
echo " $0 run program.bpf.o"
echo " $0 xdp program.bpf.o wlp6s0"
echo " $0 stop"
exit 1
;;

View File

@ -242,8 +242,17 @@ def process_stmt(func, module, builder, stmt, local_sym_tab, map_sym_tab, did_re
builder.ret(ir.Constant(
ret_type, stmt.value.args[0].value))
did_return = True
elif isinstance(stmt.value, ast.Name):
if stmt.value.id == "XDP_PASS":
builder.ret(ir.Constant(ret_type, 2))
did_return = True
elif stmt.value.id == "XDP_DROP":
builder.ret(ir.Constant(ret_type, 1))
did_return = True
else:
raise ValueError("Failed to evaluate return expression")
else:
print("Unsupported return value")
raise ValueError("Unsupported return value")
return did_return

View File

@ -7,3 +7,6 @@ def deref(ptr):
"dereference a pointer"
result = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_void_p)).contents.value
return result if result is not None else 0
XDP_DROP = ctypes.c_int64(1)
XDP_PASS = ctypes.c_int64(2)