7
7
"path/filepath"
8
8
"reflect"
9
9
"strings"
10
- "unsafe"
11
10
12
11
"github.com/cilium/ebpf/asm"
13
12
"github.com/cilium/ebpf/btf"
@@ -676,6 +675,7 @@ func (cl *collectionLoader) loadVariable(varName string) (*Variable, error) {
676
675
// populateDeferredMaps iterates maps holding programs or other maps and loads
677
676
// any dependencies. Populates all maps in cl and freezes them if specified.
678
677
func (cl * collectionLoader ) populateDeferredMaps () error {
678
+ fmt .Println ("hogehogehogehoge" )
679
679
for mapName , m := range cl .maps {
680
680
mapSpec , ok := cl .coll .Maps [mapName ]
681
681
if ! ok {
@@ -721,31 +721,37 @@ func (cl *collectionLoader) populateDeferredMaps() error {
721
721
}
722
722
723
723
if mapSpec .Type == StructOpsMap {
724
- structOps , ok := cl . stOpsSpecs [ mapName ]
724
+ userType , ok := btf. As [ * btf. Struct ]( mapSpec . Value )
725
725
if ! ok {
726
- return fmt .Errorf ("struct_ops Map: %s is not initialized" , mapName )
726
+ return fmt .Errorf ("value should be a *Struct" )
727
727
}
728
728
729
- for idx , progName := range structOps .programName {
730
- if progName == "" {
731
- continue // unlikely to happen
732
- }
733
- // loadProgram is idempotent and could return an existing Program.
734
- prog , err := cl .loadProgram (progName )
735
- if err != nil {
736
- return fmt .Errorf ("loading program %s is not loaded, for map %s: %w" ,
737
- progName , mapName , err )
738
- }
739
- defer prog .Close ()
729
+ userData , ok := mapSpec .Contents [0 ].Value .([]byte )
730
+ if ! ok {
731
+ return fmt .Errorf ("value should be an array of byte" )
732
+ }
733
+
734
+ s , err := btf .LoadKernelSpec ()
735
+ if err != nil {
736
+ return fmt .Errorf ("load vmlinux BTF: %w" , err )
737
+ }
738
+
739
+ kernType , _ , _ , err := findStructByNameWithPrefix (s , userType )
740
+ if err != nil {
741
+ return fmt .Errorf ("find wrapper type: %w" , err )
742
+ }
743
+
744
+ kernVData , err := translateStructData (userType , userData , kernType )
745
+ if err != nil {
746
+ return err
747
+ }
740
748
741
- // populate ProgFDs as Values
742
- off := structOps .kernFuncOff [idx ]
743
- ptr := unsafe .Pointer (& structOps .kernVData [0 ])
744
- * (* uint64 )(unsafe .Pointer (uintptr (ptr ) + uintptr (off ))) = uint64 (prog .FD ())
749
+ if err := populateFuncPtr (kernType , kernVData , cl .programs ); err != nil {
750
+ return err
745
751
}
746
752
747
753
mapSpec .Contents [0 ] =
748
- MapKV {Key : uint32 (0 ), Value : structOps . kernVData }
754
+ MapKV {Key : uint32 (0 ), Value : kernVData }
749
755
}
750
756
751
757
// Populate and freeze the map if specified.
@@ -757,99 +763,100 @@ func (cl *collectionLoader) populateDeferredMaps() error {
757
763
return nil
758
764
}
759
765
760
- // copyDataMember copies one field from the user struct into the kernel buffer.
761
- // If the field is a function pointer, record attach metadata instead.
762
- func (cl * collectionLoader ) copyDataMember (
763
- idx int ,
764
- member btf.Member ,
765
- kern * structOpsKernTypes ,
766
- structOps * structOpsSpec ,
767
- structOpsMeta * structOpsMeta ,
768
- ms * MapSpec ,
769
- ) error {
770
- memberName := member .Name
771
- memberOff := member .Offset / 8
772
- memberData := structOpsMeta .data [memberOff :]
773
-
774
- memberSize , err := btf .Sizeof (member .Type )
775
- if err != nil {
776
- return fmt .Errorf ("failed to resolve the size of member %s: %w" , memberName , err )
777
- }
766
+ // translateStructData fills in all fields in `from` that exist in `to` with contents of fromData.
767
+ func translateStructData (from * btf.Struct , fromData []byte , to * btf.Struct ) ([]byte , error ) {
768
+ innerName := strings .TrimPrefix (to .Name , structOpsValuePrefix )
769
+ toData := make ([]byte , int (to .Size ))
778
770
779
- kernMember , err := getStructMemberByName (kern .typ , memberName )
780
- if err != nil {
781
- // allow missing kernel member if user data is zero
782
- if isMemoryZero (memberData [:memberSize ]) {
783
- return nil
784
- }
785
- return fmt .Errorf ("member %s not found in kernel BTF and data is not zero" , memberName )
786
- }
771
+ var inner * btf.Struct
772
+ var innerOff int
787
773
788
- kernMemberIdx := getStructMemberIndexOf (kern .typ , kernMember )
789
- if member .BitfieldSize > 0 || kernMember .BitfieldSize > 0 {
790
- return fmt .Errorf ("bitfield %s is not supported" , memberName )
774
+ for _ , m := range to .Members {
775
+ st , ok := btf.As [* btf.Struct ](btf .UnderlyingType (m .Type ))
776
+ fmt .Println (m .Name , st .Name )
777
+ if ok && st .Name == innerName {
778
+ inner = st
779
+ innerOff = int (m .Offset / 8 )
780
+ }
791
781
}
792
782
793
- kernMemberOff := kernMember .Offset / 8
794
- kernMemberData := structOps .kernVData [kernMemberOff :]
795
-
796
- // normalize user/kernel types (strip typedef/qualifiers, one level)
797
- memberType , err := skipModsAndTypedefs (kern .spec , member .Type )
798
- if err != nil {
799
- return fmt .Errorf ("user: failed to skip typedefs for %s: %w" , memberName , err )
783
+ if inner == nil {
784
+ return nil , fmt .Errorf ("member %s not found in %s" , innerName , to .Name )
800
785
}
801
786
802
- kernMemberType , err := skipModsAndTypedefs ( kern . spec , kernMember . Type )
803
- if err != nil {
804
- return fmt . Errorf ( "kern: failed to skip typedefs for %s: %w" , kernMember . Name , err )
787
+ kernIndexByName := make ( map [ string ]btf. Member , len ( inner . Members ) )
788
+ for _ , m := range inner . Members {
789
+ kernIndexByName [ m . Name ] = m
805
790
}
806
791
807
- // function-pointer member: map to program & record attach info
808
- if _ , ok := memberType .(* btf.Pointer ); ok {
809
- var fnName string
810
-
811
- for _ , fn := range structOpsMeta .funcs {
812
- if fn .member == memberName {
813
- fnName = fn .progName
814
- break
815
- }
792
+ for _ , m := range from .Members {
793
+ if m .BitfieldSize > 0 {
794
+ return nil , fmt .Errorf ("bitfield %s not supported" , m .Name )
795
+ }
816
796
797
+ kernMember , ok := kernIndexByName [m .Name ]
798
+ if ! ok {
799
+ continue
817
800
}
818
- if fnName == "" {
819
- // skip if the member is not specified in the MapSpec
820
- return nil
801
+
802
+ if kernMember . BitfieldSize > 0 {
803
+ return nil , fmt . Errorf ( "bitfield %s not supported in kern struct" , kernMember . Name )
821
804
}
822
805
823
- ps , ok := cl . coll . Programs [ fnName ]
824
- if ! ok {
825
- return fmt .Errorf ("Program %s is not found in CollectionSpec " , fnName )
806
+ sz , err := btf . Sizeof ( m . Type )
807
+ if err != nil {
808
+ return nil , fmt .Errorf ("failed to resolve size of %s: %w " , m . Name , err )
826
809
}
827
- if ps .Type != StructOps {
828
- return fmt .Errorf ("program %s is not a valid StructOps program" , fnName )
810
+
811
+ kernSz , err := btf .Sizeof (kernMember .Type )
812
+ if err != nil {
813
+ return nil , fmt .Errorf ("failed to resolve size of %s: %w" , kernMember .Name , err )
829
814
}
830
815
831
- attachType := sys .AttachType (kernMemberIdx )
832
- if int (attachType ) > len (kern .typ .Members ) {
833
- return fmt .Errorf ("program %s: unexpected attach type %d" , ps .Name , attachType )
816
+ if sz != kernSz {
817
+ return nil , fmt .Errorf ("size mismatch for %s: %d != %d" , m .Name , sz , kernSz )
834
818
}
835
819
836
- // where the kernel expects the prog FD to be written
837
- kernFuncOff := kern .dataMember .Offset / 8 + kern .typ .Members [kernMemberIdx ].Offset / 8
838
- structOps .kernFuncOff [idx ] = int (kernFuncOff )
839
- structOps .progAttachType [ps .Name ] = attachType
840
- cl .stOpsProgsToMap [ps .Name ] = ms .Name
820
+ src := int (m .Offset / 8 )
821
+ dst := innerOff + int (kernMember .Offset / 8 )
822
+ copy (toData [dst :dst + int (sz )], fromData [src :src + int (sz )])
823
+ }
824
+
825
+ return toData , nil
826
+ }
827
+
828
+ // 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 )
841
831
842
- // set `AttachTo` for struct_ops prog; e.g. "bpf_testmod_ops:test_1"
843
- ps .AttachTo = fmt .Sprintf ("%s:%s" , kern .typ .Name , memberName )
832
+ var inner * btf.Struct
833
+ var innerOff int
834
+
835
+ for _ , m := range wrapper .Members {
836
+ st , ok := btf.As [* btf.Struct ](btf .UnderlyingType (m .Type ))
837
+ if ok && st .Name == innerName {
838
+ inner = st
839
+ innerOff = int (m .Offset / 8 )
840
+ }
841
+ }
842
+
843
+ if inner == nil {
844
+ return fmt .Errorf ("member %s not found in %s" , innerName , wrapper .Name )
844
845
}
845
846
846
- // Handle data member. copy data members from the user-defined struct to the kernel data buffer.
847
- // It ensures that the sizes match between user and kernel types before copying the data.
848
- kernMemberSize , err := btf .Sizeof (kernMemberType )
849
- if err != nil || memberSize != kernMemberSize {
850
- return fmt .Errorf ("size mismatch for member %s: %d != %d (kernel)" , memberName , memberSize , kernMemberSize )
847
+ for _ , m := range inner .Members {
848
+ if _ , isPtr := btf.As [* btf.Pointer ](m .Type ); ! isPtr {
849
+ continue
850
+ }
851
+
852
+ p , ok := programs [m .Name ]
853
+ if ! ok || p == nil {
854
+ continue
855
+ }
856
+
857
+ off := innerOff + int (m .Offset / 8 )
858
+ binary .LittleEndian .PutUint64 (data [off :off + 8 ], uint64 (p .FD ()))
851
859
}
852
- copy (kernMemberData [:memberSize ], memberData [:memberSize ])
853
860
854
861
return nil
855
862
}
@@ -867,7 +874,7 @@ func (cl *collectionLoader) initKernStructOps() error {
867
874
return fmt .Errorf ("user struct type should be specified as Value" )
868
875
}
869
876
870
- userStructType , ok := ms . Value .( * btf.Struct )
877
+ userStructType , ok := btf. As [ * btf.Struct ]( ms . Value )
871
878
if ! ok {
872
879
return fmt .Errorf ("user struct type should be a Struct" )
873
880
}
@@ -888,28 +895,31 @@ func (cl *collectionLoader) initKernStructOps() error {
888
895
make (map [string ]sys.AttachType ),
889
896
kernTypes .typeID ,
890
897
}
898
+
891
899
cl .stOpsSpecs [ms .Name ] = structOps
900
+ cl .setStructOpsProgAttachTo (kernTypes .typ , ms .Name )
901
+ }
892
902
893
- structOpsMeta , err := extractStructOpsMeta (ms .Contents )
894
- if err != nil {
895
- return err
903
+ return nil
904
+ }
905
+
906
+ func (cl * collectionLoader ) setStructOpsProgAttachTo (kernType * btf.Struct , mapName string ) {
907
+ for _ , m := range kernType .Members {
908
+ if _ , ok := btf.As [* btf.Pointer ](btf .UnderlyingType (m .Type )); ! ok {
909
+ continue
896
910
}
897
911
898
- // populate kernel buffer & record attach info per member
899
- for idx , member := range kernTypes .typ .Members {
900
- if err := cl .copyDataMember (
901
- idx , member ,
902
- kernTypes ,
903
- structOps ,
904
- structOpsMeta ,
905
- ms ,
906
- ); err != nil {
907
- return err
908
- }
912
+ member := m .Name
913
+ ps , ok := cl .coll .Programs [member ]
914
+ if ! ok || ps == nil || ps .Type != StructOps {
915
+ continue
909
916
}
910
- }
911
917
912
- return nil
918
+ cl .stOpsProgsToMap [ps .Name ] = mapName
919
+ if ps .AttachTo == "" {
920
+ ps .AttachTo = fmt .Sprintf ("%s:%s" , kernType .Name , member )
921
+ }
922
+ }
913
923
}
914
924
915
925
// resolveKconfig resolves all variables declared in .kconfig and populates
0 commit comments