diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33ef4045d..300223bc8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,7 +155,7 @@ jobs: needs: build-and-lint timeout-minutes: 15 env: - EBPF_TEST_IGNORE_KERNEL_VERSION: 'TestKprobeMulti,TestKprobeMultiErrors,TestKprobeMultiCookie,TestKprobeMultiProgramCall,TestHaveBPFLinkKprobeMulti' + EBPF_TEST_IGNORE_VERSION: 'TestKprobeMulti,TestKprobeMultiErrors,TestKprobeMultiCookie,TestKprobeMultiProgramCall,TestHaveBPFLinkKprobeMulti' steps: - uses: actions/checkout@v4 diff --git a/btf/feature.go b/btf/feature.go index 6feb08dfb..d33f9fc7c 100644 --- a/btf/feature.go +++ b/btf/feature.go @@ -11,19 +11,19 @@ import ( // haveBTF attempts to load a BTF blob containing an Int. It should pass on any // kernel that supports BPF_BTF_LOAD. -var haveBTF = internal.NewFeatureTest("BTF", "4.18", func() error { +var haveBTF = internal.NewFeatureTest("BTF", func() error { // 0-length anonymous integer err := probeBTF(&Int{}) if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) { return internal.ErrNotSupported } return err -}) +}, "4.18") // haveMapBTF attempts to load a minimal BTF blob containing a Var. It is // used as a proxy for .bss, .data and .rodata map support, which generally // come with a Var and Datasec. These were introduced in Linux 5.2. -var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func() error { +var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", func() error { if err := haveBTF(); err != nil { return err } @@ -40,12 +40,12 @@ var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func() return internal.ErrNotSupported } return err -}) +}, "5.2") // haveProgBTF attempts to load a BTF blob containing a Func and FuncProto. It // is used as a proxy for ext_info (func_info) support, which depends on // Func(Proto) by definition. -var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0", func() error { +var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", func() error { if err := haveBTF(); err != nil { return err } @@ -60,9 +60,9 @@ var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0", return internal.ErrNotSupported } return err -}) +}, "5.0") -var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func() error { +var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", func() error { if err := haveProgBTF(); err != nil { return err } @@ -78,9 +78,9 @@ var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func() return internal.ErrNotSupported } return err -}) +}, "5.6") -var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error { +var haveEnum64 = internal.NewFeatureTest("ENUM64", func() error { if err := haveBTF(); err != nil { return err } @@ -97,7 +97,7 @@ var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error { return internal.ErrNotSupported } return err -}) +}, "6.0") func probeBTF(typ Type) error { b, err := NewBuilder([]Type{typ}) diff --git a/features/misc.go b/features/misc.go index 6bd8df933..0c4e1a261 100644 --- a/features/misc.go +++ b/features/misc.go @@ -16,7 +16,7 @@ func HaveLargeInstructions() error { return haveLargeInstructions() } -var haveLargeInstructions = internal.NewFeatureTest(">4096 instructions", "5.2", func() error { +var haveLargeInstructions = internal.NewFeatureTest(">4096 instructions", func() error { const maxInsns = 4096 insns := make(asm.Instructions, maxInsns, maxInsns+1) @@ -29,7 +29,7 @@ var haveLargeInstructions = internal.NewFeatureTest(">4096 instructions", "5.2", Type: ebpf.SocketFilter, Instructions: insns, }) -}) +}, "5.2") // HaveBoundedLoops probes the running kernel if bounded loops are supported. // @@ -40,7 +40,7 @@ func HaveBoundedLoops() error { return haveBoundedLoops() } -var haveBoundedLoops = internal.NewFeatureTest("bounded loops", "5.3", func() error { +var haveBoundedLoops = internal.NewFeatureTest("bounded loops", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ @@ -50,7 +50,7 @@ var haveBoundedLoops = internal.NewFeatureTest("bounded loops", "5.3", func() er asm.Return(), }, }) -}) +}, "5.3") // HaveV2ISA probes the running kernel if instructions of the v2 ISA are supported. // @@ -61,7 +61,7 @@ func HaveV2ISA() error { return haveV2ISA() } -var haveV2ISA = internal.NewFeatureTest("v2 ISA", "4.14", func() error { +var haveV2ISA = internal.NewFeatureTest("v2 ISA", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ @@ -71,7 +71,7 @@ var haveV2ISA = internal.NewFeatureTest("v2 ISA", "4.14", func() error { asm.Return().WithSymbol("exit"), }, }) -}) +}, "4.14") // HaveV3ISA probes the running kernel if instructions of the v3 ISA are supported. // @@ -82,7 +82,7 @@ func HaveV3ISA() error { return haveV3ISA() } -var haveV3ISA = internal.NewFeatureTest("v3 ISA", "5.1", func() error { +var haveV3ISA = internal.NewFeatureTest("v3 ISA", func() error { return probeProgram(&ebpf.ProgramSpec{ Type: ebpf.SocketFilter, Instructions: asm.Instructions{ @@ -92,4 +92,4 @@ var haveV3ISA = internal.NewFeatureTest("v3 ISA", "5.1", func() error { asm.Return().WithSymbol("exit"), }, }) -}) +}, "5.1") diff --git a/info.go b/info.go index 9bb67b1e9..3652fd779 100644 --- a/info.go +++ b/info.go @@ -644,7 +644,7 @@ func EnableStats(which uint32) (io.Closer, error) { return fd, nil } -var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", "4.15", func() error { +var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", func() error { prog, err := progLoad(asm.Instructions{ asm.LoadImm(asm.R0, 0, asm.DWord), asm.Return(), @@ -669,4 +669,4 @@ var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", " } return err -}) +}, "4.15") diff --git a/internal/feature.go b/internal/feature.go index 2b856c735..6399be085 100644 --- a/internal/feature.go +++ b/internal/feature.go @@ -3,15 +3,25 @@ package internal import ( "errors" "fmt" + "runtime" + "strings" "sync" ) -// ErrNotSupported indicates that a feature is not supported by the current kernel. +// ErrNotSupported indicates that a feature is not supported. var ErrNotSupported = errors.New("not supported") +// ErrNotSupportedOnOS indicates that a feature is not supported on the current +// operating system. +var ErrNotSupportedOnOS = fmt.Errorf("%w on %s", ErrNotSupported, runtime.GOOS) + // UnsupportedFeatureError is returned by FeatureTest() functions. type UnsupportedFeatureError struct { - // The minimum Linux mainline version required for this feature. + // The minimum version required for this feature. + // + // On Linux this refers to the mainline kernel version, on other platforms + // to the version of the runtime. + // // Used for the error string, and for sanity checking during testing. MinimumVersion Version @@ -58,11 +68,44 @@ type FeatureTest struct { type FeatureTestFn func() error // NewFeatureTest is a convenient way to create a single [FeatureTest]. -func NewFeatureTest(name, version string, fn FeatureTestFn) func() error { +// +// versions specifies in which version of a BPF runtime a feature appeared. +// The format is "GOOS:Major.Minor[.Patch]". GOOS may be omitted when targeting +// Linux. Returns [ErrNotSupportedOnOS] if there is no version specified for the +// current OS. +func NewFeatureTest(name string, fn FeatureTestFn, versions ...string) func() error { + const nativePrefix = runtime.GOOS + ":" + + if len(versions) == 0 { + return func() error { + return fmt.Errorf("feature test %q: no versions specified", name) + } + } + ft := &FeatureTest{ - Name: name, - Version: version, - Fn: fn, + Name: name, + Fn: fn, + } + + for _, version := range versions { + if strings.HasPrefix(version, nativePrefix) { + ft.Version = strings.TrimPrefix(version, nativePrefix) + break + } + + if runtime.GOOS == "linux" && !strings.ContainsRune(version, ':') { + // Allow version numbers without a GOOS prefix on Linux. + ft.Version = version + break + } + } + + if ft.Version == "" { + return func() error { + // We don't return an UnsupportedFeatureError here, since that will + // trigger version checks which don't make sense. + return fmt.Errorf("%s: %w", name, ErrNotSupportedOnOS) + } } return ft.execute diff --git a/internal/feature_test.go b/internal/feature_test.go index f477819ed..cd57eb464 100644 --- a/internal/feature_test.go +++ b/internal/feature_test.go @@ -2,9 +2,12 @@ package internal import ( "errors" + "runtime" "strings" "testing" + "github.com/go-quicktest/qt" + "github.com/cilium/ebpf/internal/testutils/fdtrace" ) @@ -15,27 +18,30 @@ func TestMain(m *testing.M) { func TestFeatureTest(t *testing.T) { var called bool - fn := NewFeatureTest("foo", "1.0", func() error { + fn := NewFeatureTest("foo", func() error { called = true return nil - }) + }, "1.0") if called { t.Error("Function was called too early") } err := fn() - if !called { - t.Error("Function wasn't called") + if errors.Is(err, ErrNotSupportedOnOS) { + qt.Assert(t, qt.IsFalse(called)) + return } + qt.Assert(t, qt.IsTrue(called), qt.Commentf("function should be invoked")) + if err != nil { t.Error("Unexpected negative result:", err) } - fn = NewFeatureTest("bar", "2.1.1", func() error { + fn = NewFeatureTest("bar", func() error { return ErrNotSupported - }) + }, "2.1.1") err = fn() if err == nil { @@ -60,12 +66,24 @@ func TestFeatureTest(t *testing.T) { t.Error("Didn't cache an error wrapping ErrNotSupported") } - fn = NewFeatureTest("bar", "2.1.1", func() error { + fn = NewFeatureTest("bar", func() error { return errors.New("foo") - }) + }, "2.1.1") err1, err2 := fn(), fn() if err1 == err2 { t.Error("Cached result of unsuccessful execution") } } + +func TestFeatureTestNotSupportedOnOS(t *testing.T) { + sentinel := errors.New("quux") + fn := func() error { return sentinel } + + qt.Assert(t, qt.IsNotNil(NewFeatureTest("foo", fn)())) + qt.Assert(t, qt.ErrorIs(NewFeatureTest("foo", fn, "froz:1.0.0")(), ErrNotSupportedOnOS)) + qt.Assert(t, qt.ErrorIs(NewFeatureTest("foo", fn, runtime.GOOS+":1.0")(), sentinel)) + if runtime.GOOS == "linux" { + qt.Assert(t, qt.ErrorIs(NewFeatureTest("foo", fn, "1.0")(), sentinel)) + } +} diff --git a/internal/testutils/feature.go b/internal/testutils/feature.go index 75edcd124..e3da03949 100644 --- a/internal/testutils/feature.go +++ b/internal/testutils/feature.go @@ -11,7 +11,7 @@ import ( ) const ( - ignoreKernelVersionEnvVar = "EBPF_TEST_IGNORE_KERNEL_VERSION" + ignoreVersionEnvVar = "EBPF_TEST_IGNORE_VERSION" ) func CheckFeatureTest(t *testing.T, fn func() error) { @@ -25,7 +25,7 @@ func checkFeatureTestError(t *testing.T, err error) { var ufe *internal.UnsupportedFeatureError if errors.As(err, &ufe) { - checkKernelVersion(t, ufe) + checkVersion(t, ufe) } else { t.Error("Feature test failed:", err) } @@ -50,7 +50,7 @@ func SkipIfNotSupported(tb testing.TB, err error) { var ufe *internal.UnsupportedFeatureError if errors.As(err, &ufe) { - checkKernelVersion(tb, ufe) + checkVersion(tb, ufe) tb.Skip(ufe.Error()) } if errors.Is(err, internal.ErrNotSupported) { @@ -58,15 +58,28 @@ func SkipIfNotSupported(tb testing.TB, err error) { } } -func checkKernelVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) { +func SkipIfNotSupportedOnOS(tb testing.TB, err error) { + tb.Helper() + + if err == internal.ErrNotSupportedOnOS { + tb.Fatal("Unwrapped ErrNotSupportedOnOS") + } + + if errors.Is(err, internal.ErrNotSupportedOnOS) { + tb.Skip(err.Error()) + } +} + +func checkVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) { if ufe.MinimumVersion.Unspecified() { return } tb.Helper() - if ignoreKernelVersionCheck(tb.Name()) { - tb.Skipf("Ignoring error due to %s: %s", ignoreKernelVersionEnvVar, ufe.Error()) + if ignoreVersionCheck(tb.Name()) { + tb.Logf("Ignoring error due to %s: %s", ignoreVersionEnvVar, ufe.Error()) + return } if !isKernelLessThan(tb, ufe.MinimumVersion) { @@ -121,12 +134,15 @@ func kernelVersion(tb testing.TB) internal.Version { return v } -// ignoreKernelVersionCheck checks if test name should be ignored for kernel version check by checking against environment var EBPF_TEST_IGNORE_KERNEL_VERSION. -// EBPF_TEST_IGNORE_KERNEL_VERSION is a comma (,) separated list of test names for which kernel version check should be ignored. +// ignoreVersionCheck checks whether to omit the version check for a test. +// +// It reads a comma separated list of test names from an environment variable. +// +// For example: // -// eg: EBPF_TEST_IGNORE_KERNEL_VERSION=TestABC,TestXYZ -func ignoreKernelVersionCheck(tName string) bool { - tNames := os.Getenv(ignoreKernelVersionEnvVar) +// EBPF_TEST_IGNORE_VERSION=TestABC,TestXYZ go test ... +func ignoreVersionCheck(tName string) bool { + tNames := os.Getenv(ignoreVersionEnvVar) if tNames == "" { return false } diff --git a/internal/testutils/feature_test.go b/internal/testutils/feature_test.go index 71432cc49..d2e0a6def 100644 --- a/internal/testutils/feature_test.go +++ b/internal/testutils/feature_test.go @@ -44,9 +44,9 @@ func TestIgnoreKernelVersionCheckWhenEnvVarIsSet(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - t.Setenv(ignoreKernelVersionEnvVar, tt.toIgnoreNamesEnvValue) + t.Setenv(ignoreVersionEnvVar, tt.toIgnoreNamesEnvValue) - if got := ignoreKernelVersionCheck(tt.testName); got != tt.ignoreKernelVersionCheck { + if got := ignoreVersionCheck(tt.testName); got != tt.ignoreKernelVersionCheck { t.Errorf("ignoreKernelVersionCheck() = %v, want %v", got, tt.ignoreKernelVersionCheck) } }) diff --git a/link/kprobe_multi.go b/link/kprobe_multi.go index 77aa58645..094cb0538 100644 --- a/link/kprobe_multi.go +++ b/link/kprobe_multi.go @@ -149,7 +149,7 @@ func (kml *kprobeMultiLink) Info() (*Info, error) { }, nil } -var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5.18", func() error { +var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Name: "probe_kpm_link", Type: ebpf.Kprobe, @@ -188,4 +188,4 @@ var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5 fd.Close() return nil -}) +}, "5.18") diff --git a/link/perf_event.go b/link/perf_event.go index 675ddf91e..7440e8b29 100644 --- a/link/perf_event.go +++ b/link/perf_event.go @@ -303,7 +303,7 @@ func openTracepointPerfEvent(tid uint64, pid int) (*sys.FD, error) { // // https://elixir.bootlin.com/linux/v5.16.8/source/kernel/bpf/syscall.c#L4307 // https://github.com/torvalds/linux/commit/b89fbfbb854c9afc3047e8273cc3a694650b802e -var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", "5.15", func() error { +var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Name: "probe_bpf_perf_link", Type: ebpf.Kprobe, @@ -329,4 +329,4 @@ var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", "5.15" return nil } return err -}) +}, "5.15") diff --git a/link/syscalls.go b/link/syscalls.go index d09b5acb0..25951b017 100644 --- a/link/syscalls.go +++ b/link/syscalls.go @@ -30,7 +30,7 @@ const ( NetkitType = sys.BPF_LINK_TYPE_NETKIT ) -var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error { +var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Type: ebpf.CGroupSKB, License: "MIT", @@ -48,9 +48,9 @@ var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() e // have the syscall. prog.Close() return nil -}) +}, "4.10") -var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", "5.5", func() error { +var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", func() error { if err := haveProgAttach(); err != nil { return err } @@ -90,9 +90,9 @@ var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic repl return nil } return err -}) +}, "5.5") -var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error { +var haveBPFLink = internal.NewFeatureTest("bpf_link", func() error { attr := sys.LinkCreateAttr{ // This is a hopefully invalid file descriptor, which triggers EBADF. TargetFd: ^uint32(0), @@ -107,9 +107,9 @@ var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error { return nil } return err -}) +}, "5.7") -var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() error { +var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", func() error { attr := sys.ProgQueryAttr{ // We rely on this being checked during the syscall. // With an otherwise correct payload we expect EBADF here @@ -127,9 +127,9 @@ var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() err return ErrNotSupported } return errors.New("syscall succeeded unexpectedly") -}) +}, "4.15") -var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error { +var haveTCX = internal.NewFeatureTest("tcx", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Type: ebpf.SchedCLS, License: "MIT", @@ -162,9 +162,9 @@ var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error { return ErrNotSupported } return errors.New("syscall succeeded unexpectedly") -}) +}, "6.6") -var haveNetkit = internal.NewFeatureTest("netkit", "6.7", func() error { +var haveNetkit = internal.NewFeatureTest("netkit", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Type: ebpf.SchedCLS, License: "MIT", @@ -197,4 +197,4 @@ var haveNetkit = internal.NewFeatureTest("netkit", "6.7", func() error { return ErrNotSupported } return errors.New("syscall succeeded unexpectedly") -}) +}, "6.7") diff --git a/link/uprobe.go b/link/uprobe.go index 2cb185243..1852a3fad 100644 --- a/link/uprobe.go +++ b/link/uprobe.go @@ -16,7 +16,7 @@ var ( uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset" // elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799 uprobeRefCtrOffsetShift = 32 - haveRefCtrOffsetPMU = internal.NewFeatureTest("RefCtrOffsetPMU", "4.20", func() error { + haveRefCtrOffsetPMU = internal.NewFeatureTest("RefCtrOffsetPMU", func() error { _, err := os.Stat(uprobeRefCtrOffsetPMUPath) if errors.Is(err, os.ErrNotExist) { return internal.ErrNotSupported @@ -25,7 +25,7 @@ var ( return err } return nil - }) + }, "4.20") // ErrNoSymbol indicates that the given symbol was not found // in the ELF symbols table. diff --git a/link/uprobe_multi.go b/link/uprobe_multi.go index 53f463fe3..49dc18b44 100644 --- a/link/uprobe_multi.go +++ b/link/uprobe_multi.go @@ -175,7 +175,7 @@ func (kml *uprobeMultiLink) Update(_ *ebpf.Program) error { return fmt.Errorf("update uprobe_multi: %w", ErrNotSupported) } -var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6.6", func() error { +var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Name: "probe_upm_link", Type: ebpf.Kprobe, @@ -216,4 +216,4 @@ var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6 // should not happen fd.Close() return errors.New("successfully attached uprobe_multi to /, kernel bug?") -}) +}, "6.6") diff --git a/prog.go b/prog.go index 697ff9f4f..0525196d5 100644 --- a/prog.go +++ b/prog.go @@ -733,7 +733,7 @@ func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.D return ret, total, nil } -var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error { +var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", func() error { prog, err := NewProgram(&ProgramSpec{ // SocketFilter does not require privileges on newer kernels. Type: SocketFilter, @@ -775,7 +775,7 @@ var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error { } return err -}) +}, "4.12") func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) { if uint(len(opts.Data)) > math.MaxUint32 { diff --git a/syscalls.go b/syscalls.go index 0766e7dd6..9eac66150 100644 --- a/syscalls.go +++ b/syscalls.go @@ -60,7 +60,7 @@ func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, }) } -var haveNestedMaps = internal.NewFeatureTest("nested maps", "4.12", func() error { +var haveNestedMaps = internal.NewFeatureTest("nested maps", func() error { _, err := sys.MapCreate(&sys.MapCreateAttr{ MapType: sys.MapType(ArrayOfMaps), KeySize: 4, @@ -76,9 +76,9 @@ var haveNestedMaps = internal.NewFeatureTest("nested maps", "4.12", func() error return nil } return err -}) +}, "4.12") -var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only maps", "5.2", func() error { +var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only maps", func() error { // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check. m, err := sys.MapCreate(&sys.MapCreateAttr{ @@ -93,9 +93,9 @@ var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only m } _ = m.Close() return nil -}) +}, "5.2") -var haveMmapableMaps = internal.NewFeatureTest("mmapable maps", "5.5", func() error { +var haveMmapableMaps = internal.NewFeatureTest("mmapable maps", func() error { // This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps. m, err := sys.MapCreate(&sys.MapCreateAttr{ MapType: sys.MapType(Array), @@ -109,9 +109,9 @@ var haveMmapableMaps = internal.NewFeatureTest("mmapable maps", "5.5", func() er } _ = m.Close() return nil -}) +}, "5.5") -var haveInnerMaps = internal.NewFeatureTest("inner maps", "5.10", func() error { +var haveInnerMaps = internal.NewFeatureTest("inner maps", func() error { // This checks BPF_F_INNER_MAP, which appeared in 5.10. m, err := sys.MapCreate(&sys.MapCreateAttr{ MapType: sys.MapType(Array), @@ -126,9 +126,9 @@ var haveInnerMaps = internal.NewFeatureTest("inner maps", "5.10", func() error { } _ = m.Close() return nil -}) +}, "5.10") -var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", "4.6", func() error { +var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", func() error { // This checks BPF_F_NO_PREALLOC, which appeared in 4.6. m, err := sys.MapCreate(&sys.MapCreateAttr{ MapType: sys.MapType(Hash), @@ -143,7 +143,7 @@ var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", "4.6", func() } _ = m.Close() return nil -}) +}, "4.6") func wrapMapError(err error) error { if err == nil { @@ -169,7 +169,7 @@ func wrapMapError(err error) error { return err } -var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error { +var haveObjName = internal.NewFeatureTest("object names", func() error { attr := sys.MapCreateAttr{ MapType: sys.MapType(Array), KeySize: 4, @@ -185,9 +185,9 @@ var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error { _ = fd.Close() return nil -}) +}, "4.15") -var objNameAllowsDot = internal.NewFeatureTest("dot in object names", "5.2", func() error { +var objNameAllowsDot = internal.NewFeatureTest("dot in object names", func() error { if err := haveObjName(); err != nil { return err } @@ -207,9 +207,9 @@ var objNameAllowsDot = internal.NewFeatureTest("dot in object names", "5.2", fun _ = fd.Close() return nil -}) +}, "5.2") -var haveBatchAPI = internal.NewFeatureTest("map batch api", "5.6", func() error { +var haveBatchAPI = internal.NewFeatureTest("map batch api", func() error { var maxEntries uint32 = 2 attr := sys.MapCreateAttr{ MapType: sys.MapType(Hash), @@ -239,9 +239,9 @@ var haveBatchAPI = internal.NewFeatureTest("map batch api", "5.6", func() error return internal.ErrNotSupported } return nil -}) +}, "5.6") -var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", "5.5", func() error { +var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", func() error { insns := asm.Instructions{ asm.Mov.Reg(asm.R1, asm.R10), asm.Add.Imm(asm.R1, -8), @@ -257,9 +257,9 @@ var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", "5.5" } _ = fd.Close() return nil -}) +}, "5.5") -var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", "4.16", func() error { +var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", func() error { insns := asm.Instructions{ asm.Call.Label("prog2").WithSymbol("prog1"), asm.Return(), @@ -273,9 +273,9 @@ var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", "4.16", func() } _ = fd.Close() return nil -}) +}, "4.16") -var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func() error { +var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", func() error { prefix := internal.PlatformPrefix() if prefix == "" { return fmt.Errorf("unable to find the platform prefix for (%s)", runtime.GOARCH) @@ -302,9 +302,9 @@ var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func } return evt.Close() -}) +}, "4.17") -var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", func() error { +var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", func() error { insns := asm.Instructions{ asm.Mov.Imm(asm.R0, 0), asm.Return(), @@ -334,4 +334,4 @@ var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", fu } return err -}) +}, "5.0")