mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2025-12-31 21:06:25 +00:00
add i32 support special case and find ctx repetition in multiple functions error.
This commit is contained in:
@ -81,7 +81,7 @@ def _allocate_for_call(builder, var_name, rval, local_sym_tab, structs_sym_tab):
|
|||||||
call_type = rval.func.id
|
call_type = rval.func.id
|
||||||
|
|
||||||
# C type constructors
|
# C type constructors
|
||||||
if call_type in ("c_int32", "c_int64", "c_uint32", "c_uint64"):
|
if call_type in ("c_int32", "c_int64", "c_uint32", "c_uint64", "c_void_p"):
|
||||||
ir_type = ctypes_to_ir(call_type)
|
ir_type = ctypes_to_ir(call_type)
|
||||||
var = builder.alloca(ir_type, name=var_name)
|
var = builder.alloca(ir_type, name=var_name)
|
||||||
var.align = ir_type.width // 8
|
var.align = ir_type.width // 8
|
||||||
@ -259,7 +259,16 @@ def _allocate_for_attribute(builder, var_name, rval, local_sym_tab, structs_sym_
|
|||||||
field_size_bits = field_size_bytes * 8
|
field_size_bits = field_size_bytes * 8
|
||||||
|
|
||||||
if field_size_bits in [8, 16, 32, 64]:
|
if field_size_bits in [8, 16, 32, 64]:
|
||||||
actual_ir_type = ir.IntType(field_size_bits)
|
# Special case: struct_xdp_md i32 fields should allocate as i64
|
||||||
|
# because load_ctx_field will zero-extend them to i64
|
||||||
|
if vmlinux_struct_name == "struct_xdp_md" and field_size_bits == 32:
|
||||||
|
actual_ir_type = ir.IntType(64)
|
||||||
|
logger.info(
|
||||||
|
f"Allocating {var_name} as i64 for i32 field from struct_xdp_md.{field_name} "
|
||||||
|
"(will be zero-extended during load)"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
actual_ir_type = ir.IntType(field_size_bits)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Unusual field size {field_size_bits} bits for {field_name}"
|
f"Unusual field size {field_size_bits} bits for {field_name}"
|
||||||
|
|||||||
@ -152,15 +152,26 @@ def handle_variable_assignment(
|
|||||||
if val_type != var_type:
|
if val_type != var_type:
|
||||||
if isinstance(val_type, Field):
|
if isinstance(val_type, Field):
|
||||||
logger.info("Handling assignment to struct field")
|
logger.info("Handling assignment to struct field")
|
||||||
|
# Special handling for struct_xdp_md i32 fields that are zero-extended to i64
|
||||||
|
# The load_ctx_field already extended them, so val is i64 but val_type.type shows c_uint
|
||||||
|
if (hasattr(val_type, 'type') and
|
||||||
|
val_type.type.__name__ == "c_uint" and
|
||||||
|
isinstance(var_type, ir.IntType) and
|
||||||
|
var_type.width == 64):
|
||||||
|
# This is the struct_xdp_md case - value is already i64
|
||||||
|
builder.store(val, var_ptr)
|
||||||
|
logger.info(f"Assigned zero-extended struct_xdp_md i32 field to {var_name} (i64)")
|
||||||
|
return True
|
||||||
# TODO: handling only ctype struct fields for now. Handle other stuff too later.
|
# TODO: handling only ctype struct fields for now. Handle other stuff too later.
|
||||||
if var_type == ctypes_to_ir(val_type.type.__name__):
|
elif var_type == ctypes_to_ir(val_type.type.__name__):
|
||||||
builder.store(val, var_ptr)
|
builder.store(val, var_ptr)
|
||||||
logger.info(f"Assigned ctype struct field to {var_name}")
|
logger.info(f"Assigned ctype struct field to {var_name}")
|
||||||
return True
|
return True
|
||||||
logger.error(
|
else:
|
||||||
f"Failed to assign ctype struct field to {var_name}: {val_type} != {var_type}"
|
logger.error(
|
||||||
)
|
f"Failed to assign ctype struct field to {var_name}: {val_type} != {var_type}"
|
||||||
return False
|
)
|
||||||
|
return False
|
||||||
elif isinstance(val_type, ir.IntType) and isinstance(var_type, ir.IntType):
|
elif isinstance(val_type, ir.IntType) and isinstance(var_type, ir.IntType):
|
||||||
# Allow implicit int widening
|
# Allow implicit int widening
|
||||||
if val_type.width < var_type.width:
|
if val_type.width < var_type.width:
|
||||||
|
|||||||
@ -94,12 +94,13 @@ class VmlinuxHandler:
|
|||||||
f"Attempting to access field {field_name} of possible vmlinux struct {struct_var_name}"
|
f"Attempting to access field {field_name} of possible vmlinux struct {struct_var_name}"
|
||||||
)
|
)
|
||||||
python_type: type = var_info.metadata
|
python_type: type = var_info.metadata
|
||||||
|
struct_name = python_type.__name__
|
||||||
globvar_ir, field_data = self.get_field_type(
|
globvar_ir, field_data = self.get_field_type(
|
||||||
python_type.__name__, field_name
|
struct_name, field_name
|
||||||
)
|
)
|
||||||
builder.function.args[0].type = ir.PointerType(ir.IntType(8))
|
builder.function.args[0].type = ir.PointerType(ir.IntType(8))
|
||||||
field_ptr = self.load_ctx_field(
|
field_ptr = self.load_ctx_field(
|
||||||
builder, builder.function.args[0], globvar_ir, field_data
|
builder, builder.function.args[0], globvar_ir, field_data, struct_name
|
||||||
)
|
)
|
||||||
# Return pointer to field and field type
|
# Return pointer to field and field type
|
||||||
return field_ptr, field_data
|
return field_ptr, field_data
|
||||||
@ -107,7 +108,7 @@ class VmlinuxHandler:
|
|||||||
raise RuntimeError("Variable accessed not found in symbol table")
|
raise RuntimeError("Variable accessed not found in symbol table")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_ctx_field(builder, ctx_arg, offset_global, field_data):
|
def load_ctx_field(builder, ctx_arg, offset_global, field_data, struct_name=None):
|
||||||
"""
|
"""
|
||||||
Generate LLVM IR to load a field from BPF context using offset.
|
Generate LLVM IR to load a field from BPF context using offset.
|
||||||
|
|
||||||
@ -116,8 +117,9 @@ class VmlinuxHandler:
|
|||||||
ctx_arg: The context pointer argument (ptr/i8*)
|
ctx_arg: The context pointer argument (ptr/i8*)
|
||||||
offset_global: Global variable containing the field offset (i64)
|
offset_global: Global variable containing the field offset (i64)
|
||||||
field_data: contains data about the field
|
field_data: contains data about the field
|
||||||
|
struct_name: Name of the struct being accessed (optional)
|
||||||
Returns:
|
Returns:
|
||||||
The loaded value (i64 register)
|
The loaded value (i64 register or appropriately sized)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Load the offset value
|
# Load the offset value
|
||||||
@ -164,6 +166,7 @@ class VmlinuxHandler:
|
|||||||
|
|
||||||
# Determine the appropriate IR type based on field information
|
# Determine the appropriate IR type based on field information
|
||||||
int_width = 64 # Default to 64-bit
|
int_width = 64 # Default to 64-bit
|
||||||
|
needs_zext = False # Track if we need zero-extension for xdp_md
|
||||||
|
|
||||||
if field_data is not None:
|
if field_data is not None:
|
||||||
# Try to determine the size from field metadata
|
# Try to determine the size from field metadata
|
||||||
@ -175,6 +178,12 @@ class VmlinuxHandler:
|
|||||||
if field_size_bits in [8, 16, 32, 64]:
|
if field_size_bits in [8, 16, 32, 64]:
|
||||||
int_width = field_size_bits
|
int_width = field_size_bits
|
||||||
logger.info(f"Determined field size: {int_width} bits")
|
logger.info(f"Determined field size: {int_width} bits")
|
||||||
|
|
||||||
|
# Special handling for struct_xdp_md i32 fields
|
||||||
|
# Load as i32 but extend to i64 before storing
|
||||||
|
if struct_name == "struct_xdp_md" and int_width == 32:
|
||||||
|
needs_zext = True
|
||||||
|
logger.info(f"struct_xdp_md i32 field detected, will zero-extend to i64")
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Unusual field size {field_size_bits} bits, using default 64"
|
f"Unusual field size {field_size_bits} bits, using default 64"
|
||||||
@ -203,6 +212,11 @@ class VmlinuxHandler:
|
|||||||
# Load and return the value
|
# Load and return the value
|
||||||
value = builder.load(typed_ptr)
|
value = builder.load(typed_ptr)
|
||||||
|
|
||||||
|
# Zero-extend i32 to i64 for struct_xdp_md fields
|
||||||
|
if needs_zext:
|
||||||
|
value = builder.zext(value, ir.IntType(64))
|
||||||
|
logger.info("Zero-extended i32 value to i64 for struct_xdp_md field")
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def has_field(self, struct_name, field_name):
|
def has_field(self, struct_name, field_name):
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
BPF_CLANG := clang
|
BPF_CLANG := clang
|
||||||
CFLAGS := -O0 -emit-llvm -target bpf -c
|
CFLAGS := -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)
|
||||||
|
LL2 := $(SRC:.bpf.c=.bpf.o2.ll)
|
||||||
OBJ := $(SRC:.bpf.c=.bpf.o)
|
OBJ := $(SRC:.bpf.c=.bpf.o)
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
all: $(LL) $(OBJ)
|
all: $(LL) $(OBJ) $(LL2)
|
||||||
|
|
||||||
%.bpf.o: %.bpf.c
|
%.bpf.o: %.bpf.c
|
||||||
$(BPF_CLANG) -O2 -g -target bpf -c $< -o $@
|
$(BPF_CLANG) -O2 -g -target bpf -c $< -o $@
|
||||||
|
|
||||||
%.bpf.ll: %.bpf.c
|
%.bpf.ll: %.bpf.c
|
||||||
$(BPF_CLANG) $(CFLAGS) -g -S $< -o $@
|
$(BPF_CLANG) -O0 $(CFLAGS) -g -S $< -o $@
|
||||||
|
|
||||||
|
%.bpf.o2.ll: %.bpf.c
|
||||||
|
$(BPF_CLANG) -O2 $(CFLAGS) -g -S $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(LL) $(OBJ)
|
rm -f $(LL) $(OBJ) $(LL2)
|
||||||
|
|||||||
@ -5,9 +5,9 @@ SEC("xdp")
|
|||||||
int print_xdp_data(struct xdp_md *ctx)
|
int print_xdp_data(struct xdp_md *ctx)
|
||||||
{
|
{
|
||||||
// 'data' is a pointer to the start of packet data
|
// 'data' is a pointer to the start of packet data
|
||||||
void *data = (void *)(long)ctx->data;
|
long data = (long)ctx->data;
|
||||||
|
|
||||||
bpf_printk("ctx->data = %p\n", data);
|
bpf_printk("ctx->data = %lld\n", data);
|
||||||
|
|
||||||
return XDP_PASS;
|
return XDP_PASS;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from ctypes import c_int64, c_int32
|
from ctypes import c_int64, c_int32, c_void_p
|
||||||
from pythonbpf import bpf, section, bpfglobal, compile_to_ir, compile
|
from pythonbpf import bpf, section, bpfglobal, compile_to_ir, compile
|
||||||
from vmlinux import struct_xdp_md
|
from vmlinux import struct_xdp_md
|
||||||
from vmlinux import XDP_PASS
|
from vmlinux import XDP_PASS
|
||||||
@ -8,10 +8,16 @@ from vmlinux import XDP_PASS
|
|||||||
@section("xdp")
|
@section("xdp")
|
||||||
def print_xdp_data(ctx: struct_xdp_md) -> c_int64:
|
def print_xdp_data(ctx: struct_xdp_md) -> c_int64:
|
||||||
data = ctx.data # 32-bit field: packet start pointer
|
data = ctx.data # 32-bit field: packet start pointer
|
||||||
something = c_int32(2 + data)
|
something = c_void_p(data)
|
||||||
print(f"ctx->data = {something}")
|
print(f"ctx->data = {something}")
|
||||||
return c_int64(XDP_PASS)
|
return c_int64(XDP_PASS)
|
||||||
|
|
||||||
|
@bpf
|
||||||
|
@section("xdp")
|
||||||
|
def print_xdp_dat2a(ct2x: struct_xdp_md) -> c_int64:
|
||||||
|
data = ct2x.data # 32-bit field: packet start pointer
|
||||||
|
print(f"ct2x->data = {data}")
|
||||||
|
return c_int64(XDP_PASS)
|
||||||
|
|
||||||
@bpf
|
@bpf
|
||||||
@bpfglobal
|
@bpfglobal
|
||||||
|
|||||||
Reference in New Issue
Block a user