diff --git a/go.mod b/go.mod index 8e9b4ea1..a3dbbd9a 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.21.6 require ( github.com/cheggaaa/pb/v3 v3.1.5 - github.com/cilium/ebpf v0.15.0 + github.com/cilium/ebpf v0.16.0 github.com/cloudflare/cbpfc v0.0.0-20221017140110-11acb56438a2 github.com/jsimonetti/rtnetlink v1.4.2 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index df138098..d70f0f33 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,8 @@ github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAU github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk= github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI= github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= -github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= -github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= +github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= +github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= github.com/cloudflare/cbpfc v0.0.0-20221017140110-11acb56438a2 h1:tR13nc9+yx04rglzDJGQLoz3bTsh0os9tXpis6qwSVk= github.com/cloudflare/cbpfc v0.0.0-20221017140110-11acb56438a2/go.mod h1:KV9WSdjdUOxRC4RdsvoV1W5JTdMe7IjMgSUwcBrs860= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -20,6 +20,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90= github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM= +github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM= +github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/vendor/github.com/cilium/ebpf/.vimto.toml b/vendor/github.com/cilium/ebpf/.vimto.toml new file mode 100644 index 00000000..49a12dbc --- /dev/null +++ b/vendor/github.com/cilium/ebpf/.vimto.toml @@ -0,0 +1,12 @@ +kernel="ghcr.io/cilium/ci-kernels:stable" +smp="cpus=2" +memory="1G" +user="root" +setup=[ + "mount -t cgroup2 -o nosuid,noexec,nodev cgroup2 /sys/fs/cgroup", + "/bin/sh -c 'modprobe bpf_testmod || true'", + "dmesg --clear", +] +teardown=[ + "dmesg --read-clear", +] diff --git a/vendor/github.com/cilium/ebpf/CODEOWNERS b/vendor/github.com/cilium/ebpf/CODEOWNERS index ad13437e..ca65d23c 100644 --- a/vendor/github.com/cilium/ebpf/CODEOWNERS +++ b/vendor/github.com/cilium/ebpf/CODEOWNERS @@ -7,3 +7,5 @@ perf/ @florianl ringbuf/ @florianl btf/ @dylandreimerink + +cmd/bpf2go/ @mejedi diff --git a/vendor/github.com/cilium/ebpf/Makefile b/vendor/github.com/cilium/ebpf/Makefile index c55a93d9..d355eea7 100644 --- a/vendor/github.com/cilium/ebpf/Makefile +++ b/vendor/github.com/cilium/ebpf/Makefile @@ -106,7 +106,7 @@ testdata/loader-%-eb.elf: testdata/loader.c $(STRIP) -g $@ .PHONY: update-kernel-deps -update-kernel-deps: export KERNEL_VERSION?=6.7 +update-kernel-deps: export KERNEL_VERSION?=6.8 update-kernel-deps: ./testdata/sh/update-kernel-deps.sh $(MAKE) container-all diff --git a/vendor/github.com/cilium/ebpf/btf/btf.go b/vendor/github.com/cilium/ebpf/btf/btf.go index 204757db..671f680b 100644 --- a/vendor/github.com/cilium/ebpf/btf/btf.go +++ b/vendor/github.com/cilium/ebpf/btf/btf.go @@ -66,7 +66,7 @@ func (s *immutableTypes) typeByID(id TypeID) (Type, bool) { // mutableTypes is a set of types which may be changed. type mutableTypes struct { imm immutableTypes - mu *sync.RWMutex // protects copies below + mu sync.RWMutex // protects copies below copies map[Type]Type // map[orig]copy copiedTypeIDs map[Type]TypeID // map[copy]origID } @@ -94,10 +94,14 @@ func (mt *mutableTypes) add(typ Type, typeIDs map[Type]TypeID) Type { } // copy a set of mutable types. -func (mt *mutableTypes) copy() mutableTypes { - mtCopy := mutableTypes{ +func (mt *mutableTypes) copy() *mutableTypes { + if mt == nil { + return nil + } + + mtCopy := &mutableTypes{ mt.imm, - &sync.RWMutex{}, + sync.RWMutex{}, make(map[Type]Type, len(mt.copies)), make(map[Type]TypeID, len(mt.copiedTypeIDs)), } @@ -169,7 +173,7 @@ func (mt *mutableTypes) anyTypesByName(name string) ([]Type, error) { // Spec allows querying a set of Types and loading the set into the // kernel. type Spec struct { - mutableTypes + *mutableTypes // String table from ELF. strings *stringTable @@ -339,7 +343,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error typeIDs, typesByName := indexTypes(types, firstTypeID) return &Spec{ - mutableTypes{ + &mutableTypes{ immutableTypes{ types, typeIDs, @@ -347,7 +351,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error typesByName, bo, }, - &sync.RWMutex{}, + sync.RWMutex{}, make(map[Type]Type), make(map[Type]TypeID), }, @@ -522,6 +526,10 @@ func fixupDatasecLayout(ds *Datasec) error { // Copy creates a copy of Spec. func (s *Spec) Copy() *Spec { + if s == nil { + return nil + } + return &Spec{ s.mutableTypes.copy(), s.strings, diff --git a/vendor/github.com/cilium/ebpf/btf/handle.go b/vendor/github.com/cilium/ebpf/btf/handle.go index b6b3e87f..adfa6fed 100644 --- a/vendor/github.com/cilium/ebpf/btf/handle.go +++ b/vendor/github.com/cilium/ebpf/btf/handle.go @@ -41,6 +41,8 @@ func NewHandle(b *Builder) (*Handle, error) { // // Returns an error wrapping ErrNotSupported if the kernel doesn't support BTF. func NewHandleFromRawBTF(btf []byte) (*Handle, error) { + const minLogSize = 64 * 1024 + if uint64(len(btf)) > math.MaxUint32 { return nil, errors.New("BTF exceeds the maximum size") } @@ -50,26 +52,54 @@ func NewHandleFromRawBTF(btf []byte) (*Handle, error) { BtfSize: uint32(len(btf)), } - fd, err := sys.BtfLoad(attr) - if err == nil { - return &Handle{fd, attr.BtfSize, false}, nil + var ( + logBuf []byte + err error + ) + for { + var fd *sys.FD + fd, err = sys.BtfLoad(attr) + if err == nil { + return &Handle{fd, attr.BtfSize, false}, nil + } + + if attr.BtfLogTrueSize != 0 && attr.BtfLogSize >= attr.BtfLogTrueSize { + // The log buffer already has the correct size. + break + } + + if attr.BtfLogSize != 0 && !errors.Is(err, unix.ENOSPC) { + // Up until at least kernel 6.0, the BTF verifier does not return ENOSPC + // if there are other verification errors. ENOSPC is only returned when + // the BTF blob is correct, a log was requested, and the provided buffer + // is too small. We're therefore not sure whether we got the full + // log or not. + break + } + + // Make an educated guess how large the buffer should be. Start + // at a reasonable minimum and then double the size. + logSize := uint32(max(len(logBuf)*2, minLogSize)) + if int(logSize) < len(logBuf) { + return nil, errors.New("overflow while probing log buffer size") + } + + if attr.BtfLogTrueSize != 0 { + // The kernel has given us a hint how large the log buffer has to be. + logSize = attr.BtfLogTrueSize + } + + logBuf = make([]byte, logSize) + attr.BtfLogSize = logSize + attr.BtfLogBuf = sys.NewSlicePointer(logBuf) + attr.BtfLogLevel = 1 } if err := haveBTF(); err != nil { return nil, err } - logBuf := make([]byte, 64*1024) - attr.BtfLogBuf = sys.NewSlicePointer(logBuf) - attr.BtfLogSize = uint32(len(logBuf)) - attr.BtfLogLevel = 1 - - // Up until at least kernel 6.0, the BTF verifier does not return ENOSPC - // if there are other verification errors. ENOSPC is only returned when - // the BTF blob is correct, a log was requested, and the provided buffer - // is too small. - _, ve := sys.BtfLoad(attr) - return nil, internal.ErrorWithLog("load btf", err, logBuf, errors.Is(ve, unix.ENOSPC)) + return nil, internal.ErrorWithLog("load btf", err, logBuf) } // NewHandleFromID returns the BTF handle for a given id. diff --git a/vendor/github.com/cilium/ebpf/btf/types.go b/vendor/github.com/cilium/ebpf/btf/types.go index 3cb9184f..a3397460 100644 --- a/vendor/github.com/cilium/ebpf/btf/types.go +++ b/vendor/github.com/cilium/ebpf/btf/types.go @@ -682,6 +682,10 @@ func Copy(typ Type) Type { } func copyType(typ Type, ids map[Type]TypeID, copies map[Type]Type, copiedIDs map[Type]TypeID) Type { + if typ == nil { + return nil + } + cpy, ok := copies[typ] if ok { // This has been copied previously, no need to continue. diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/compile.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/compile.go deleted file mode 100644 index 2aa08f92..00000000 --- a/vendor/github.com/cilium/ebpf/cmd/bpf2go/compile.go +++ /dev/null @@ -1,210 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "strings" -) - -type compileArgs struct { - // Which compiler to use - cc string - cFlags []string - // Absolute working directory - dir string - // Absolute input file name - source string - // Absolute output file name - dest string - // Target to compile for, defaults to "bpf". - target string - // Depfile will be written here if depName is not empty - dep io.Writer -} - -func compile(args compileArgs) error { - // Default cflags that can be overridden by args.cFlags - overrideFlags := []string{ - // Code needs to be optimized, otherwise the verifier will often fail - // to understand it. - "-O2", - // Clang defaults to mcpu=probe which checks the kernel that we are - // compiling on. This isn't appropriate for ahead of time - // compiled code so force the most compatible version. - "-mcpu=v1", - } - - cmd := exec.Command(args.cc, append(overrideFlags, args.cFlags...)...) - cmd.Stderr = os.Stderr - - inputDir := filepath.Dir(args.source) - relInputDir, err := filepath.Rel(args.dir, inputDir) - if err != nil { - return err - } - - target := args.target - if target == "" { - target = "bpf" - } - - // C flags that can't be overridden. - cmd.Args = append(cmd.Args, - "-target", target, - "-c", args.source, - "-o", args.dest, - // Don't include clang version - "-fno-ident", - // Don't output inputDir into debug info - "-fdebug-prefix-map="+inputDir+"="+relInputDir, - "-fdebug-compilation-dir", ".", - // We always want BTF to be generated, so enforce debug symbols - "-g", - fmt.Sprintf("-D__BPF_TARGET_MISSING=%q", "GCC error \"The eBPF is using target specific macros, please provide -target that is not bpf, bpfel or bpfeb\""), - ) - cmd.Dir = args.dir - - var depFile *os.File - if args.dep != nil { - depFile, err = os.CreateTemp("", "bpf2go") - if err != nil { - return err - } - defer depFile.Close() - defer os.Remove(depFile.Name()) - - cmd.Args = append(cmd.Args, - // Output dependency information. - "-MD", - // Create phony targets so that deleting a dependency doesn't - // break the build. - "-MP", - // Write it to temporary file - "-MF"+depFile.Name(), - ) - } - - if err := cmd.Run(); err != nil { - return fmt.Errorf("can't execute %s: %s", args.cc, err) - } - - if depFile != nil { - if _, err := io.Copy(args.dep, depFile); err != nil { - return fmt.Errorf("error writing depfile: %w", err) - } - } - - return nil -} - -func adjustDependencies(baseDir string, deps []dependency) ([]byte, error) { - var buf bytes.Buffer - for _, dep := range deps { - relativeFile, err := filepath.Rel(baseDir, dep.file) - if err != nil { - return nil, err - } - - if len(dep.prerequisites) == 0 { - _, err := fmt.Fprintf(&buf, "%s:\n\n", relativeFile) - if err != nil { - return nil, err - } - continue - } - - var prereqs []string - for _, prereq := range dep.prerequisites { - relativePrereq, err := filepath.Rel(baseDir, prereq) - if err != nil { - return nil, err - } - - prereqs = append(prereqs, relativePrereq) - } - - _, err = fmt.Fprintf(&buf, "%s: \\\n %s\n\n", relativeFile, strings.Join(prereqs, " \\\n ")) - if err != nil { - return nil, err - } - } - return buf.Bytes(), nil -} - -type dependency struct { - file string - prerequisites []string -} - -func parseDependencies(baseDir string, in io.Reader) ([]dependency, error) { - abs := func(path string) string { - if filepath.IsAbs(path) { - return path - } - return filepath.Join(baseDir, path) - } - - scanner := bufio.NewScanner(in) - var line strings.Builder - var deps []dependency - for scanner.Scan() { - buf := scanner.Bytes() - if line.Len()+len(buf) > 1024*1024 { - return nil, errors.New("line too long") - } - - if bytes.HasSuffix(buf, []byte{'\\'}) { - line.Write(buf[:len(buf)-1]) - continue - } - - line.Write(buf) - if line.Len() == 0 { - // Skip empty lines - continue - } - - parts := strings.SplitN(line.String(), ":", 2) - if len(parts) < 2 { - return nil, fmt.Errorf("invalid line without ':'") - } - - // NB: This doesn't handle filenames with spaces in them. - // It seems like make doesn't do that either, so oh well. - var prereqs []string - for _, prereq := range strings.Fields(parts[1]) { - prereqs = append(prereqs, abs(prereq)) - } - - deps = append(deps, dependency{ - abs(string(parts[0])), - prereqs, - }) - line.Reset() - } - if err := scanner.Err(); err != nil { - return nil, err - } - - // There is always at least a dependency for the main file. - if len(deps) == 0 { - return nil, fmt.Errorf("empty dependency file") - } - return deps, nil -} - -// strip DWARF debug info from file by executing exe. -func strip(exe, file string) error { - cmd := exec.Command(exe, "-g", file) - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return fmt.Errorf("%s: %s", exe, err) - } - return nil -} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/flags.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/flags.go index ca8852a2..806d2cd2 100644 --- a/vendor/github.com/cilium/ebpf/cmd/bpf2go/flags.go +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/flags.go @@ -43,15 +43,3 @@ func andConstraints(x, y constraint.Expr) constraint.Expr { return &constraint.AndExpr{X: x, Y: y} } - -func orConstraints(x, y constraint.Expr) constraint.Expr { - if x == nil { - return y - } - - if y == nil { - return x - } - - return &constraint.OrExpr{X: x, Y: y} -} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/compile.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/compile.go new file mode 100644 index 00000000..09d57da8 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/compile.go @@ -0,0 +1,91 @@ +package gen + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" +) + +type CompileArgs struct { + // Which compiler to use. + CC string + // Command used to strip DWARF from the ELF. + Strip string + // Flags to pass to the compiler. + Flags []string + // Absolute working directory + Workdir string + // Absolute input file name + Source string + // Absolute output file name + Dest string + // Target to compile for, defaults to compiling generic BPF in host endianness. + Target Target + DisableStripping bool +} + +// Compile C to a BPF ELF file. +func Compile(args CompileArgs) error { + // Default cflags that can be overridden by args.cFlags + overrideFlags := []string{ + // Code needs to be optimized, otherwise the verifier will often fail + // to understand it. + "-O2", + // Clang defaults to mcpu=probe which checks the kernel that we are + // compiling on. This isn't appropriate for ahead of time + // compiled code so force the most compatible version. + "-mcpu=v1", + } + + cmd := exec.Command(args.CC, append(overrideFlags, args.Flags...)...) + cmd.Stderr = os.Stderr + + inputDir := filepath.Dir(args.Source) + relInputDir, err := filepath.Rel(args.Workdir, inputDir) + if err != nil { + return err + } + + target := args.Target + if target == (Target{}) { + target.clang = "bpf" + } + + // C flags that can't be overridden. + if linux := target.linux; linux != "" { + cmd.Args = append(cmd.Args, "-D__TARGET_ARCH_"+linux) + } + + cmd.Args = append(cmd.Args, + "-Wunused-command-line-argument", + "-target", target.clang, + "-c", args.Source, + "-o", args.Dest, + // Don't include clang version + "-fno-ident", + // Don't output inputDir into debug info + "-fdebug-prefix-map="+inputDir+"="+relInputDir, + "-fdebug-compilation-dir", ".", + // We always want BTF to be generated, so enforce debug symbols + "-g", + fmt.Sprintf("-D__BPF_TARGET_MISSING=%q", "GCC error \"The eBPF is using target specific macros, please provide -target that is not bpf, bpfel or bpfeb\""), + ) + cmd.Dir = args.Workdir + + if err := cmd.Run(); err != nil { + return err + } + + if args.DisableStripping { + return nil + } + + cmd = exec.Command(args.Strip, "-g", args.Dest) + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("strip %s: %w", args.Dest, err) + } + + return nil +} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/doc.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/doc.go new file mode 100644 index 00000000..1f3080f6 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/doc.go @@ -0,0 +1,2 @@ +// Package gen contains utilities to generate Go bindings for eBPF ELF files. +package gen diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/output.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/output.go similarity index 59% rename from vendor/github.com/cilium/ebpf/cmd/bpf2go/output.go rename to vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/output.go index 51f19707..a054fd2f 100644 --- a/vendor/github.com/cilium/ebpf/cmd/bpf2go/output.go +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/output.go @@ -1,4 +1,4 @@ -package main +package gen import ( "bytes" @@ -10,9 +10,11 @@ import ( "sort" "strings" "text/template" + "unicode" + "unicode/utf8" - "github.com/cilium/ebpf" "github.com/cilium/ebpf/btf" + b2gInt "github.com/cilium/ebpf/cmd/bpf2go/internal" "github.com/cilium/ebpf/internal" ) @@ -71,38 +73,58 @@ func (n templateName) CloseHelper() string { return "_" + toUpperFirst(string(n)) + "Close" } -type outputArgs struct { +type GenerateArgs struct { // Package of the resulting file. - pkg string + Package string // The prefix of all names declared at the top-level. - stem string - // Build constraints included in the resulting file. - constraints constraint.Expr + Stem string + // Build Constraints included in the resulting file. + Constraints constraint.Expr // Maps to be emitted. - maps []string + Maps []string // Programs to be emitted. - programs []string + Programs []string // Types to be emitted. - types []btf.Type - // Filename of the ELF object to embed. - obj string - out io.Writer + Types []btf.Type + // Filename of the object to embed. + ObjectFile string + // Output to write template to. + Output io.Writer } -func output(args outputArgs) error { +// Generate bindings for a BPF ELF file. +func Generate(args GenerateArgs) error { + if !token.IsIdentifier(args.Stem) { + return fmt.Errorf("%q is not a valid identifier", args.Stem) + } + + if strings.ContainsAny(args.ObjectFile, "\n") { + // Prevent injecting newlines into the template. + return fmt.Errorf("file %q contains an invalid character", args.ObjectFile) + } + + for _, typ := range args.Types { + if _, ok := btf.As[*btf.Datasec](typ); ok { + // Avoid emitting .rodata, .bss, etc. for now. We might want to + // name these types differently, etc. + return fmt.Errorf("can't output btf.Datasec: %s", typ) + } + } + maps := make(map[string]string) - for _, name := range args.maps { + for _, name := range args.Maps { maps[name] = internal.Identifier(name) } programs := make(map[string]string) - for _, name := range args.programs { + for _, name := range args.Programs { programs[name] = internal.Identifier(name) } typeNames := make(map[btf.Type]string) - for _, typ := range args.types { - typeNames[typ] = args.stem + internal.Identifier(typ.TypeName()) + for _, typ := range args.Types { + // NB: This also deduplicates types. + typeNames[typ] = args.Stem + internal.Identifier(typ.TypeName()) } // Ensure we don't have conflicting names and generate a sorted list of @@ -112,8 +134,6 @@ func output(args outputArgs) error { return err } - module := currentModule() - gf := &btf.GoFormatter{ Names: typeNames, Identifier: internal.Identifier, @@ -132,15 +152,15 @@ func output(args outputArgs) error { File string }{ gf, - module, - args.pkg, - args.constraints, - templateName(args.stem), + b2gInt.CurrentModule, + args.Package, + args.Constraints, + templateName(args.Stem), maps, programs, types, typeNames, - args.obj, + args.ObjectFile, } var buf bytes.Buffer @@ -148,74 +168,7 @@ func output(args outputArgs) error { return fmt.Errorf("can't generate types: %s", err) } - return internal.WriteFormatted(buf.Bytes(), args.out) -} - -func collectFromSpec(spec *ebpf.CollectionSpec, cTypes []string, skipGlobalTypes bool) (maps, programs []string, types []btf.Type, _ error) { - for name := range spec.Maps { - // Skip .rodata, .data, .bss, etc. sections - if !strings.HasPrefix(name, ".") { - maps = append(maps, name) - } - } - - for name := range spec.Programs { - programs = append(programs, name) - } - - types, err := collectCTypes(spec.Types, cTypes) - if err != nil { - return nil, nil, nil, fmt.Errorf("collect C types: %w", err) - } - - // Collect map key and value types, unless we've been asked not to. - if skipGlobalTypes { - return maps, programs, types, nil - } - - for _, typ := range collectMapTypes(spec.Maps) { - switch btf.UnderlyingType(typ).(type) { - case *btf.Datasec: - // Avoid emitting .rodata, .bss, etc. for now. We might want to - // name these types differently, etc. - continue - - case *btf.Int: - // Don't emit primitive types by default. - continue - } - - types = append(types, typ) - } - - return maps, programs, types, nil -} - -func collectCTypes(types *btf.Spec, names []string) ([]btf.Type, error) { - var result []btf.Type - for _, cType := range names { - typ, err := types.AnyTypeByName(cType) - if err != nil { - return nil, err - } - result = append(result, typ) - } - return result, nil -} - -// collectMapTypes returns a list of all types used as map keys or values. -func collectMapTypes(maps map[string]*ebpf.MapSpec) []btf.Type { - var result []btf.Type - for _, m := range maps { - if m.Key != nil && m.Key.TypeName() != "" { - result = append(result, m.Key) - } - - if m.Value != nil && m.Value.TypeName() != "" { - result = append(result, m.Value) - } - } - return result + return internal.WriteFormatted(buf.Bytes(), args.Output) } // sortTypes returns a list of types sorted by their (generated) Go type name. @@ -242,3 +195,8 @@ func sortTypes(typeNames map[btf.Type]string) ([]btf.Type, error) { return types, nil } + +func toUpperFirst(str string) string { + first, n := utf8.DecodeRuneInString(str) + return string(unicode.ToUpper(first)) + str[n:] +} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/output.tpl b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/output.tpl similarity index 100% rename from vendor/github.com/cilium/ebpf/cmd/bpf2go/output.tpl rename to vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/output.tpl diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/target.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/target.go new file mode 100644 index 00000000..f5484ccc --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/target.go @@ -0,0 +1,155 @@ +package gen + +import ( + "errors" + "fmt" + "go/build/constraint" + "maps" + "runtime" + "slices" +) + +var ErrInvalidTarget = errors.New("unsupported target") + +var targetsByGoArch = map[GoArch]Target{ + "386": {"bpfel", "x86"}, + "amd64": {"bpfel", "x86"}, + "arm": {"bpfel", "arm"}, + "arm64": {"bpfel", "arm64"}, + "loong64": {"bpfel", "loongarch"}, + "mips": {"bpfeb", "mips"}, + "mipsle": {"bpfel", ""}, + "mips64": {"bpfeb", ""}, + "mips64le": {"bpfel", ""}, + "ppc64": {"bpfeb", "powerpc"}, + "ppc64le": {"bpfel", "powerpc"}, + "riscv64": {"bpfel", "riscv"}, + "s390x": {"bpfeb", "s390"}, +} + +type Target struct { + // Clang arch string, used to define the clang -target flag, as per + // "clang -print-targets". + clang string + // Linux arch string, used to define __TARGET_ARCH_xzy macros used by + // https://github.com/libbpf/libbpf/blob/master/src/bpf_tracing.h + linux string +} + +// TargetsByGoArch returns all supported targets. +func TargetsByGoArch() map[GoArch]Target { + return maps.Clone(targetsByGoArch) +} + +// IsGeneric returns true if the target will compile to generic BPF. +func (tgt *Target) IsGeneric() bool { + return tgt.linux == "" +} + +// Suffix returns a a string suitable for appending to a file name to +// identify the target. +func (tgt *Target) Suffix() string { + // The output filename must not match any of the following patterns: + // + // *_GOOS + // *_GOARCH + // *_GOOS_GOARCH + // + // Otherwise it is interpreted as a build constraint by the Go toolchain. + stem := tgt.clang + if tgt.linux != "" { + stem = fmt.Sprintf("%s_%s", tgt.linux, tgt.clang) + } + return stem +} + +// ObsoleteSuffix returns an obsolete suffix for a subset of targets. +// +// It's used to work around an old bug and should not be used in new code. +func (tgt *Target) ObsoleteSuffix() string { + if tgt.linux == "" { + return "" + } + + return fmt.Sprintf("%s_%s", tgt.clang, tgt.linux) +} + +// GoArch is a Go arch string. +// +// See https://go.dev/doc/install/source#environment for valid GOARCHes when +// GOOS=linux. +type GoArch string + +type GoArches []GoArch + +// Constraints is satisfied when GOARCH is any of the arches. +func (arches GoArches) Constraint() constraint.Expr { + var archConstraint constraint.Expr + for _, goarch := range arches { + tag := &constraint.TagExpr{Tag: string(goarch)} + archConstraint = orConstraints(archConstraint, tag) + } + return archConstraint +} + +// FindTarget turns a list of identifiers into targets and their respective +// GoArches. +// +// The following are valid identifiers: +// +// - bpf: compile generic BPF for host endianness +// - bpfel: compile generic BPF for little endian +// - bpfeb: compile generic BPF for big endian +// - native: compile BPF for host target +// - $GOARCH: compile BPF for $GOARCH target +// +// Generic BPF can run on any target goarch with the correct endianness, +// but doesn't have access to some arch specific tracing functionality. +func FindTarget(id string) (Target, GoArches, error) { + switch id { + case "bpf", "bpfel", "bpfeb": + var goarches []GoArch + for arch, archTarget := range targetsByGoArch { + if archTarget.clang == id { + // Include tags for all goarches that have the same endianness. + goarches = append(goarches, arch) + } + } + slices.Sort(goarches) + return Target{id, ""}, goarches, nil + + case "native": + id = runtime.GOARCH + fallthrough + + default: + archTarget, ok := targetsByGoArch[GoArch(id)] + if !ok || archTarget.linux == "" { + return Target{}, nil, fmt.Errorf("%q: %w", id, ErrInvalidTarget) + } + + var goarches []GoArch + for goarch, lt := range targetsByGoArch { + if lt == archTarget { + // Include tags for all goarches that have the same + // target. + goarches = append(goarches, goarch) + } + } + + slices.Sort(goarches) + return archTarget, goarches, nil + } +} + +func orConstraints(x, y constraint.Expr) constraint.Expr { + if x == nil { + return y + } + + if y == nil { + return x + } + + return &constraint.OrExpr{X: x, Y: y} +} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/types.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/types.go new file mode 100644 index 00000000..37dad0c7 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/gen/types.go @@ -0,0 +1,44 @@ +package gen + +import ( + "github.com/cilium/ebpf" + "github.com/cilium/ebpf/btf" +) + +// CollectGlobalTypes finds all types which are used in the global scope. +// +// This currently includes the types of map keys and values. +func CollectGlobalTypes(spec *ebpf.CollectionSpec) []btf.Type { + var types []btf.Type + for _, typ := range collectMapTypes(spec.Maps) { + switch btf.UnderlyingType(typ).(type) { + case *btf.Datasec: + // Avoid emitting .rodata, .bss, etc. for now. We might want to + // name these types differently, etc. + continue + + case *btf.Int: + // Don't emit primitive types by default. + continue + } + + types = append(types, typ) + } + + return types +} + +// collectMapTypes returns a list of all types used as map keys or values. +func collectMapTypes(maps map[string]*ebpf.MapSpec) []btf.Type { + var result []btf.Type + for _, m := range maps { + if m.Key != nil && m.Key.TypeName() != "" { + result = append(result, m.Key) + } + + if m.Value != nil && m.Value.TypeName() != "" { + result = append(result, m.Value) + } + } + return result +} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/internal/module.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/internal/module.go new file mode 100644 index 00000000..43f7f6d4 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/internal/module.go @@ -0,0 +1,9 @@ +package internal + +// We used to have some clever code here which relied on debug.ReadBuildInfo(). +// This is broken due to https://github.com/golang/go/issues/33976, and some build +// systems like bazel also do not generate the necessary data. Let's keep it +// simple instead. + +// The module containing the code in this repository. +const CurrentModule = "github.com/cilium/ebpf" diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/main.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/main.go index 6064d44f..fb077e13 100644 --- a/vendor/github.com/cilium/ebpf/cmd/bpf2go/main.go +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/main.go @@ -1,23 +1,21 @@ package main import ( - "bytes" "errors" "flag" "fmt" - "go/build/constraint" - "go/token" "io" "os" "os/exec" "path/filepath" "regexp" - "runtime" "slices" "sort" "strings" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/btf" + "github.com/cilium/ebpf/cmd/bpf2go/gen" ) const helpText = `Usage: %[1]s [options] [-- ] @@ -44,29 +42,6 @@ Options: ` -// Targets understood by bpf2go. -// -// Targets without a Linux string can't be used directly and are only included -// for the generic bpf, bpfel, bpfeb targets. -// -// See https://go.dev/doc/install/source#environment for valid GOARCHes when -// GOOS=linux. -var targetByGoArch = map[goarch]target{ - "386": {"bpfel", "x86"}, - "amd64": {"bpfel", "x86"}, - "arm": {"bpfel", "arm"}, - "arm64": {"bpfel", "arm64"}, - "loong64": {"bpfel", "loongarch"}, - "mips": {"bpfeb", "mips"}, - "mipsle": {"bpfel", ""}, - "mips64": {"bpfeb", ""}, - "mips64le": {"bpfel", ""}, - "ppc64": {"bpfeb", "powerpc"}, - "ppc64le": {"bpfel", "powerpc"}, - "riscv64": {"bpfel", "riscv"}, - "s390x": {"bpfeb", "s390"}, -} - func run(stdout io.Writer, args []string) (err error) { b2g, err := newB2G(stdout, args) switch { @@ -92,7 +67,7 @@ type bpf2go struct { // Valid go identifier. identStem string // Targets to build for. - targetArches map[target][]goarch + targetArches map[gen.Target]gen.GoArches // C compiler. cc string // Command used to strip DWARF. @@ -190,9 +165,6 @@ func newB2G(stdout io.Writer, args []string) (*bpf2go, error) { } b2g.identStem = args[0] - if !token.IsIdentifier(b2g.identStem) { - return nil, fmt.Errorf("%q is not a valid identifier", b2g.identStem) - } sourceFile, err := filepath.Abs(args[1]) if err != nil { @@ -211,14 +183,18 @@ func newB2G(stdout io.Writer, args []string) (*bpf2go, error) { return nil, fmt.Errorf("-output-stem %q must not contain path separation characters", b2g.outputStem) } - targetArches, err := collectTargets(strings.Split(*flagTarget, ",")) - if errors.Is(err, errInvalidTarget) { - printTargets(b2g.stdout) - fmt.Fprintln(b2g.stdout) - return nil, err - } - if err != nil { - return nil, err + targetArches := make(map[gen.Target]gen.GoArches) + for _, tgt := range strings.Split(*flagTarget, ",") { + target, goarches, err := gen.FindTarget(tgt) + if err != nil { + if errors.Is(err, gen.ErrInvalidTarget) { + printTargets(b2g.stdout) + fmt.Fprintln(b2g.stdout) + } + return nil, err + } + + targetArches[target] = goarches } if len(targetArches) == 0 { @@ -306,7 +282,7 @@ func (b2g *bpf2go) convertAll() (err error) { return nil } -func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { +func (b2g *bpf2go) convert(tgt gen.Target, goarches gen.GoArches) (err error) { removeOnError := func(f *os.File) { if err != nil { os.Remove(f.Name()) @@ -319,17 +295,7 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { outputStem = strings.ToLower(b2g.identStem) } - // The output filename must not match any of the following patterns: - // - // *_GOOS - // *_GOARCH - // *_GOOS_GOARCH - // - // Otherwise it is interpreted as a build constraint by the Go toolchain. - stem := fmt.Sprintf("%s_%s", outputStem, tgt.clang) - if tgt.linux != "" { - stem = fmt.Sprintf("%s_%s_%s", outputStem, tgt.linux, tgt.clang) - } + stem := fmt.Sprintf("%s_%s", outputStem, tgt.Suffix()) absOutPath, err := filepath.Abs(b2g.outputDir) if err != nil { @@ -343,44 +309,51 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { return err } - var archConstraint constraint.Expr - for _, goarch := range goarches { - tag := &constraint.TagExpr{Tag: string(goarch)} - archConstraint = orConstraints(archConstraint, tag) - } - + archConstraint := goarches.Constraint() constraints := andConstraints(archConstraint, b2g.tags.Expr) - cFlags := make([]string, len(b2g.cFlags)) - copy(cFlags, b2g.cFlags) - if tgt.linux != "" { - cFlags = append(cFlags, "-D__TARGET_ARCH_"+tgt.linux) - } - if err := b2g.removeOldOutputFiles(outputStem, tgt); err != nil { return fmt.Errorf("remove obsolete output: %w", err) } - var dep bytes.Buffer - err = compile(compileArgs{ - cc: b2g.cc, - cFlags: cFlags, - target: tgt.clang, - dir: cwd, - source: b2g.sourceFile, - dest: objFileName, - dep: &dep, + var depInput *os.File + cFlags := slices.Clone(b2g.cFlags) + if b2g.makeBase != "" { + depInput, err = os.CreateTemp("", "bpf2go") + if err != nil { + return err + } + defer depInput.Close() + defer os.Remove(depInput.Name()) + + cFlags = append(cFlags, + // Output dependency information. + "-MD", + // Create phony targets so that deleting a dependency doesn't + // break the build. + "-MP", + // Write it to temporary file + "-MF"+depInput.Name(), + ) + } + + err = gen.Compile(gen.CompileArgs{ + CC: b2g.cc, + Strip: b2g.strip, + DisableStripping: b2g.disableStripping, + Flags: cFlags, + Target: tgt, + Workdir: cwd, + Source: b2g.sourceFile, + Dest: objFileName, }) if err != nil { - return err + return fmt.Errorf("compile: %w", err) } fmt.Fprintln(b2g.stdout, "Compiled", objFileName) if !b2g.disableStripping { - if err := strip(b2g.strip, objFileName); err != nil { - return err - } fmt.Fprintln(b2g.stdout, "Stripped", objFileName) } @@ -389,9 +362,26 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { return fmt.Errorf("can't load BPF from ELF: %s", err) } - maps, programs, types, err := collectFromSpec(spec, b2g.cTypes, b2g.skipGlobalTypes) + var maps []string + for name := range spec.Maps { + // Skip .rodata, .data, .bss, etc. sections + if !strings.HasPrefix(name, ".") { + maps = append(maps, name) + } + } + + var programs []string + for name := range spec.Programs { + programs = append(programs, name) + } + + types, err := collectCTypes(spec.Types, b2g.cTypes) if err != nil { - return err + return fmt.Errorf("collect C types: %w", err) + } + + if !b2g.skipGlobalTypes { + types = append(types, gen.CollectGlobalTypes(spec)...) } // Write out generated go @@ -402,15 +392,15 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { } defer removeOnError(goFile) - err = output(outputArgs{ - pkg: b2g.pkg, - stem: b2g.identStem, - constraints: constraints, - maps: maps, - programs: programs, - types: types, - obj: filepath.Base(objFileName), - out: goFile, + err = gen.Generate(gen.GenerateArgs{ + Package: b2g.pkg, + Stem: b2g.identStem, + Constraints: constraints, + Maps: maps, + Programs: programs, + Types: types, + ObjectFile: filepath.Base(objFileName), + Output: goFile, }) if err != nil { return fmt.Errorf("can't write %s: %s", goFileName, err) @@ -422,21 +412,22 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { return } - deps, err := parseDependencies(cwd, &dep) + deps, err := parseDependencies(cwd, depInput) if err != nil { return fmt.Errorf("can't read dependency information: %s", err) } - // There is always at least a dependency for the main file. - deps[0].file = goFileName - depFile, err := adjustDependencies(b2g.makeBase, deps) + depFileName := goFileName + ".d" + depOutput, err := os.Create(depFileName) if err != nil { - return fmt.Errorf("can't adjust dependency information: %s", err) + return fmt.Errorf("write make dependencies: %w", err) } + defer depOutput.Close() - depFileName := goFileName + ".d" - if err := os.WriteFile(depFileName, depFile, 0666); err != nil { - return fmt.Errorf("can't write dependency file: %s", err) + // There is always at least a dependency for the main file. + deps[0].file = goFileName + if err := adjustDependencies(depOutput, b2g.makeBase, deps); err != nil { + return fmt.Errorf("can't adjust dependency information: %s", err) } fmt.Fprintln(b2g.stdout, "Wrote", depFileName) @@ -447,12 +438,13 @@ func (b2g *bpf2go) convert(tgt target, goarches []goarch) (err error) { // // In the old scheme some linux targets were interpreted as build constraints // by the go toolchain. -func (b2g *bpf2go) removeOldOutputFiles(outputStem string, tgt target) error { - if tgt.linux == "" { +func (b2g *bpf2go) removeOldOutputFiles(outputStem string, tgt gen.Target) error { + suffix := tgt.ObsoleteSuffix() + if suffix == "" { return nil } - stem := fmt.Sprintf("%s_%s_%s", outputStem, tgt.clang, tgt.linux) + stem := fmt.Sprintf("%s_%s", outputStem, suffix) for _, ext := range []string{".o", ".go"} { filename := filepath.Join(b2g.outputDir, stem+ext) @@ -468,21 +460,10 @@ func (b2g *bpf2go) removeOldOutputFiles(outputStem string, tgt target) error { return nil } -type target struct { - // Clang arch string, used to define the clang -target flag, as per - // "clang -print-targets". - clang string - // Linux arch string, used to define __TARGET_ARCH_xzy macros used by - // https://github.com/libbpf/libbpf/blob/master/src/bpf_tracing.h - linux string -} - -type goarch string - func printTargets(w io.Writer) { var arches []string - for goarch, archTarget := range targetByGoArch { - if archTarget.linux == "" { + for goarch, archTarget := range gen.TargetsByGoArch() { + if archTarget.IsGeneric() { continue } arches = append(arches, string(goarch)) @@ -496,47 +477,15 @@ func printTargets(w io.Writer) { } } -var errInvalidTarget = errors.New("unsupported target") - -func collectTargets(targets []string) (map[target][]goarch, error) { - result := make(map[target][]goarch) - for _, tgt := range targets { - switch tgt { - case "bpf", "bpfel", "bpfeb": - var goarches []goarch - for arch, archTarget := range targetByGoArch { - if archTarget.clang == tgt { - // Include tags for all goarches that have the same endianness. - goarches = append(goarches, arch) - } - } - slices.Sort(goarches) - result[target{tgt, ""}] = goarches - - case "native": - tgt = runtime.GOARCH - fallthrough - - default: - archTarget, ok := targetByGoArch[goarch(tgt)] - if !ok || archTarget.linux == "" { - return nil, fmt.Errorf("%q: %w", tgt, errInvalidTarget) - } - - var goarches []goarch - for goarch, lt := range targetByGoArch { - if lt == archTarget { - // Include tags for all goarches that have the same - // target. - goarches = append(goarches, goarch) - } - } - - slices.Sort(goarches) - result[archTarget] = goarches +func collectCTypes(types *btf.Spec, names []string) ([]btf.Type, error) { + var result []btf.Type + for _, cType := range names { + typ, err := types.AnyTypeByName(cType) + if err != nil { + return nil, err } + result = append(result, typ) } - return result, nil } diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/makedep.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/makedep.go new file mode 100644 index 00000000..9f4973c3 --- /dev/null +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/makedep.go @@ -0,0 +1,106 @@ +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "path/filepath" + "strings" +) + +func adjustDependencies(w io.Writer, baseDir string, deps []dependency) error { + for _, dep := range deps { + relativeFile, err := filepath.Rel(baseDir, dep.file) + if err != nil { + return err + } + + if len(dep.prerequisites) == 0 { + _, err := fmt.Fprintf(w, "%s:\n\n", relativeFile) + if err != nil { + return err + } + continue + } + + var prereqs []string + for _, prereq := range dep.prerequisites { + relativePrereq, err := filepath.Rel(baseDir, prereq) + if err != nil { + return err + } + + prereqs = append(prereqs, relativePrereq) + } + + _, err = fmt.Fprintf(w, "%s: \\\n %s\n\n", relativeFile, strings.Join(prereqs, " \\\n ")) + if err != nil { + return err + } + } + return nil +} + +type dependency struct { + file string + prerequisites []string +} + +func parseDependencies(baseDir string, in io.Reader) ([]dependency, error) { + abs := func(path string) string { + if filepath.IsAbs(path) { + return path + } + return filepath.Join(baseDir, path) + } + + scanner := bufio.NewScanner(in) + var line strings.Builder + var deps []dependency + for scanner.Scan() { + buf := scanner.Bytes() + if line.Len()+len(buf) > 1024*1024 { + return nil, errors.New("line too long") + } + + if bytes.HasSuffix(buf, []byte{'\\'}) { + line.Write(buf[:len(buf)-1]) + continue + } + + line.Write(buf) + if line.Len() == 0 { + // Skip empty lines + continue + } + + parts := strings.SplitN(line.String(), ":", 2) + if len(parts) < 2 { + return nil, fmt.Errorf("invalid line without ':'") + } + + // NB: This doesn't handle filenames with spaces in them. + // It seems like make doesn't do that either, so oh well. + var prereqs []string + for _, prereq := range strings.Fields(parts[1]) { + prereqs = append(prereqs, abs(prereq)) + } + + deps = append(deps, dependency{ + abs(string(parts[0])), + prereqs, + }) + line.Reset() + } + if err := scanner.Err(); err != nil { + return nil, err + } + + // There is always at least a dependency for the main file. + if len(deps) == 0 { + return nil, fmt.Errorf("empty dependency file") + } + return deps, nil +} diff --git a/vendor/github.com/cilium/ebpf/cmd/bpf2go/tools.go b/vendor/github.com/cilium/ebpf/cmd/bpf2go/tools.go index d2e020b4..e754d7ac 100644 --- a/vendor/github.com/cilium/ebpf/cmd/bpf2go/tools.go +++ b/vendor/github.com/cilium/ebpf/cmd/bpf2go/tools.go @@ -3,10 +3,7 @@ package main import ( "errors" "fmt" - "runtime/debug" "strings" - "unicode" - "unicode/utf8" ) func splitCFlagsFromArgs(in []string) (args, cflags []string) { @@ -77,18 +74,3 @@ func splitArguments(in string) ([]string, error) { return result, nil } - -func toUpperFirst(str string) string { - first, n := utf8.DecodeRuneInString(str) - return string(unicode.ToUpper(first)) + str[n:] -} - -func currentModule() string { - bi, ok := debug.ReadBuildInfo() - if !ok { - // Fall back to constant since bazel doesn't support BuildInfo. - return "github.com/cilium/ebpf" - } - - return bi.Main.Path -} diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go index a5532220..b2cb214a 100644 --- a/vendor/github.com/cilium/ebpf/collection.go +++ b/vendor/github.com/cilium/ebpf/collection.go @@ -57,7 +57,7 @@ func (cs *CollectionSpec) Copy() *CollectionSpec { Maps: make(map[string]*MapSpec, len(cs.Maps)), Programs: make(map[string]*ProgramSpec, len(cs.Programs)), ByteOrder: cs.ByteOrder, - Types: cs.Types, + Types: cs.Types.Copy(), } for name, spec := range cs.Maps { diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go index d55ab889..620037d8 100644 --- a/vendor/github.com/cilium/ebpf/elf_reader.go +++ b/vendor/github.com/cilium/ebpf/elf_reader.go @@ -972,6 +972,9 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b return nil, fmt.Errorf("resolving values contents: %w", err) } + case "map_extra": + return nil, fmt.Errorf("BTF map definition: field %s: %w", member.Name, ErrNotSupported) + default: return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name) } diff --git a/vendor/github.com/cilium/ebpf/info.go b/vendor/github.com/cilium/ebpf/info.go index 79b11c95..04c60c64 100644 --- a/vendor/github.com/cilium/ebpf/info.go +++ b/vendor/github.com/cilium/ebpf/info.go @@ -20,6 +20,23 @@ import ( "github.com/cilium/ebpf/internal/unix" ) +// The *Info structs expose metadata about a program or map. Most +// fields are exposed via a getter: +// +// func (*MapInfo) ID() (MapID, bool) +// +// This is because the metadata available changes based on kernel version. +// The second boolean return value indicates whether a particular field is +// available on the current kernel. +// +// Always add new metadata as such a getter, unless you can somehow get the +// value of the field on all supported kernels. Also document which version +// a particular field first appeared in. +// +// Some metadata is a buffer which needs additional parsing. In this case, +// store the undecoded data in the Info struct and provide a getter which +// decodes it when necessary. See ProgramInfo.Instructions for an example. + // MapInfo describes a map. type MapInfo struct { Type MapType @@ -30,6 +47,8 @@ type MapInfo struct { Flags uint32 // Name as supplied by user space at load time. Available from 4.15. Name string + + btf btf.ID } func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) { @@ -50,6 +69,7 @@ func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) { info.MaxEntries, uint32(info.MapFlags), unix.ByteSliceToString(info.Name[:]), + btf.ID(info.BtfId), }, nil } @@ -77,12 +97,27 @@ func (mi *MapInfo) ID() (MapID, bool) { return mi.id, mi.id > 0 } +// BTFID returns the BTF ID associated with the Map. +// +// The ID is only valid as long as the associated Map is kept alive. +// Available from 4.18. +// +// The bool return value indicates whether this optional field is available and +// populated. (The field may be available but not populated if the kernel +// supports the field but the Map was loaded without BTF information.) +func (mi *MapInfo) BTFID() (btf.ID, bool) { + return mi.btf, mi.btf > 0 +} + // programStats holds statistics of a program. type programStats struct { // Total accumulated runtime of the program ins ns. runtime time.Duration // Total number of times the program was called. runCount uint64 + // Total number of times the programm was NOT called. + // Added in commit 9ed9e9ba2337 ("bpf: Count the number of times recursion was prevented"). + recursionMisses uint64 } // ProgramInfo describes a program. @@ -125,8 +160,9 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) { Name: unix.ByteSliceToString(info.Name[:]), btf: btf.ID(info.BtfId), stats: &programStats{ - runtime: time.Duration(info.RunTimeNs), - runCount: info.RunCnt, + runtime: time.Duration(info.RunTimeNs), + runCount: info.RunCnt, + recursionMisses: info.RecursionMisses, }, } @@ -259,6 +295,16 @@ func (pi *ProgramInfo) Runtime() (time.Duration, bool) { return time.Duration(0), false } +// RecursionMisses returns the total number of times the program was NOT called. +// This can happen when another bpf program is already running on the cpu, which +// is likely to happen for example when you interrupt bpf program execution. +func (pi *ProgramInfo) RecursionMisses() (uint64, bool) { + if pi.stats != nil { + return pi.stats.recursionMisses, true + } + return 0, false +} + // Instructions returns the 'xlated' instruction stream of the program // after it has been verified and rewritten by the kernel. These instructions // cannot be loaded back into the kernel as-is, this is mainly used for diff --git a/vendor/github.com/cilium/ebpf/internal/errors.go b/vendor/github.com/cilium/ebpf/internal/errors.go index bda01e2f..83a371ad 100644 --- a/vendor/github.com/cilium/ebpf/internal/errors.go +++ b/vendor/github.com/cilium/ebpf/internal/errors.go @@ -12,7 +12,7 @@ import ( // // The default error output is a summary of the full log. The latter can be // accessed via VerifierError.Log or by formatting the error, see Format. -func ErrorWithLog(source string, err error, log []byte, truncated bool) *VerifierError { +func ErrorWithLog(source string, err error, log []byte) *VerifierError { const whitespace = "\t\r\v\n " // Convert verifier log C string by truncating it on the first 0 byte @@ -23,7 +23,7 @@ func ErrorWithLog(source string, err error, log []byte, truncated bool) *Verifie log = bytes.Trim(log, whitespace) if len(log) == 0 { - return &VerifierError{source, err, nil, truncated} + return &VerifierError{source, err, nil, false} } logLines := bytes.Split(log, []byte{'\n'}) @@ -34,7 +34,7 @@ func ErrorWithLog(source string, err error, log []byte, truncated bool) *Verifie lines = append(lines, string(bytes.TrimRight(line, whitespace))) } - return &VerifierError{source, err, lines, truncated} + return &VerifierError{source, err, lines, false} } // VerifierError includes information from the eBPF verifier. @@ -46,7 +46,7 @@ type VerifierError struct { Cause error // The verifier output split into lines. Log []string - // Whether the log output is truncated, based on several heuristics. + // Deprecated: the log is never truncated anymore. Truncated bool } @@ -70,7 +70,7 @@ func (le *VerifierError) Error() string { } lines := log[n-1:] - if n >= 2 && (includePreviousLine(log[n-1]) || le.Truncated) { + if n >= 2 && includePreviousLine(log[n-1]) { // Add one more line of context if it aids understanding the error. lines = log[n-2:] } @@ -81,22 +81,9 @@ func (le *VerifierError) Error() string { } omitted := len(le.Log) - len(lines) - if omitted == 0 && !le.Truncated { - return b.String() - } - - b.WriteString(" (") - if le.Truncated { - b.WriteString("truncated") - } - if omitted > 0 { - if le.Truncated { - b.WriteString(", ") - } - fmt.Fprintf(&b, "%d line(s) omitted", omitted) + fmt.Fprintf(&b, " (%d line(s) omitted)", omitted) } - b.WriteString(")") return b.String() } @@ -188,10 +175,6 @@ func (le *VerifierError) Format(f fmt.State, verb rune) { } } - if le.Truncated { - fmt.Fprintf(f, "\n\t(truncated)") - } - default: fmt.Fprintf(f, "%%!%c(BADVERB)", verb) } diff --git a/vendor/github.com/cilium/ebpf/internal/sys/types.go b/vendor/github.com/cilium/ebpf/internal/sys/types.go index d2ae9426..70e754de 100644 --- a/vendor/github.com/cilium/ebpf/internal/sys/types.go +++ b/vendor/github.com/cilium/ebpf/internal/sys/types.go @@ -359,7 +359,7 @@ const ( BPF_LINK_TYPE_TCX LinkType = 11 BPF_LINK_TYPE_UPROBE_MULTI LinkType = 12 BPF_LINK_TYPE_NETKIT LinkType = 13 - MAX_BPF_LINK_TYPE LinkType = 14 + __MAX_BPF_LINK_TYPE LinkType = 14 ) type MapType uint32 @@ -528,7 +528,7 @@ type LinkInfo struct { Id LinkID ProgId uint32 _ [4]byte - Extra [40]uint8 + Extra [48]uint8 } type MapInfo struct { @@ -1263,7 +1263,7 @@ type CgroupLinkInfo struct { _ [4]byte CgroupId uint64 AttachType AttachType - _ [28]byte + _ [36]byte } type IterLinkInfo struct { @@ -1287,6 +1287,7 @@ type KprobeLinkInfo struct { Offset uint32 Addr uint64 Missed uint64 + _ [8]byte } type KprobeMultiLinkInfo struct { @@ -1298,7 +1299,7 @@ type KprobeMultiLinkInfo struct { Count uint32 Flags uint32 Missed uint64 - _ [16]byte + _ [24]byte } type NetNsLinkInfo struct { @@ -1308,7 +1309,7 @@ type NetNsLinkInfo struct { _ [4]byte NetnsIno uint32 AttachType AttachType - _ [32]byte + _ [40]byte } type NetfilterLinkInfo struct { @@ -1320,7 +1321,7 @@ type NetfilterLinkInfo struct { Hooknum uint32 Priority int32 Flags uint32 - _ [24]byte + _ [32]byte } type NetkitLinkInfo struct { @@ -1330,7 +1331,7 @@ type NetkitLinkInfo struct { _ [4]byte Ifindex uint32 AttachType AttachType - _ [32]byte + _ [40]byte } type PerfEventLinkInfo struct { @@ -1348,7 +1349,7 @@ type RawTracepointLinkInfo struct { _ [4]byte TpName Pointer TpNameLen uint32 - _ [28]byte + _ [36]byte } type TcxLinkInfo struct { @@ -1358,7 +1359,7 @@ type TcxLinkInfo struct { _ [4]byte Ifindex uint32 AttachType AttachType - _ [32]byte + _ [40]byte } type TracingLinkInfo struct { @@ -1369,7 +1370,7 @@ type TracingLinkInfo struct { AttachType AttachType TargetObjId uint32 TargetBtfId TypeID - _ [28]byte + _ [36]byte } type XDPLinkInfo struct { @@ -1378,5 +1379,5 @@ type XDPLinkInfo struct { ProgId uint32 _ [4]byte Ifindex uint32 - _ [36]byte + _ [44]byte } diff --git a/vendor/github.com/cilium/ebpf/link/cgroup.go b/vendor/github.com/cilium/ebpf/link/cgroup.go index 79f3d2b7..f17d34f0 100644 --- a/vendor/github.com/cilium/ebpf/link/cgroup.go +++ b/vendor/github.com/cilium/ebpf/link/cgroup.go @@ -6,6 +6,7 @@ import ( "os" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) type cgroupAttachFlags uint32 @@ -187,3 +188,21 @@ func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) return &linkCgroup{*link}, err } + +func (cg *linkCgroup) Info() (*Info, error) { + var info sys.CgroupLinkInfo + if err := sys.ObjInfo(cg.fd, &info); err != nil { + return nil, fmt.Errorf("cgroup link info: %s", err) + } + extra := &CgroupInfo{ + CgroupId: info.CgroupId, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/link/kprobe.go b/vendor/github.com/cilium/ebpf/link/kprobe.go index b54ca908..fe3f17c3 100644 --- a/vendor/github.com/cilium/ebpf/link/kprobe.go +++ b/vendor/github.com/cilium/ebpf/link/kprobe.go @@ -59,6 +59,8 @@ func (ko *KprobeOptions) cookie() uint64 { // If attaching to symbol fails, automatically retries with the running // platform's syscall prefix (e.g. __x64_) to support attaching to syscalls // in a portable fashion. +// +// The returned Link may implement [PerfEvent]. func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) { k, err := kprobe(symbol, prog, opts, false) if err != nil { @@ -90,6 +92,8 @@ func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error // // On kernels 5.10 and earlier, setting a kretprobe on a nonexistent symbol // incorrectly returns unix.EINVAL instead of os.ErrNotExist. +// +// The returned Link may implement [PerfEvent]. func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) { k, err := kprobe(symbol, prog, opts, true) if err != nil { @@ -274,7 +278,11 @@ func pmuProbe(args tracefs.ProbeArgs) (*perfEvent, error) { } } - rawFd, err := unix.PerfEventOpen(&attr, args.Pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + cpu := 0 + if args.Pid != perfAllThreads { + cpu = -1 + } + rawFd, err := unix.PerfEventOpen(&attr, args.Pid, cpu, -1, unix.PERF_FLAG_FD_CLOEXEC) // On some old kernels, kprobe PMU doesn't allow `.` in symbol names and // return -EINVAL. Return ErrNotSupported to allow falling back to tracefs. diff --git a/vendor/github.com/cilium/ebpf/link/kprobe_multi.go b/vendor/github.com/cilium/ebpf/link/kprobe_multi.go index 4d364d80..f7a8291f 100644 --- a/vendor/github.com/cilium/ebpf/link/kprobe_multi.go +++ b/vendor/github.com/cilium/ebpf/link/kprobe_multi.go @@ -130,12 +130,23 @@ func (kml *kprobeMultiLink) Update(prog *ebpf.Program) error { return fmt.Errorf("update kprobe_multi: %w", ErrNotSupported) } -func (kml *kprobeMultiLink) Pin(string) error { - return fmt.Errorf("pin kprobe_multi: %w", ErrNotSupported) -} +func (kml *kprobeMultiLink) Info() (*Info, error) { + var info sys.KprobeMultiLinkInfo + if err := sys.ObjInfo(kml.fd, &info); err != nil { + return nil, fmt.Errorf("kprobe multi link info: %s", err) + } + extra := &KprobeMultiInfo{ + count: info.Count, + flags: info.Flags, + missed: info.Missed, + } -func (kml *kprobeMultiLink) Unpin() error { - return fmt.Errorf("unpin kprobe_multi: %w", ErrNotSupported) + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil } var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5.18", func() error { diff --git a/vendor/github.com/cilium/ebpf/link/link.go b/vendor/github.com/cilium/ebpf/link/link.go index 81428568..9c34616c 100644 --- a/vendor/github.com/cilium/ebpf/link/link.go +++ b/vendor/github.com/cilium/ebpf/link/link.go @@ -119,13 +119,15 @@ func wrapRawLink(raw *RawLink) (_ Link, err error) { case UprobeMultiType: return &uprobeMultiLink{*raw}, nil case PerfEventType: - return nil, fmt.Errorf("recovering perf event fd: %w", ErrNotSupported) + return &perfEventLink{*raw, nil}, nil case TCXType: return &tcxLink{*raw}, nil case NetfilterType: return &netfilterLink{*raw}, nil case NetkitType: return &netkitLink{*raw}, nil + case XDPType: + return &xdpLink{*raw}, nil default: return raw, nil } @@ -438,6 +440,9 @@ func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error { } // Info returns metadata about the link. +// +// Linktype specific metadata is not included and can be retrieved +// via the linktype specific Info() method. func (l *RawLink) Info() (*Info, error) { var info sys.LinkInfo @@ -445,117 +450,11 @@ func (l *RawLink) Info() (*Info, error) { return nil, fmt.Errorf("link info: %s", err) } - var extra interface{} - switch info.Type { - case CgroupType: - var cgroupInfo sys.CgroupLinkInfo - if err := sys.ObjInfo(l.fd, &cgroupInfo); err != nil { - return nil, fmt.Errorf("cgroup link info: %s", err) - } - extra = &CgroupInfo{ - CgroupId: cgroupInfo.CgroupId, - AttachType: cgroupInfo.AttachType, - } - case NetNsType: - var netnsInfo sys.NetNsLinkInfo - if err := sys.ObjInfo(l.fd, &netnsInfo); err != nil { - return nil, fmt.Errorf("netns link info: %s", err) - } - extra = &NetNsInfo{ - NetnsIno: netnsInfo.NetnsIno, - AttachType: netnsInfo.AttachType, - } - case TracingType: - var tracingInfo sys.TracingLinkInfo - if err := sys.ObjInfo(l.fd, &tracingInfo); err != nil { - return nil, fmt.Errorf("tracing link info: %s", err) - } - extra = &TracingInfo{ - TargetObjId: tracingInfo.TargetObjId, - TargetBtfId: tracingInfo.TargetBtfId, - AttachType: tracingInfo.AttachType, - } - case XDPType: - var xdpInfo sys.XDPLinkInfo - if err := sys.ObjInfo(l.fd, &xdpInfo); err != nil { - return nil, fmt.Errorf("xdp link info: %s", err) - } - extra = &XDPInfo{ - Ifindex: xdpInfo.Ifindex, - } - case RawTracepointType, IterType, UprobeMultiType: - // Extra metadata not supported. - case TCXType: - var tcxInfo sys.TcxLinkInfo - if err := sys.ObjInfo(l.fd, &tcxInfo); err != nil { - return nil, fmt.Errorf("tcx link info: %s", err) - } - extra = &TCXInfo{ - Ifindex: tcxInfo.Ifindex, - AttachType: tcxInfo.AttachType, - } - case NetfilterType: - var netfilterInfo sys.NetfilterLinkInfo - if err := sys.ObjInfo(l.fd, &netfilterInfo); err != nil { - return nil, fmt.Errorf("netfilter link info: %s", err) - } - extra = &NetfilterInfo{ - Pf: netfilterInfo.Pf, - Hooknum: netfilterInfo.Hooknum, - Priority: netfilterInfo.Priority, - Flags: netfilterInfo.Flags, - } - case NetkitType: - var netkitInfo sys.NetkitLinkInfo - if err := sys.ObjInfo(l.fd, &netkitInfo); err != nil { - return nil, fmt.Errorf("tcx link info: %s", err) - } - extra = &NetkitInfo{ - Ifindex: netkitInfo.Ifindex, - AttachType: netkitInfo.AttachType, - } - case KprobeMultiType: - var kprobeMultiInfo sys.KprobeMultiLinkInfo - if err := sys.ObjInfo(l.fd, &kprobeMultiInfo); err != nil { - return nil, fmt.Errorf("kprobe multi link info: %s", err) - } - extra = &KprobeMultiInfo{ - count: kprobeMultiInfo.Count, - flags: kprobeMultiInfo.Flags, - missed: kprobeMultiInfo.Missed, - } - case PerfEventType: - var perfEventInfo sys.PerfEventLinkInfo - if err := sys.ObjInfo(l.fd, &perfEventInfo); err != nil { - return nil, fmt.Errorf("perf event link info: %s", err) - } - - var extra2 interface{} - switch perfEventInfo.PerfEventType { - case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE: - var kprobeInfo sys.KprobeLinkInfo - if err := sys.ObjInfo(l.fd, &kprobeInfo); err != nil { - return nil, fmt.Errorf("kprobe multi link info: %s", err) - } - extra2 = &KprobeInfo{ - address: kprobeInfo.Addr, - missed: kprobeInfo.Missed, - } - } - - extra = &PerfEventInfo{ - Type: perfEventInfo.PerfEventType, - extra: extra2, - } - default: - return nil, fmt.Errorf("unknown link info type: %d", info.Type) - } - return &Info{ info.Type, info.Id, ebpf.ProgramID(info.ProgId), - extra, + nil, }, nil } diff --git a/vendor/github.com/cilium/ebpf/link/netfilter.go b/vendor/github.com/cilium/ebpf/link/netfilter.go index 250c8767..34be3908 100644 --- a/vendor/github.com/cilium/ebpf/link/netfilter.go +++ b/vendor/github.com/cilium/ebpf/link/netfilter.go @@ -67,4 +67,24 @@ func (*netfilterLink) Update(new *ebpf.Program) error { return fmt.Errorf("netfilter update: %w", ErrNotSupported) } +func (nf *netfilterLink) Info() (*Info, error) { + var info sys.NetfilterLinkInfo + if err := sys.ObjInfo(nf.fd, &info); err != nil { + return nil, fmt.Errorf("netfilter link info: %s", err) + } + extra := &NetfilterInfo{ + Pf: info.Pf, + Hooknum: info.Hooknum, + Priority: info.Priority, + Flags: info.Flags, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + var _ Link = (*netfilterLink)(nil) diff --git a/vendor/github.com/cilium/ebpf/link/netkit.go b/vendor/github.com/cilium/ebpf/link/netkit.go index 36ed72a4..5eee3b02 100644 --- a/vendor/github.com/cilium/ebpf/link/netkit.go +++ b/vendor/github.com/cilium/ebpf/link/netkit.go @@ -69,3 +69,21 @@ type netkitLink struct { } var _ Link = (*netkitLink)(nil) + +func (netkit *netkitLink) Info() (*Info, error) { + var info sys.NetkitLinkInfo + if err := sys.ObjInfo(netkit.fd, &info); err != nil { + return nil, fmt.Errorf("netkit link info: %s", err) + } + extra := &NetkitInfo{ + Ifindex: info.Ifindex, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/link/netns.go b/vendor/github.com/cilium/ebpf/link/netns.go index 344ecced..b1edd340 100644 --- a/vendor/github.com/cilium/ebpf/link/netns.go +++ b/vendor/github.com/cilium/ebpf/link/netns.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) // NetNsLink is a program attached to a network namespace. @@ -34,3 +35,21 @@ func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) { return &NetNsLink{*link}, nil } + +func (ns *NetNsLink) Info() (*Info, error) { + var info sys.NetNsLinkInfo + if err := sys.ObjInfo(ns.fd, &info); err != nil { + return nil, fmt.Errorf("netns link info: %s", err) + } + extra := &NetNsInfo{ + NetnsIno: info.NetnsIno, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/link/perf_event.go b/vendor/github.com/cilium/ebpf/link/perf_event.go index 5f7a628b..1d8feb58 100644 --- a/vendor/github.com/cilium/ebpf/link/perf_event.go +++ b/vendor/github.com/cilium/ebpf/link/perf_event.go @@ -3,6 +3,7 @@ package link import ( "errors" "fmt" + "os" "runtime" "unsafe" @@ -78,6 +79,18 @@ func (pe *perfEvent) Close() error { return nil } +// PerfEvent is implemented by some Link types which use a perf event under +// the hood. +type PerfEvent interface { + // PerfEvent returns a file for the underlying perf event. + // + // It is the callers responsibility to close the returned file. + // + // Making changes to the associated perf event lead to + // undefined behaviour. + PerfEvent() (*os.File, error) +} + // perfEventLink represents a bpf perf link. type perfEventLink struct { RawLink @@ -86,30 +99,16 @@ type perfEventLink struct { func (pl *perfEventLink) isLink() {} -// Pinning requires the underlying perf event FD to stay open. -// -// | PerfEvent FD | BpfLink FD | Works | -// |--------------|------------|-------| -// | Open | Open | Yes | -// | Closed | Open | No | -// | Open | Closed | No (Pin() -> EINVAL) | -// | Closed | Closed | No (Pin() -> EINVAL) | -// -// There is currently no pretty way to recover the perf event FD -// when loading a pinned link, so leave as not supported for now. -func (pl *perfEventLink) Pin(string) error { - return fmt.Errorf("perf event link pin: %w", ErrNotSupported) -} - -func (pl *perfEventLink) Unpin() error { - return fmt.Errorf("perf event link unpin: %w", ErrNotSupported) -} - func (pl *perfEventLink) Close() error { if err := pl.fd.Close(); err != nil { return fmt.Errorf("perf link close: %w", err) } + // when created from pinned link + if pl.pe == nil { + return nil + } + if err := pl.pe.Close(); err != nil { return fmt.Errorf("perf event close: %w", err) } @@ -120,6 +119,54 @@ func (pl *perfEventLink) Update(prog *ebpf.Program) error { return fmt.Errorf("perf event link update: %w", ErrNotSupported) } +var _ PerfEvent = (*perfEventLink)(nil) + +func (pl *perfEventLink) PerfEvent() (*os.File, error) { + // when created from pinned link + if pl.pe == nil { + return nil, ErrNotSupported + } + + fd, err := pl.pe.fd.Dup() + if err != nil { + return nil, err + } + + return fd.File("perf-event"), nil +} + +func (pl *perfEventLink) Info() (*Info, error) { + var info sys.PerfEventLinkInfo + if err := sys.ObjInfo(pl.fd, &info); err != nil { + return nil, fmt.Errorf("perf event link info: %s", err) + } + + var extra2 interface{} + switch info.PerfEventType { + case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE: + var kprobeInfo sys.KprobeLinkInfo + if err := sys.ObjInfo(pl.fd, &kprobeInfo); err != nil { + return nil, fmt.Errorf("kprobe link info: %s", err) + } + extra2 = &KprobeInfo{ + address: kprobeInfo.Addr, + missed: kprobeInfo.Missed, + } + } + + extra := &PerfEventInfo{ + Type: info.PerfEventType, + extra: extra2, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + // perfEventIoctl implements Link and handles the perf event lifecycle // via ioctl(). type perfEventIoctl struct { @@ -154,6 +201,17 @@ func (pi *perfEventIoctl) Info() (*Info, error) { return nil, fmt.Errorf("perf event ioctl info: %w", ErrNotSupported) } +var _ PerfEvent = (*perfEventIoctl)(nil) + +func (pi *perfEventIoctl) PerfEvent() (*os.File, error) { + fd, err := pi.fd.Dup() + if err != nil { + return nil, err + } + + return fd.File("perf-event"), nil +} + // attach the given eBPF prog to the perf event stored in pe. // pe must contain a valid perf event fd. // prog's type must match the program type stored in pe. @@ -229,7 +287,11 @@ func openTracepointPerfEvent(tid uint64, pid int) (*sys.FD, error) { Wakeup: 1, } - fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC) + cpu := 0 + if pid != perfAllThreads { + cpu = -1 + } + fd, err := unix.PerfEventOpen(&attr, pid, cpu, -1, unix.PERF_FLAG_FD_CLOEXEC) if err != nil { return nil, fmt.Errorf("opening tracepoint perf event: %w", err) } diff --git a/vendor/github.com/cilium/ebpf/link/tcx.go b/vendor/github.com/cilium/ebpf/link/tcx.go index 88f2237d..ac045b71 100644 --- a/vendor/github.com/cilium/ebpf/link/tcx.go +++ b/vendor/github.com/cilium/ebpf/link/tcx.go @@ -69,3 +69,21 @@ type tcxLink struct { } var _ Link = (*tcxLink)(nil) + +func (tcx *tcxLink) Info() (*Info, error) { + var info sys.TcxLinkInfo + if err := sys.ObjInfo(tcx.fd, &info); err != nil { + return nil, fmt.Errorf("tcx link info: %s", err) + } + extra := &TCXInfo{ + Ifindex: info.Ifindex, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/vendor/github.com/cilium/ebpf/link/tracepoint.go b/vendor/github.com/cilium/ebpf/link/tracepoint.go index 95f5fae3..6fc78b98 100644 --- a/vendor/github.com/cilium/ebpf/link/tracepoint.go +++ b/vendor/github.com/cilium/ebpf/link/tracepoint.go @@ -30,6 +30,8 @@ type TracepointOptions struct { // // Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is // only possible as of kernel 4.14 (commit cf5f5ce). +// +// The returned Link may implement [PerfEvent]. func Tracepoint(group, name string, prog *ebpf.Program, opts *TracepointOptions) (Link, error) { if group == "" || name == "" { return nil, fmt.Errorf("group and name cannot be empty: %w", errInvalidInput) diff --git a/vendor/github.com/cilium/ebpf/link/tracing.go b/vendor/github.com/cilium/ebpf/link/tracing.go index 1e1a7834..9e570afc 100644 --- a/vendor/github.com/cilium/ebpf/link/tracing.go +++ b/vendor/github.com/cilium/ebpf/link/tracing.go @@ -18,6 +18,25 @@ func (f *tracing) Update(new *ebpf.Program) error { return fmt.Errorf("tracing update: %w", ErrNotSupported) } +func (f *tracing) Info() (*Info, error) { + var info sys.TracingLinkInfo + if err := sys.ObjInfo(f.fd, &info); err != nil { + return nil, fmt.Errorf("tracing link info: %s", err) + } + extra := &TracingInfo{ + TargetObjId: info.TargetObjId, + TargetBtfId: info.TargetBtfId, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + // AttachFreplace attaches the given eBPF program to the function it replaces. // // The program and name can either be provided at link time, or can be provided diff --git a/vendor/github.com/cilium/ebpf/link/uprobe.go b/vendor/github.com/cilium/ebpf/link/uprobe.go index ad85024e..194d1d31 100644 --- a/vendor/github.com/cilium/ebpf/link/uprobe.go +++ b/vendor/github.com/cilium/ebpf/link/uprobe.go @@ -222,6 +222,8 @@ func (ex *Executable) address(symbol string, address, offset uint64) (uint64, er // // Functions provided by shared libraries can currently not be traced and // will result in an ErrNotSupported. +// +// The returned Link may implement [PerfEvent]. func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { u, err := ex.uprobe(symbol, prog, opts, false) if err != nil { @@ -256,6 +258,8 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti // // Functions provided by shared libraries can currently not be traced and // will result in an ErrNotSupported. +// +// The returned Link may implement [PerfEvent]. func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) { u, err := ex.uprobe(symbol, prog, opts, true) if err != nil { diff --git a/vendor/github.com/cilium/ebpf/link/uprobe_multi.go b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go index 9a8d329c..aea807b3 100644 --- a/vendor/github.com/cilium/ebpf/link/uprobe_multi.go +++ b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go @@ -172,14 +172,6 @@ func (kml *uprobeMultiLink) Update(prog *ebpf.Program) error { return fmt.Errorf("update uprobe_multi: %w", ErrNotSupported) } -func (kml *uprobeMultiLink) Pin(string) error { - return fmt.Errorf("pin uprobe_multi: %w", ErrNotSupported) -} - -func (kml *uprobeMultiLink) Unpin() error { - return fmt.Errorf("unpin uprobe_multi: %w", ErrNotSupported) -} - var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6.6", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Name: "probe_upm_link", diff --git a/vendor/github.com/cilium/ebpf/link/xdp.go b/vendor/github.com/cilium/ebpf/link/xdp.go index aa8dd3a4..2ec44122 100644 --- a/vendor/github.com/cilium/ebpf/link/xdp.go +++ b/vendor/github.com/cilium/ebpf/link/xdp.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) // XDPAttachFlags represents how XDP program will be attached to interface. @@ -50,5 +51,30 @@ func AttachXDP(opts XDPOptions) (Link, error) { Flags: uint32(opts.Flags), }) - return rawLink, err + if err != nil { + return nil, fmt.Errorf("failed to attach link: %w", err) + } + + return &xdpLink{*rawLink}, nil +} + +type xdpLink struct { + RawLink +} + +func (xdp *xdpLink) Info() (*Info, error) { + var info sys.XDPLinkInfo + if err := sys.ObjInfo(xdp.fd, &info); err != nil { + return nil, fmt.Errorf("xdp link info: %s", err) + } + extra := &XDPInfo{ + Ifindex: info.Ifindex, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil } diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go index e46fa3f1..0b62101c 100644 --- a/vendor/github.com/cilium/ebpf/map.go +++ b/vendor/github.com/cilium/ebpf/map.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "strings" "sync" "time" @@ -28,6 +29,10 @@ var ( ErrIterationAborted = errors.New("iteration aborted") ErrMapIncompatible = errors.New("map spec is incompatible with existing map") errMapNoBTFValue = errors.New("map spec does not contain a BTF Value") + + // pre-allocating these errors here since they may get called in hot code paths + // and cause unnecessary memory allocations + errMapLookupKeyNotExist = fmt.Errorf("lookup: %w", sysErrKeyNotExist) ) // MapOptions control loading a map into the kernel. @@ -96,11 +101,20 @@ func (ms *MapSpec) Copy() *MapSpec { } cpy := *ms + cpy.Contents = slices.Clone(cpy.Contents) + cpy.Key = btf.Copy(cpy.Key) + cpy.Value = btf.Copy(cpy.Value) - cpy.Contents = make([]MapKV, len(ms.Contents)) - copy(cpy.Contents, ms.Contents) + if cpy.InnerMap == ms { + cpy.InnerMap = &cpy + } else { + cpy.InnerMap = ms.InnerMap.Copy() + } - cpy.InnerMap = ms.InnerMap.Copy() + if cpy.Extra != nil { + extra := *cpy.Extra + cpy.Extra = &extra + } return &cpy } @@ -499,9 +513,6 @@ func handleMapCreateError(attr sys.MapCreateAttr, spec *MapSpec, err error) erro return fmt.Errorf("map create: %w (ring map size %d not a multiple of page size %d)", err, maxEntries, pageSize) } } - if attr.BtfFd == 0 { - return fmt.Errorf("map create: %w (without BTF k/v)", err) - } return fmt.Errorf("map create: %w", err) } @@ -571,6 +582,24 @@ func (m *Map) Info() (*MapInfo, error) { return newMapInfoFromFd(m.fd) } +// Handle returns a reference to the Map's type information in the kernel. +// +// Returns ErrNotSupported if the kernel has no BTF support, or if there is no +// BTF associated with the Map. +func (m *Map) Handle() (*btf.Handle, error) { + info, err := m.Info() + if err != nil { + return nil, err + } + + id, ok := info.BTFID() + if !ok { + return nil, fmt.Errorf("map %s: retrieve BTF ID: %w", m, ErrNotSupported) + } + + return btf.NewHandleFromID(id) +} + // MapLookupFlags controls the behaviour of the map lookup calls. type MapLookupFlags uint64 @@ -652,7 +681,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) { } func (m *Map) lookupPerCPU(key, valueOut any, flags MapLookupFlags) error { - slice, err := ensurePerCPUSlice(valueOut, int(m.valueSize)) + slice, err := ensurePerCPUSlice(valueOut) if err != nil { return err } @@ -677,13 +706,16 @@ func (m *Map) lookup(key interface{}, valueOut sys.Pointer, flags MapLookupFlags } if err = sys.MapLookupElem(&attr); err != nil { + if errors.Is(err, unix.ENOENT) { + return errMapLookupKeyNotExist + } return fmt.Errorf("lookup: %w", wrapMapError(err)) } return nil } func (m *Map) lookupAndDeletePerCPU(key, valueOut any, flags MapLookupFlags) error { - slice, err := ensurePerCPUSlice(valueOut, int(m.valueSize)) + slice, err := ensurePerCPUSlice(valueOut) if err != nil { return err } @@ -695,7 +727,7 @@ func (m *Map) lookupAndDeletePerCPU(key, valueOut any, flags MapLookupFlags) err } // ensurePerCPUSlice allocates a slice for a per-CPU value if necessary. -func ensurePerCPUSlice(sliceOrPtr any, elemLength int) (any, error) { +func ensurePerCPUSlice(sliceOrPtr any) (any, error) { sliceOrPtrType := reflect.TypeOf(sliceOrPtr) if sliceOrPtrType.Kind() == reflect.Slice { // The target is a slice, the caller is responsible for ensuring that @@ -985,7 +1017,11 @@ func (m *Map) guessNonExistentKey() ([]byte, error) { // the end of all possible results, even when partial results // are returned. It should be used to evaluate when lookup is "done". func (m *Map) BatchLookup(cursor *MapBatchCursor, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { - return m.batchLookup(sys.BPF_MAP_LOOKUP_BATCH, cursor, keysOut, valuesOut, opts) + n, err := m.batchLookup(sys.BPF_MAP_LOOKUP_BATCH, cursor, keysOut, valuesOut, opts) + if err != nil { + return n, fmt.Errorf("map batch lookup: %w", err) + } + return n, nil } // BatchLookupAndDelete looks up many elements in a map at once, @@ -1005,7 +1041,11 @@ func (m *Map) BatchLookup(cursor *MapBatchCursor, keysOut, valuesOut interface{} // the end of all possible results, even when partial results // are returned. It should be used to evaluate when lookup is "done". func (m *Map) BatchLookupAndDelete(cursor *MapBatchCursor, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) { - return m.batchLookup(sys.BPF_MAP_LOOKUP_AND_DELETE_BATCH, cursor, keysOut, valuesOut, opts) + n, err := m.batchLookup(sys.BPF_MAP_LOOKUP_AND_DELETE_BATCH, cursor, keysOut, valuesOut, opts) + if err != nil { + return n, fmt.Errorf("map batch lookup and delete: %w", err) + } + return n, nil } // MapBatchCursor represents a starting point for a batch operation. @@ -1027,7 +1067,11 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *MapBatchCursor, keysOut, valuesOu valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize)) n, err := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts) - if err != nil { + if errors.Is(err, unix.ENOSPC) { + // Hash tables return ENOSPC when the size of the batch is smaller than + // any bucket. + return n, fmt.Errorf("%w (batch size too small?)", err) + } else if err != nil { return n, err } diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go index f4f3af7c..9bc6325f 100644 --- a/vendor/github.com/cilium/ebpf/prog.go +++ b/vendor/github.com/cilium/ebpf/prog.go @@ -46,13 +46,13 @@ const ( outputPad = 256 + 2 ) -// DefaultVerifierLogSize is the default number of bytes allocated for the -// verifier log. +// Deprecated: the correct log size is now detected automatically and this +// constant is unused. const DefaultVerifierLogSize = 64 * 1024 -// maxVerifierLogSize is the maximum size of verifier log buffer the kernel -// will accept before returning EINVAL. -const maxVerifierLogSize = math.MaxUint32 >> 2 +// minVerifierLogSize is the default number of bytes allocated for the +// verifier log. +const minVerifierLogSize = 64 * 1024 // ProgramOptions control loading a program into the kernel. type ProgramOptions struct { @@ -73,15 +73,8 @@ type ProgramOptions struct { // attempt at loading the program. LogLevel LogLevel - // Controls the output buffer size for the verifier log, in bytes. See the - // documentation on ProgramOptions.LogLevel for details about how this value - // is used. - // - // If this value is set too low to fit the verifier log, the resulting - // [ebpf.VerifierError]'s Truncated flag will be true, and the error string - // will also contain a hint to that effect. - // - // Defaults to DefaultVerifierLogSize. + // Deprecated: the correct log buffer size is determined automatically + // and this field is ignored. LogSize int // Disables the verifier log completely, regardless of other options. @@ -262,10 +255,6 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian) } - if opts.LogSize < 0 { - return nil, errors.New("ProgramOptions.LogSize must be a positive value; disable verifier logs using ProgramOptions.LogDisabled") - } - // Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load") // require the version field to be set to the value of the KERNEL_VERSION // macro for kprobe-type programs. @@ -404,37 +393,59 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er } } - if opts.LogSize == 0 { - opts.LogSize = DefaultVerifierLogSize - } - - // The caller requested a specific verifier log level. Set up the log buffer. + // The caller requested a specific verifier log level. Set up the log buffer + // so that there is a chance of loading the program in a single shot. var logBuf []byte if !opts.LogDisabled && opts.LogLevel != 0 { - logBuf = make([]byte, opts.LogSize) + logBuf = make([]byte, minVerifierLogSize) attr.LogLevel = opts.LogLevel attr.LogSize = uint32(len(logBuf)) attr.LogBuf = sys.NewSlicePointer(logBuf) } - fd, err := sys.ProgLoad(attr) - if err == nil { - return &Program{unix.ByteSliceToString(logBuf), fd, spec.Name, "", spec.Type}, nil - } + for { + var fd *sys.FD + fd, err = sys.ProgLoad(attr) + if err == nil { + return &Program{unix.ByteSliceToString(logBuf), fd, spec.Name, "", spec.Type}, nil + } - // An error occurred loading the program, but the caller did not explicitly - // enable the verifier log. Re-run with branch-level verifier logs enabled to - // obtain more info. Preserve the original error to return it to the caller. - // An undersized log buffer will result in ENOSPC regardless of the underlying - // cause. - var err2 error - if !opts.LogDisabled && opts.LogLevel == 0 { - logBuf = make([]byte, opts.LogSize) - attr.LogLevel = LogLevelBranch - attr.LogSize = uint32(len(logBuf)) - attr.LogBuf = sys.NewSlicePointer(logBuf) + if opts.LogDisabled { + break + } - _, err2 = sys.ProgLoad(attr) + if attr.LogTrueSize != 0 && attr.LogSize >= attr.LogTrueSize { + // The log buffer already has the correct size. + break + } + + if attr.LogSize != 0 && !errors.Is(err, unix.ENOSPC) { + // Logging is enabled and the error is not ENOSPC, so we can infer + // that the log buffer is large enough. + break + } + + if attr.LogLevel == 0 { + // Logging is not enabled but loading the program failed. Enable + // basic logging. + attr.LogLevel = LogLevelBranch + } + + // Make an educated guess how large the buffer should be. Start + // at minVerifierLogSize and then double the size. + logSize := uint32(max(len(logBuf)*2, minVerifierLogSize)) + if int(logSize) < len(logBuf) { + return nil, errors.New("overflow while probing log buffer size") + } + + if attr.LogTrueSize != 0 { + // The kernel has given us a hint how large the log buffer has to be. + logSize = attr.LogTrueSize + } + + logBuf = make([]byte, logSize) + attr.LogSize = logSize + attr.LogBuf = sys.NewSlicePointer(logBuf) } end := bytes.IndexByte(logBuf, 0) @@ -452,10 +463,6 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er } case errors.Is(err, unix.EINVAL): - if opts.LogSize > maxVerifierLogSize { - return nil, fmt.Errorf("load program: %w (ProgramOptions.LogSize exceeds maximum value of %d)", err, maxVerifierLogSize) - } - if bytes.Contains(tail, coreBadCall) { err = errBadRelocation break @@ -479,8 +486,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er } } - truncated := errors.Is(err, unix.ENOSPC) || errors.Is(err2, unix.ENOSPC) - return nil, internal.ErrorWithLog("load program", err, logBuf, truncated) + return nil, internal.ErrorWithLog("load program", err, logBuf) } // NewProgramFromFD creates a program from a raw fd. diff --git a/vendor/github.com/cilium/ebpf/run-tests.sh b/vendor/github.com/cilium/ebpf/run-tests.sh deleted file mode 100644 index c7ff7ea3..00000000 --- a/vendor/github.com/cilium/ebpf/run-tests.sh +++ /dev/null @@ -1,144 +0,0 @@ -#!/usr/bin/env bash -# Test the current package under a different kernel. -# Requires virtme and qemu to be installed. -# Examples: -# Run all tests on a 5.4 kernel -# $ ./run-tests.sh 5.4 -# Run a subset of tests: -# $ ./run-tests.sh 5.4 ./link -# Run using a local kernel image -# $ ./run-tests.sh /path/to/bzImage - -set -euo pipefail - -script="$(realpath "$0")" -readonly script - -source "$(dirname "$script")/testdata/sh/lib.sh" - -quote_env() { - for var in "$@"; do - if [ -v "$var" ]; then - printf "%s=%q " "$var" "${!var}" - fi - done -} - -declare -a preserved_env=( - PATH - CI_MAX_KERNEL_VERSION - TEST_SEED - KERNEL_VERSION -) - -# This script is a bit like a Matryoshka doll since it keeps re-executing itself -# in various different contexts: -# -# 1. invoked by the user like run-tests.sh 5.4 -# 2. invoked by go test like run-tests.sh --exec-vm -# 3. invoked by init in the vm like run-tests.sh --exec-test -# -# This allows us to use all available CPU on the host machine to compile our -# code, and then only use the VM to execute the test. This is because the VM -# is usually slower at compiling than the host. -if [[ "${1:-}" = "--exec-vm" ]]; then - shift - - input="$1" - shift - - # Use sudo if /dev/kvm isn't accessible by the current user. - sudo="" - if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then - sudo="sudo" - fi - readonly sudo - - testdir="$(dirname "$1")" - output="$(mktemp -d)" - printf -v cmd "%q " "$@" - - if [[ "$(stat -c '%t:%T' -L /proc/$$/fd/0)" == "1:3" ]]; then - # stdin is /dev/null, which doesn't play well with qemu. Use a fifo as a - # blocking substitute. - mkfifo "${output}/fake-stdin" - # Open for reading and writing to avoid blocking. - exec 0<> "${output}/fake-stdin" - rm "${output}/fake-stdin" - fi - - if ! $sudo virtme-run --kimg "${input}/boot/vmlinuz" --cpus 2 --memory 1G --pwd \ - --rwdir="${testdir}=${testdir}" \ - --rodir=/run/input="${input}" \ - --rwdir=/run/output="${output}" \ - --script-sh "$(quote_env "${preserved_env[@]}") \"$script\" \ - --exec-test $cmd"; then - exit 23 - fi - - if ! [[ -e "${output}/status" ]]; then - exit 42 - fi - - rc=$(<"${output}/status") - $sudo rm -r "$output" - exit "$rc" -elif [[ "${1:-}" = "--exec-test" ]]; then - shift - - mount -t bpf bpf /sys/fs/bpf - mount -t tracefs tracefs /sys/kernel/debug/tracing - - if [[ -d "/run/input/usr/src/linux/tools/testing/selftests/bpf" ]]; then - export KERNEL_SELFTESTS="/run/input/usr/src/linux/tools/testing/selftests/bpf" - fi - - if [[ -d "/run/input/lib/modules" ]]; then - find /run/input/lib/modules -type f -name bpf_testmod.ko -exec insmod {} \; - fi - - dmesg --clear - rc=0 - "$@" || rc=$? - dmesg - echo $rc > "/run/output/status" - exit $rc # this return code is "swallowed" by qemu -fi - -if [[ -z "${1:-}" ]]; then - echo "Expecting kernel version or path as first argument" - exit 1 -fi - -input="$(mktemp -d)" -readonly input - -if [[ -f "${1}" ]]; then - # First argument is a local file. - readonly kernel="${1}" - cp "${1}" "${input}/boot/vmlinuz" -else - readonly kernel="${1}" - - # LINUX_VERSION_CODE test compares this to discovered value. - export KERNEL_VERSION="${1}" - - if ! extract_oci_image "ghcr.io/cilium/ci-kernels:${kernel}-selftests" "${input}"; then - extract_oci_image "ghcr.io/cilium/ci-kernels:${kernel}" "${input}" - fi -fi -shift - -args=(-short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...) -if (( $# > 0 )); then - args=("$@") -fi - -export GOFLAGS=-mod=readonly -export CGO_ENABLED=0 - -echo Testing on "${kernel}" -go test -exec "$script --exec-vm $input" "${args[@]}" -echo "Test successful on ${kernel}" - -rm -r "${input}" diff --git a/vendor/modules.txt b/vendor/modules.txt index ac9e8073..bcf82553 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -5,12 +5,14 @@ github.com/VividCortex/ewma ## explicit; go 1.17 github.com/cheggaaa/pb/v3 github.com/cheggaaa/pb/v3/termutil -# github.com/cilium/ebpf v0.15.0 -## explicit; go 1.21.0 +# github.com/cilium/ebpf v0.16.0 +## explicit; go 1.21 github.com/cilium/ebpf github.com/cilium/ebpf/asm github.com/cilium/ebpf/btf github.com/cilium/ebpf/cmd/bpf2go +github.com/cilium/ebpf/cmd/bpf2go/gen +github.com/cilium/ebpf/cmd/bpf2go/internal github.com/cilium/ebpf/internal github.com/cilium/ebpf/internal/kallsyms github.com/cilium/ebpf/internal/kconfig