Skip to content

support StructOps skeleton generation in bpf2go #1957

@shun159

Description

@shun159

bpftool gen skeleton provides "shadow" for StructOps, allowing C developers to assign BPF programs to struct fields directly. In Go, cilium/ebpf users currently have to manually handle ebpf.Map.Update with binary buffers or raw slices, which is error-prone.

  1. Manual Offset Management: In projects like sched_ext, the memory layout of struct_ops changes across kernel versions. Manually calculating offsets in Go is difficult.
  2. Lack of Abstraction: There is no bridge between *ebpf.Program and the StructOps map fields in the generated code.

Proposal:

  • Enhance bpf2go to generate StructOps Shadow Types.
  • Source Generation: bpf2go scans for StructOps maps and generates Go structs mirroring the C structure.
  • Dynamic Mapping: Use User BTF (or vmlinux BTF) at runtime to resolve member offsets and sizes, ensuring compatibility across different kernels.
  • Declarative Assignment: Allow users to assign *ebpf.Program and scalar values directly to struct fields before/during load.

A mockup of the generated Go struct

// generated shadow struct by bpf2go
type bpfStructOps struct {
	MinimalSched *bpfMinimalSchedStructOps `ebpf:"minimal_sched"`
}

type bpfMinimalSchedStructOps struct {
	// Function pointers are defined as *ebpf.Program.
	SelectCpu *ebpf.Program `ebpf:"select_cpu"`
	Enqueue   *ebpf.Program `ebpf:"enqueue"`
	Dispatch  *ebpf.Program `ebpf:"dispatch"`
	Running   *ebpf.Program `ebpf:"running"`

	// Scalar values are mapped to appropriate Go types.
	Flags     uint64 `ebpf:"flags"`
	TimeoutMs uint32 `ebpf:"timeout_ms"`
}

main.go

func main() {
	objs := bpfObjects{}
	// LoadAndAssign internally binds the shadow struct with the map's initial values.
	if err := loadBpfObjects(&objs, nil); err != nil {
		log.Fatal(err)
	}
	defer objs.Close()

	// --- Highly intuitive API for users ---
	ops := objs.StructOps.MinimalSched
	
	// Dynamic program assignment at runtime.
	ops.SelectCpu = objs.Programs.MyCustomSelectCpu
	ops.Enqueue = objs.Programs.MyGlobalEnqueue
	
	// Fine-tuning parameters via scalar fields.
	ops.Flags = 0x1 // e.g., SCX_OPS_KEEP_BUILTIN_IDLE
	ops.TimeoutMs = 100

	// Map update: BTF-based offset resolution occurs internally.
	if err := objs.MinimalSched.PutStructOps(ops); err != nil {
		log.Fatalf("failed to set struct_ops: %v", err)
	}

	// Attachment.
	l, err := link.AttachStructOps(link.StructOpsOptions{Map: objs.MinimalSched})
	if err != nil {
		log.Fatal(err)
	}
	defer l.Close()
	
	// ... (Wait for signal)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions