github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/operators/btfgen/btfgen.go (about) 1 // Copyright 2024 The Inspektor Gadget authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package btfgenoperator 16 17 import ( 18 "archive/tar" 19 "bytes" 20 "compress/gzip" 21 "fmt" 22 "io" 23 "sync" 24 25 "github.com/cilium/ebpf/btf" 26 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 27 28 "github.com/inspektor-gadget/inspektor-gadget/pkg/btfgen" 29 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-service/api" 30 "github.com/inspektor-gadget/inspektor-gadget/pkg/oci" 31 "github.com/inspektor-gadget/inspektor-gadget/pkg/operators" 32 ) 33 34 const ( 35 btfMediaType = "application/vnd.gadget.btfgen.v1+binary" 36 kernelTypesVar = "kernelTypes" 37 ) 38 39 var kernelHasBTF func() bool = sync.OnceValue(func() bool { 40 _, err := btf.LoadKernelSpec() 41 return err == nil 42 }) 43 44 type btfgenOperator struct{} 45 46 func (o *btfgenOperator) Name() string { 47 return "btfgen" 48 } 49 50 func (o *btfgenOperator) Description() string { 51 return "Enables to run gadget on kernels without BTF information by using BTF types generated with btfgen" 52 } 53 54 func (o *btfgenOperator) InstantiateImageOperator( 55 gadgetCtx operators.GadgetContext, desc ocispec.Descriptor, paramValues api.ParamValues, 56 ) (operators.ImageOperatorInstance, error) { 57 logger := gadgetCtx.Logger() 58 59 // If the kernel exposes BTF; nothing to do 60 if kernelHasBTF() { 61 logger.Debugf("kernel provides BTF, nothing to do on btfgen operator") 62 return nil, nil 63 } 64 65 return &btfgenOperatorInstance{ 66 desc: desc, 67 }, nil 68 } 69 70 type btfgenOperatorInstance struct { 71 desc ocispec.Descriptor 72 } 73 74 func (i *btfgenOperatorInstance) Name() string { 75 return "btfgenInstance" 76 } 77 78 func (i *btfgenOperatorInstance) Prepare(gadgetCtx operators.GadgetContext) error { 79 info, err := btfgen.GetOSInfo() 80 if err != nil { 81 return fmt.Errorf("getting OS info: %w", err) 82 } 83 84 r, err := oci.GetContentFromDescriptor(gadgetCtx.Context(), i.desc) 85 if err != nil { 86 return fmt.Errorf("getting ebpf binary: %w", err) 87 } 88 defer r.Close() 89 90 btfFileName := fmt.Sprintf("%s/%s/%s/%s.btf", info.ID, info.VersionID, info.Arch, info.Kernel) 91 btfBytes, err := getBTFFile(r, btfFileName) 92 if err != nil { 93 return fmt.Errorf("getting BTF file: %w", err) 94 } 95 96 btfSpec, err := btf.LoadSpecFromReader(bytes.NewReader(btfBytes)) 97 if err != nil { 98 return fmt.Errorf("loading BTF spec: %w", err) 99 } 100 101 // save the kernel types to be used by the ebpf operator when loading bpf the spec. 102 gadgetCtx.SetVar(kernelTypesVar, btfSpec) 103 104 return nil 105 } 106 107 func (i *btfgenOperatorInstance) Start(gadgetCtx operators.GadgetContext) error { 108 return nil 109 } 110 111 func (i *btfgenOperatorInstance) Stop(gadgetCtx operators.GadgetContext) error { 112 return nil 113 } 114 115 func getBTFFile(r io.Reader, filename string) ([]byte, error) { 116 gzr, err := gzip.NewReader(r) 117 if err != nil { 118 return nil, err 119 } 120 121 tr := tar.NewReader(gzr) 122 for { 123 hdr, err := tr.Next() 124 if err == io.EOF { 125 return nil, fmt.Errorf("BTF file %q not found", filename) 126 } 127 if err != nil { 128 return nil, fmt.Errorf("reading tar: %w", err) 129 } 130 131 if hdr.Name == filename { 132 b, err := io.ReadAll(tr) 133 if err != nil { 134 return nil, fmt.Errorf("reading BTF: %w", err) 135 } 136 137 return b, nil 138 } 139 } 140 } 141 142 func (i *btfgenOperatorInstance) ExtraParams(gadgetCtx operators.GadgetContext) api.Params { 143 return nil 144 } 145 146 func init() { 147 operators.RegisterOperatorForMediaType(btfMediaType, &btfgenOperator{}) 148 }