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 import bpf, map, section, bpfglobal, compile
from pythonbpf.helpers import ktime, deref from pythonbpf.helpers import ktime
from pythonbpf.maps import HashMap from pythonbpf.maps import HashMap
from ctypes import c_void_p, c_int64, c_uint64 from ctypes import c_void_p, c_int64, c_uint64
# Instructions to how to run this program # Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf # 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python demo/pybpf.py # 2. Run the program: python demo/pybpf2.py
# 3. Run the program with sudo: sudo examples/check.sh run demo/pybpf.o # 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. # 4. Start a Python repl and `import os` and then keep entering `os.sync()` to see reponses.
@bpf @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 BPF_CLANG := clang
CFLAGS := -O0 -emit-llvm -target bpf -c CFLAGS := -O2 -emit-llvm -target bpf -c
SRC := $(wildcard *.bpf.c) SRC := $(wildcard *.bpf.c)
LL := $(SRC:.bpf.c=.bpf.ll) LL := $(SRC:.bpf.c=.bpf.ll)

View File

@ -3,20 +3,10 @@
#define u64 unsigned long long #define u64 unsigned long long
#define u32 unsigned int #define u32 unsigned int
struct { SEC("xdp")
__uint(type, BPF_MAP_TYPE_HASH); int hello(struct xdp_md *ctx) {
__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) {
bpf_printk("Hello, World!\n"); bpf_printk("Hello, World!\n");
u64 b; return XDP_PASS;
u64 a = 3 * b;
bpf_printk("%d", a);
return 0;
} }
char LICENSE[] SEC("license") = "GPL"; char LICENSE[] SEC("license") = "GPL";

View File

@ -22,11 +22,23 @@ case "$1" in
sudo rm -f "$PIN_PATH" sudo rm -f "$PIN_PATH"
echo "[+] Stopped" 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 "Usage: $0 <check|run|stop> <file.o>"
echo "Examples:" echo "Examples:"
echo " $0 check program.bpf.o" echo " $0 check program.bpf.o"
echo " $0 run program.bpf.o" echo " $0 run program.bpf.o"
echo " $0 xdp program.bpf.o wlp6s0"
echo " $0 stop" echo " $0 stop"
exit 1 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( builder.ret(ir.Constant(
ret_type, stmt.value.args[0].value)) ret_type, stmt.value.args[0].value))
did_return = True 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: else:
print("Unsupported return value") raise ValueError("Unsupported return value")
return did_return return did_return

View File

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