Skip to content

Commit 280b68a

Browse files
committed
struct_ops: use value type as MapSpec.Value and drop unused helpers
Set MapSpec.Value to the "value struct" (`bpf_struct_ops_<ops>`) instead of the "kern struct". This matches the actual BTF layout where the sturct_ops struct matches with the `data` member inside the value type. Also remove unused helper functions (`findStructByNameWithPrefix`, `doFindStructTypeByName`, etc.) to simplify type resolution. Signed-off-by: shun159 <[email protected]>
1 parent 818cc65 commit 280b68a

File tree

6 files changed

+35
-61
lines changed

6 files changed

+35
-61
lines changed

collection.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ func (cl *collectionLoader) populateDeferredMaps() error {
721721
}
722722

723723
if mapSpec.Type == StructOpsMap {
724-
userType, ok := btf.As[*btf.Struct](mapSpec.Value)
724+
vType, ok := btf.As[*btf.Struct](mapSpec.Value)
725725
if !ok {
726726
return fmt.Errorf("value should be a *Struct")
727727
}
@@ -736,12 +736,12 @@ func (cl *collectionLoader) populateDeferredMaps() error {
736736
return fmt.Errorf("load vmlinux BTF: %w", err)
737737
}
738738

739-
kernType, _, _, err := findStructByNameWithPrefix(s, userType)
739+
kernType, _, _, err := findStructTypeByName(s, vType.Name)
740740
if err != nil {
741-
return fmt.Errorf("find wrapper type: %w", err)
741+
return fmt.Errorf("find value type: %w", err)
742742
}
743743

744-
kernVData, err := translateStructData(userType, userData, kernType)
744+
kernVData, err := translateStructData(vType, userData, kernType)
745745
if err != nil {
746746
return err
747747
}
@@ -826,13 +826,13 @@ func translateStructData(from *btf.Struct, fromData []byte, to *btf.Struct) ([]b
826826
}
827827

828828
// populateFuncPtr writes progFD into `data` at the offset
829-
func populateFuncPtr(wrapper *btf.Struct, data []byte, programs map[string]*Program) error {
830-
innerName := strings.TrimPrefix(wrapper.Name, structOpsValuePrefix)
829+
func populateFuncPtr(vType *btf.Struct, data []byte, programs map[string]*Program) error {
830+
innerName := strings.TrimPrefix(vType.Name, structOpsValuePrefix)
831831

832832
var inner *btf.Struct
833833
var innerOff int
834834

835-
for _, m := range wrapper.Members {
835+
for _, m := range vType.Members {
836836
st, ok := btf.As[*btf.Struct](btf.UnderlyingType(m.Type))
837837
if ok && st.Name == innerName {
838838
inner = st
@@ -841,7 +841,7 @@ func populateFuncPtr(wrapper *btf.Struct, data []byte, programs map[string]*Prog
841841
}
842842

843843
if inner == nil {
844-
return fmt.Errorf("member %s not found in %s", innerName, wrapper.Name)
844+
return fmt.Errorf("member %s not found in %s", innerName, vType.Name)
845845
}
846846

847847
for _, m := range inner.Members {
@@ -869,18 +869,18 @@ func (cl *collectionLoader) initKernStructOps() error {
869869
continue
870870
}
871871

872-
userSt := ms.Value
873-
if userSt == nil {
872+
kernSt := ms.Value
873+
if kernSt == nil {
874874
return fmt.Errorf("user struct type should be specified as Value")
875875
}
876876

877-
userStructType, ok := btf.As[*btf.Struct](ms.Value)
877+
kType, ok := btf.As[*btf.Struct](kernSt)
878878
if !ok {
879879
return fmt.Errorf("user struct type should be a Struct")
880880
}
881881

882-
// resolve kernel-side types (target + wrapper)
883-
kernTypes, err := findStructOpsKernTypes(userStructType)
882+
// resolve kernel-side types (target + value type)
883+
kernTypes, err := findStructOpsKernTypes(kType)
884884
if err != nil {
885885
return fmt.Errorf("find kern_type: %w", err)
886886
}

collection_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ func TestStructOpsMapSpecSimpleLoadAndAssign(t *testing.T) {
790790
},
791791
Maps: map[string]*MapSpec{
792792
"testmod_ops": {
793-
Name: "testmod_ops",
793+
Name: "bpf_struct_ops_testmod_ops",
794794
Type: StructOpsMap,
795795
Flags: sys.BPF_F_LINK,
796796
KeySize: 4,
@@ -812,7 +812,7 @@ func TestStructOpsMapSpecSimpleLoadAndAssign(t *testing.T) {
812812
t.Fatal(err)
813813
}
814814

815-
_, _, _, err = doFindStructTypeByName(s, "bpf_testmod_ops")
815+
_, _, _, err = findStructTypeByName(s, "bpf_testmod_ops")
816816
if errors.Is(err, btf.ErrNotFound) {
817817
t.Skip("bpf_testmod_ops not loaded")
818818
}

map.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -569,19 +569,19 @@ func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
569569
return nil, fmt.Errorf("struct type is not specified as Value")
570570
}
571571

572-
userStType, ok := spec.Value.(*btf.Struct)
572+
vType, ok := btf.As[*btf.Struct](spec.Value)
573573
if !ok {
574574
return nil, fmt.Errorf("value must be Struct type")
575575
}
576576

577-
// struct_ops: resolve wrapper type ("bpf_struct_ops_<name>") and
577+
// struct_ops: resolve value type ("bpf_struct_ops_<name>") and
578578
// record kernel-specific BTF IDs / FDs needed for map creation.
579-
userStructType, s, modBtfObjId, err := findStructByNameWithPrefix(s, userStType)
579+
kType, s, modBtfObjId, err := findStructTypeByName(s, vType.Name)
580580
if err != nil {
581581
return nil, fmt.Errorf("lookup struct type: %w", err)
582582
}
583583

584-
btfValueTypeId, err := s.TypeID(userStructType)
584+
btfValueTypeId, err := s.TypeID(kType)
585585
if err != nil {
586586
return nil, fmt.Errorf("lookup type_id: %w", err)
587587
}

prog.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ 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 := doFindStructTypeByName(s, attachTo)
411+
st, spec2, modBtfObjID, err := findStructTypeByName(s, attachTo)
412412
if err != nil {
413413
return nil, err
414414
}
@@ -436,7 +436,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, c *btf.Cache)
436436
}
437437
}
438438

439-
if module != nil {
439+
if module != nil && attr.AttachBtfObjFd == 0 {
440440
attr.AttachBtfObjFd = uint32(module.FD())
441441
defer module.Close()
442442
}

struct_ops.go

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type structOpsKernTypes struct {
1717
// target kernel struct type (e.g. tcp_congestion_ops).
1818
typ *btf.Struct
1919
typeID btf.TypeID
20-
// wrapper struct "bpf_struct_ops_<name>" that contains typ.
20+
// value struct "bpf_struct_ops_<name>" that contains typ.
2121
valueType *btf.Struct
2222
// The *btf.Member within valueType that embeds typ.
2323
dataMember *btf.Member
@@ -92,33 +92,7 @@ func findByTypeFromStruct(spec *btf.Spec, st *btf.Struct, typ btf.Type) (*btf.Me
9292
return nil, fmt.Errorf("member of type %s not found in %s", typ.TypeName(), st.Name)
9393
}
9494

95-
// findStructByNameWithPrefix resolves a struct_ops "value" type by name,
96-
// after applying the standard prefix convention.
97-
//
98-
// It expects val to be the user-visible struct type (e.g. "bpf_dummy_ops")
99-
// and looks up the kernel-side wrapper name:
100-
//
101-
// "bpf_dummy_ops" -> "bpf_struct_ops_bpf_dummy_ops"
102-
//
103-
// Returns the matching *btf.Struct, the *btf.Spec it was found in (either the
104-
// base vmlinux spec or a module spec), and the module BTF ID (0 for vmlinux).
105-
// See doFindStructTypeByName for resolution details and error behavior.
106-
func findStructByNameWithPrefix(s *btf.Spec, val *btf.Struct) (*btf.Struct, *btf.Spec, uint32, error) {
107-
return doFindStructTypeByName(s, structOpsValuePrefix+val.TypeName())
108-
}
109-
110-
// findStructTypeByName resolves the exact BTF struct type that corresponds
111-
// to typ.TypeName() by searching first in vmlinux and then across all loaded
112-
// kernel modules.
113-
//
114-
// Returns the first *btf.Struct that matches the name verbatim, the *btf.Spec
115-
// where it was found, and the module BTF ID (0 if found in vmlinux).
116-
// If no matching struct exists anywhere, btf.ErrNotFound is returned.
117-
func findStructTypeByName(s *btf.Spec, typ *btf.Struct) (*btf.Struct, *btf.Spec, uint32, error) {
118-
return doFindStructTypeByName(s, typ.TypeName())
119-
}
120-
121-
// doFindStructTypeByName looks up a struct type with the exact name in the
95+
// findStructTypeByName looks up a struct type with the exact name in the
12296
// provided base BTF spec, and falls back to scanning all loaded module BTFs
12397
// if it is not present in vmlinux.
12498
//
@@ -131,7 +105,7 @@ func findStructTypeByName(s *btf.Spec, typ *btf.Struct) (*btf.Struct, *btf.Spec,
131105
//
132106
// Returns (*btf.Struct, *btf.Spec, moduleID, nil) on success, or btf.ErrNotFound
133107
// if no matching struct is present in vmlinux or any module.
134-
func doFindStructTypeByName(s *btf.Spec, name string) (*btf.Struct, *btf.Spec, uint32, error) {
108+
func findStructTypeByName(s *btf.Spec, name string) (*btf.Struct, *btf.Spec, uint32, error) {
135109
if s == nil {
136110
return nil, nil, 0, fmt.Errorf("nil BTF: %w", btf.ErrNotFound)
137111
}
@@ -194,26 +168,27 @@ func findStructTypeByNameFromModule(base *btf.Spec, name string) (*btf.Struct, *
194168
// findStructOpsKernTypes discovers all kernel-side BTF artifacts that belong to
195169
// a given struct_ops, identified by the user-visible base struct name
196170
// (e.g., "tcp_congestion_ops").
197-
func findStructOpsKernTypes(userStructType *btf.Struct) (*structOpsKernTypes, error) {
171+
func findStructOpsKernTypes(kType *btf.Struct) (*structOpsKernTypes, error) {
198172
spec, err := btf.LoadKernelSpec()
199173
if err != nil {
200174
return nil, fmt.Errorf("load vmlinux BTF: %w", err)
201175
}
202176

203177
// 1. kernel target struct (e.g. tcp_congestion_ops)
204-
kType, s, modID, err := findStructTypeByName(spec, userStructType)
178+
kType, s, modID, err := findStructTypeByName(spec, kType.Name)
205179
if err != nil {
206-
return nil, fmt.Errorf("struct type: %s %w", userStructType.TypeName(), err)
180+
return nil, fmt.Errorf("struct type: %s %w", kType.TypeName(), err)
207181
}
208182

209-
// 2. wrapper struct (bpf_struct_ops_<name>)
210-
wType, _, _, err := findStructByNameWithPrefix(s, userStructType)
183+
// 2. value struct (bpf_struct_ops_<name>)
184+
vTypeName := structOpsValuePrefix + kType.Name
185+
vType, _, _, err := findStructTypeByName(s, vTypeName)
211186
if err != nil {
212-
return nil, fmt.Errorf("kern struct type for %s %w", userStructType.TypeName(), err)
187+
return nil, fmt.Errorf("kern struct type for %s %w", kType.TypeName(), err)
213188
}
214189

215190
// 3. member “data” that embeds the real ops
216-
dataMem, err := findByTypeFromStruct(s, wType, kType)
191+
dataMem, err := findByTypeFromStruct(s, vType, kType)
217192
if err != nil {
218193
return nil, err
219194
}
@@ -228,7 +203,7 @@ func findStructOpsKernTypes(userStructType *btf.Struct) (*structOpsKernTypes, er
228203
spec: s,
229204
typ: kType,
230205
typeID: kID,
231-
valueType: wType,
206+
valueType: vType,
232207
dataMember: dataMem,
233208
modBtfObjId: uint32(modID),
234209
}, nil

struct_ops_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ func TestCreateStructOpsMapSpecSimple(t *testing.T) {
1919
KeySize: 4,
2020
ValueSize: 448,
2121
MaxEntries: 1,
22-
// we use `Value` to specify a user struct type as BTF
23-
Value: &btf.Struct{Name: "bpf_testmod_ops"},
22+
Value: &btf.Struct{Name: "bpf_struct_ops_testmod_ops"},
2423
Contents: []MapKV{
2524
{
2625
Key: uint32(0),
@@ -34,7 +33,7 @@ func TestCreateStructOpsMapSpecSimple(t *testing.T) {
3433
t.Fatal(err)
3534
}
3635

37-
_, _, _, err = doFindStructTypeByName(s, "bpf_testmod_ops")
36+
_, _, _, err = findStructTypeByName(s, "bpf_struct_ops_testmod_ops")
3837
if errors.Is(err, btf.ErrNotFound) {
3938
t.Skip("bpf_testmod_ops not loaded")
4039
}

0 commit comments

Comments
 (0)