Skip to content

Commit fbc36d3

Browse files
committed
struct_ops: remove ad-hoc helpers and use findTargetInKernel
Signed-off-by: shun159 <[email protected]>
1 parent 3040131 commit fbc36d3

File tree

6 files changed

+48
-108
lines changed

6 files changed

+48
-108
lines changed

collection.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -710,10 +710,14 @@ func (cl *collectionLoader) populateDeferredMaps() error {
710710
return fmt.Errorf("load vmlinux BTF: %w", err)
711711
}
712712

713-
vType, _, _, err := findStructTypeByName(s, valueType.Name)
713+
target := btf.Type((*btf.Struct)(nil))
714+
s, module, err := findTargetInKernel(s, valueType.Name, &target)
714715
if err != nil {
715-
return fmt.Errorf("find value type: %w", err)
716+
return fmt.Errorf("lookup value type %q: %w", valueType.Name, err)
716717
}
718+
defer module.Close()
719+
720+
vType, _ := btf.As[*btf.Struct](target)
717721

718722
kernVData, err := translateStructData(valueType, userData, vType)
719723
if err != nil {
@@ -858,9 +862,17 @@ func (cl *collectionLoader) initKernStructOps() error {
858862
}
859863

860864
kTypeName := strings.TrimPrefix(vType.Name, structOpsValuePrefix)
861-
kType, _, _, err := findStructTypeByName(s, kTypeName)
865+
866+
target := btf.Type((*btf.Struct)(nil))
867+
_, module, err := findTargetInKernel(s, kTypeName, &target)
862868
if err != nil {
863-
return fmt.Errorf("struct type: %s %w", kTypeName, err)
869+
return fmt.Errorf("lookup kern type %q: %w", kTypeName, err)
870+
}
871+
defer module.Close()
872+
873+
kType, ok := btf.As[*btf.Struct](target)
874+
if !ok {
875+
return fmt.Errorf("conversion target %s -> Struct in initKernStructOps", kTypeName)
864876
}
865877

866878
cl.setStructOpsProgAttachTo(kType)

collection_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,13 +809,15 @@ func TestStructOpsMapSpecSimpleLoadAndAssign(t *testing.T) {
809809
t.Fatal(err)
810810
}
811811

812-
_, _, _, err = findStructTypeByName(s, "bpf_testmod_ops")
812+
target := btf.Type((*btf.Struct)(nil))
813+
_, module, err := findTargetInKernel(s, "bpf_struct_ops_bpf_testmod_ops", &target)
813814
if errors.Is(err, btf.ErrNotFound) {
814815
t.Skip("bpf_testmod_ops not loaded")
815816
}
816817
if err != nil {
817818
t.Fatal(err)
818819
}
820+
defer module.Close()
819821

820822
coll := mustNewCollection(t, spec, nil)
821823
for name := range spec.Maps {

map.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -576,13 +576,19 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
576576

577577
// struct_ops: resolve value type ("bpf_struct_ops_<name>") and
578578
// record kernel-specific BTF IDs / FDs needed for map creation.
579-
vType, s, modBtfObjId, err := findStructTypeByName(s, valueType.Name)
579+
target := btf.Type((*btf.Struct)(nil))
580+
s, module, err := findTargetInKernel(s, valueType.Name, &target)
580581
if err != nil {
581582
return nil, fmt.Errorf("lookup value type %q: %w", valueType.Name, err)
582583
}
584+
defer module.Close()
585+
586+
vType, ok := btf.As[*btf.Struct](target)
587+
if !ok {
588+
return nil, fmt.Errorf("conversion target %s -> Struct for map", valueType.Name)
589+
}
583590

584591
btfValueTypeId, err := s.TypeID(vType)
585-
fmt.Println(vType, btfValueTypeId)
586592
if err != nil {
587593
return nil, fmt.Errorf("lookup type_id: %w", err)
588594
}
@@ -591,17 +597,11 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
591597
attr.BtfVmlinuxValueTypeId = btfValueTypeId
592598
attr.BtfFd = uint32(h.FD())
593599

594-
if modBtfObjId != 0 {
600+
if module != nil {
595601
// BPF_F_VTYPE_BTF_OBJ_FD is required if the type comes from a module
596602
attr.MapFlags |= sys.BPF_F_VTYPE_BTF_OBJ_FD
597-
// resolve a module handler for the kernel model
598-
modH, err := btf.NewHandleFromID(btf.ID(modBtfObjId))
599-
if err != nil {
600-
return nil, fmt.Errorf("open module BTF (id=%d): %w", modBtfObjId, err)
601-
}
602603
// set FD for the kernel module
603-
attr.ValueTypeBtfObjFd = int32(modH.FD())
604-
defer modH.Close()
604+
attr.ValueTypeBtfObjFd = int32(module.FD())
605605
}
606606
} else {
607607
handle, keyTypeID, valueTypeID, err := btf.MarshalMapKV(spec.Key, spec.Value)

prog.go

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -408,31 +408,33 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache)
408408
return nil, fmt.Errorf("load vmlinux BTF: %w", err)
409409
}
410410

411-
st, spec2, modBtfObjID, err := findStructTypeByName(s, attachTo)
411+
target := btf.Type((*btf.Struct)(nil))
412+
s, module, err := findTargetInKernel(s, attachTo, &target)
412413
if err != nil {
413-
return nil, err
414+
return nil, fmt.Errorf("lookup struct_ops kern type %q: %w", attachTo, err)
415+
}
416+
defer module.Close()
417+
418+
kType, ok := btf.As[*btf.Struct](target)
419+
if !ok {
420+
return nil, fmt.Errorf("conversion target %s -> Struct for prog", attachTo)
414421
}
415422

416-
tid, err := spec2.TypeID(st)
423+
tid, err := s.TypeID(kType)
417424
if err != nil {
418-
return nil, fmt.Errorf("type id for %s: %w", st.TypeName(), err)
425+
return nil, fmt.Errorf("type id for %s: %w", kType.TypeName(), err)
419426
}
420427
attr.AttachBtfId = sys.TypeID(tid)
421428

422-
idx := getStructMemberIndexByName(st, targetMember)
429+
idx := getStructMemberIndexByName(kType, targetMember)
423430
if idx < 0 {
424-
return nil, fmt.Errorf("member %q not found in %s", targetMember, st.Name)
431+
return nil, fmt.Errorf("member %q not found in %s", targetMember, kType.Name)
425432
}
426433

427434
attr.ExpectedAttachType = sys.AttachType(idx)
428435

429-
if modBtfObjID != 0 {
430-
h, err := btf.NewHandleFromID(btf.ID(modBtfObjID))
431-
if err != nil {
432-
return nil, fmt.Errorf("open module BTF handle (id=%d): %w", modBtfObjID, err)
433-
}
434-
defer h.Close()
435-
attr.AttachBtfObjFd = uint32(h.FD())
436+
if module != nil {
437+
attr.AttachBtfObjFd = uint32(module.FD())
436438
}
437439
}
438440

struct_ops.go

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,9 @@
11
package ebpf
22

3-
import (
4-
"errors"
5-
"fmt"
6-
7-
"github.com/cilium/ebpf/btf"
8-
)
3+
import "github.com/cilium/ebpf/btf"
94

105
const structOpsValuePrefix = "bpf_struct_ops_"
116

12-
// findStructTypeByName looks up a struct type with the exact name in the
13-
// provided base BTF spec, and falls back to scanning all loaded module BTFs
14-
// if it is not present in vmlinux.
15-
//
16-
// Search order and behavior:
17-
// 1. vmlinux (base spec): try AnyTypeByName(name). If it exists and is a
18-
// *btf.Struct, return it immediately with moduleID=0.
19-
// - If AnyTypeByName returns a non-notfound error, the error is propagated.
20-
// - If a type is found but is not a *btf.Struct, we fall back to modules.
21-
// 2. modules: see findStructTypeByNameFromModule.
22-
//
23-
// Returns (*btf.Struct, *btf.Spec, moduleID, nil) on success, or btf.ErrNotFound
24-
// if no matching struct is present in vmlinux or any module.
25-
func findStructTypeByName(s *btf.Spec, name string) (*btf.Struct, *btf.Spec, uint32, error) {
26-
if s == nil {
27-
return nil, nil, 0, fmt.Errorf("nil BTF: %w", btf.ErrNotFound)
28-
}
29-
30-
t, err := s.AnyTypeByName(name)
31-
if err == nil {
32-
if typ, ok := btf.As[*btf.Struct](t); ok {
33-
return typ, s, 0, nil
34-
}
35-
} else if !errors.Is(err, btf.ErrNotFound) {
36-
return nil, nil, 0, err
37-
}
38-
return findStructTypeByNameFromModule(s, name)
39-
}
40-
41-
// findStructTypeByNameFromModule scans all loaded kernel modules and tries
42-
// to resolve a struct type with the exact name. The iteration uses the base
43-
// vmlinux spec for string/ID interning as required by btf.Handle.Spec(base).
44-
//
45-
// For the first module where AnyTypeByName(name) returns a *btf.Struct,
46-
// the function returns that struct, the module's *btf.Spec, and its BTF ID.
47-
// If the type is not found in any module, btf.ErrNotFound is returned.
48-
func findStructTypeByNameFromModule(base *btf.Spec, name string) (*btf.Struct, *btf.Spec, uint32, error) {
49-
it := new(btf.HandleIterator)
50-
51-
for it.Next() {
52-
defer it.Handle.Close()
53-
54-
info, err := it.Handle.Info()
55-
if err != nil {
56-
return nil, nil, 0, fmt.Errorf("get info for BTF ID %d: %w", it.ID, err)
57-
}
58-
59-
if !info.IsModule() {
60-
continue
61-
}
62-
63-
spec, err := it.Handle.Spec(base)
64-
if err != nil {
65-
return nil, nil, 0, fmt.Errorf("parse types for module %s: %w", info.Name, err)
66-
}
67-
68-
t, err := spec.AnyTypeByName(name)
69-
if errors.Is(err, btf.ErrNotFound) {
70-
continue
71-
}
72-
73-
if err != nil {
74-
return nil, nil, 0, fmt.Errorf("lookup type in module %s: %w", info.Name, err)
75-
}
76-
77-
if typ, ok := btf.As[*btf.Struct](t); ok {
78-
return typ, spec, uint32(it.ID), nil
79-
}
80-
}
81-
82-
return nil, nil, 0, btf.ErrNotFound
83-
}
84-
857
// getStructMemberIndexByName returns the index of `member` within struct `s` by
868
// comparing the member name.
879
func getStructMemberIndexByName(s *btf.Struct, name string) int {

struct_ops_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,15 @@ func TestCreateStructOpsMapSpecSimple(t *testing.T) {
3333
t.Fatal(err)
3434
}
3535

36-
_, _, _, err = findStructTypeByName(s, "bpf_struct_ops_bpf_testmod_ops")
36+
target := btf.Type((*btf.Struct)(nil))
37+
_, module, err := findTargetInKernel(s, "bpf_struct_ops_bpf_testmod_ops", &target)
3738
if errors.Is(err, btf.ErrNotFound) {
3839
t.Skip("bpf_testmod_ops not loaded")
3940
}
4041
if err != nil {
4142
t.Fatal(err)
4243
}
44+
defer module.Close()
4345

4446
m, err := NewMap(ms)
4547
testutils.SkipIfNotSupported(t, err)

0 commit comments

Comments
 (0)