diff --git a/btf/core_reloc_test.go b/btf/core_reloc_test.go index 32737be42..20e86d984 100644 --- a/btf/core_reloc_test.go +++ b/btf/core_reloc_test.go @@ -13,126 +13,111 @@ import ( ) func TestCORERelocationLoad(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/relocs-*.elf"), func(t *testing.T, file string) { - fh, err := os.Open(file) - if err != nil { - t.Fatal(err) - } - defer fh.Close() - - spec, err := ebpf.LoadCollectionSpecFromReader(fh) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - for _, progSpec := range spec.Programs { - t.Run(progSpec.Name, func(t *testing.T) { - if _, err := fh.Seek(0, io.SeekStart); err != nil { - t.Fatal(err) - } - - prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ - KernelTypes: spec.Types, - }) - testutils.SkipIfNotSupported(t, err) - - if strings.HasPrefix(progSpec.Name, "err_") { - if err == nil { - prog.Close() - t.Fatal("Expected an error") - } - t.Log("Got expected error:", err) - return - } - - if err != nil { - t.Fatal("Load program:", err) - } - defer prog.Close() - - ret, _, err := prog.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Error when running:", err) - } + file := testutils.NativeFile(t, "testdata/relocs-%s.elf") + fh, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + defer fh.Close() + + spec, err := ebpf.LoadCollectionSpecFromReader(fh) + if err != nil { + t.Fatal(err) + } + + for _, progSpec := range spec.Programs { + t.Run(progSpec.Name, func(t *testing.T) { + if _, err := fh.Seek(0, io.SeekStart); err != nil { + t.Fatal(err) + } + + prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ + KernelTypes: spec.Types, + }) + testutils.SkipIfNotSupported(t, err) - if ret != 0 { - t.Error("Assertion failed on line", ret) + if strings.HasPrefix(progSpec.Name, "err_") { + if err == nil { + prog.Close() + t.Fatal("Expected an error") } - }) - } - }) + t.Log("Got expected error:", err) + return + } + + if err != nil { + t.Fatal("Load program:", err) + } + defer prog.Close() + + ret, _, err := prog.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Error when running:", err) + } + + if ret != 0 { + t.Error("Assertion failed on line", ret) + } + }) + } } func TestCORERelocationRead(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/relocs_read-*.elf"), func(t *testing.T, file string) { - spec, err := ebpf.LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - targetFile := testutils.NativeFile(t, "testdata/relocs_read_tgt-%s.elf") - targetSpec, err := btf.LoadSpec(targetFile) - if err != nil { - t.Fatal(err) - } - - for _, progSpec := range spec.Programs { - t.Run(progSpec.Name, func(t *testing.T) { - prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ - KernelTypes: targetSpec, - }) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Load program:", err) - } - defer prog.Close() - - ret, _, err := prog.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Error when running:", err) - } - - if ret != 0 { - t.Error("Assertion failed on line", ret) - } + file := testutils.NativeFile(t, "testdata/relocs_read-%s.elf") + spec, err := ebpf.LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } + + targetFile := testutils.NativeFile(t, "testdata/relocs_read_tgt-%s.elf") + targetSpec, err := btf.LoadSpec(targetFile) + if err != nil { + t.Fatal(err) + } + + for _, progSpec := range spec.Programs { + t.Run(progSpec.Name, func(t *testing.T) { + prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ + KernelTypes: targetSpec, }) - } - }) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Load program:", err) + } + defer prog.Close() + + ret, _, err := prog.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Error when running:", err) + } + + if ret != 0 { + t.Error("Assertion failed on line", ret) + } + }) + } } func TestLD64IMMReloc(t *testing.T) { testutils.SkipOnOldKernel(t, "5.4", "vmlinux BTF in sysfs") - testutils.Files(t, testutils.Glob(t, "testdata/relocs_enum-*.elf"), func(t *testing.T, file string) { - fh, err := os.Open(file) - if err != nil { - t.Fatal(err) - } - defer fh.Close() - - spec, err := ebpf.LoadCollectionSpecFromReader(fh) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - coll, err := ebpf.NewCollection(spec) - if err != nil { - t.Fatal(err) - } - defer coll.Close() - }) + file := testutils.NativeFile(t, "testdata/relocs_enum-%s.elf") + fh, err := os.Open(file) + if err != nil { + t.Fatal(err) + } + defer fh.Close() + + spec, err := ebpf.LoadCollectionSpecFromReader(fh) + if err != nil { + t.Fatal(err) + } + + coll, err := ebpf.NewCollection(spec) + if err != nil { + t.Fatal(err) + } + defer coll.Close() } diff --git a/elf_reader_test.go b/elf_reader_test.go index d77463bfa..3ba38e6dc 100644 --- a/elf_reader_test.go +++ b/elf_reader_test.go @@ -343,34 +343,32 @@ func TestCollectionSpecDetach(t *testing.T) { } func TestLoadInvalidMap(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/invalid_map-*.elf"), func(t *testing.T, file string) { - cs, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't load CollectionSpec", err) - } + file := testutils.NativeFile(t, "testdata/invalid_map-%s.elf") + cs, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't load CollectionSpec", err) + } - ms, ok := cs.Maps["invalid_map"] - if !ok { - t.Fatal("invalid_map not found in CollectionSpec") - } + ms, ok := cs.Maps["invalid_map"] + if !ok { + t.Fatal("invalid_map not found in CollectionSpec") + } - m, err := NewMap(ms) - t.Log(err) - if err == nil { - m.Close() - t.Fatal("Creating a Map from a MapSpec with non-zero Extra is expected to fail.") - } - }) + m, err := NewMap(ms) + t.Log(err) + if err == nil { + m.Close() + t.Fatal("Creating a Map from a MapSpec with non-zero Extra is expected to fail.") + } } func TestLoadInvalidMapMissingSymbol(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/invalid_map_static-el.elf"), func(t *testing.T, file string) { - _, err := LoadCollectionSpec(file) - t.Log(err) - if err == nil { - t.Fatal("Loading a map with static qualifier should fail") - } - }) + file := testutils.NativeFile(t, "testdata/invalid_map_static-%s.elf") + _, err := LoadCollectionSpec(file) + t.Log(err) + if err == nil { + t.Fatal("Loading a map with static qualifier should fail") + } } func TestLoadInitializedBTFMap(t *testing.T) { @@ -460,13 +458,12 @@ func TestLoadInitializedBTFMap(t *testing.T) { } func TestLoadInvalidInitializedBTFMap(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/invalid_btf_map_init-*.elf"), func(t *testing.T, file string) { - _, err := LoadCollectionSpec(file) - t.Log(err) - if !errors.Is(err, internal.ErrNotSupported) { - t.Fatal("Loading an initialized BTF map should be unsupported") - } - }) + file := testutils.NativeFile(t, "testdata/invalid_btf_map_init-%s.elf") + _, err := LoadCollectionSpec(file) + t.Log(err) + if !errors.Is(err, internal.ErrNotSupported) { + t.Fatal("Loading an initialized BTF map should be unsupported") + } } func TestStringSection(t *testing.T) { @@ -531,250 +528,215 @@ func TestStringSection(t *testing.T) { func TestLoadRawTracepoint(t *testing.T) { testutils.SkipOnOldKernel(t, "4.17", "BPF_RAW_TRACEPOINT API") - testutils.Files(t, testutils.Glob(t, "testdata/raw_tracepoint-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - coll, err := NewCollectionWithOptions(spec, CollectionOptions{ - Programs: ProgramOptions{ - LogLevel: LogLevelBranch, - }, - }) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Can't create collection:", err) - } + file := testutils.NativeFile(t, "testdata/raw_tracepoint-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } - coll.Close() + coll, err := NewCollectionWithOptions(spec, CollectionOptions{ + Programs: ProgramOptions{ + LogLevel: LogLevelBranch, + }, }) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Can't create collection:", err) + } + + coll.Close() } func TestTailCall(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/btf_map_init-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - TailMain *Program `ebpf:"tail_main"` - ProgArray *Map `ebpf:"prog_array_init"` - } + var obj struct { + TailMain *Program `ebpf:"tail_main"` + ProgArray *Map `ebpf:"prog_array_init"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } - defer obj.TailMain.Close() - defer obj.ProgArray.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } + defer obj.TailMain.Close() + defer obj.ProgArray.Close() - ret, _, err := obj.TailMain.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.TailMain.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - // Expect the tail_1 tail call to be taken, returning value 42. - if ret != 42 { - t.Fatalf("Expected tail call to return value 42, got %d", ret) - } - }) + // Expect the tail_1 tail call to be taken, returning value 42. + if ret != 42 { + t.Fatalf("Expected tail call to return value 42, got %d", ret) + } } func TestKconfigKernelVersion(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/kconfig-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kconfig-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"kernel_version"` - } + var obj struct { + Main *Program `ebpf:"kernel_version"` + } - testutils.SkipOnOldKernel(t, "5.2", "readonly maps") + testutils.SkipOnOldKernel(t, "5.2", "readonly maps") - err = spec.LoadAndAssign(&obj, nil) - if err != nil { - t.Fatal(err) - } - defer obj.Main.Close() + err = spec.LoadAndAssign(&obj, nil) + if err != nil { + t.Fatal(err) + } + defer obj.Main.Close() - ret, _, err := obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - v, err := internal.KernelVersion() - if err != nil { - t.Fatalf("getting kernel version: %s", err) - } + v, err := internal.KernelVersion() + if err != nil { + t.Fatalf("getting kernel version: %s", err) + } - version := v.Kernel() - if ret != version { - t.Fatalf("Expected eBPF to return value %d, got %d", version, ret) - } - }) + version := v.Kernel() + if ret != version { + t.Fatalf("Expected eBPF to return value %d, got %d", version, ret) + } } func TestKconfigSyscallWrapper(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/kconfig-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kconfig-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"syscall_wrapper"` - } + var obj struct { + Main *Program `ebpf:"syscall_wrapper"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } - defer obj.Main.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } + defer obj.Main.Close() - ret, _, err := obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - var expected uint32 - if testutils.IsKernelLessThan(t, "4.17") { - expected = 0 - } else { - expected = 1 - } + var expected uint32 + if testutils.IsKernelLessThan(t, "4.17") { + expected = 0 + } else { + expected = 1 + } - if ret != expected { - t.Fatalf("Expected eBPF to return value %d, got %d", expected, ret) - } - }) + if ret != expected { + t.Fatalf("Expected eBPF to return value %d, got %d", expected, ret) + } } func TestKconfigConfig(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/kconfig_config-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kconfig_config-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"kconfig"` - ArrayMap *Map `ebpf:"array_map"` - } + var obj struct { + Main *Program `ebpf:"kconfig"` + ArrayMap *Map `ebpf:"array_map"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } - defer obj.Main.Close() - defer obj.ArrayMap.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } + defer obj.Main.Close() + defer obj.ArrayMap.Close() - _, _, err = obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + _, _, err = obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - var value uint64 - err = obj.ArrayMap.Lookup(uint32(0), &value) - if err != nil { - t.Fatal(err) - } + var value uint64 + err = obj.ArrayMap.Lookup(uint32(0), &value) + if err != nil { + t.Fatal(err) + } - // CONFIG_HZ must have a value. - qt.Assert(t, qt.Not(qt.Equals(value, 0))) - }) + // CONFIG_HZ must have a value. + qt.Assert(t, qt.Not(qt.Equals(value, 0))) } func TestKfunc(t *testing.T) { testutils.SkipOnOldKernel(t, "5.18", "kfunc support") - testutils.Files(t, testutils.Glob(t, "testdata/kfunc-e*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kfunc-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"call_kfunc"` - } + var obj struct { + Main *Program `ebpf:"call_kfunc"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatalf("%+v", err) - } - defer obj.Main.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatalf("%+v", err) + } + defer obj.Main.Close() - ret, _, err := obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - if ret != 1 { - t.Fatalf("Expected kfunc to return value 1, got %d", ret) - } - }) + if ret != 1 { + t.Fatalf("Expected kfunc to return value 1, got %d", ret) + } } func TestWeakKfunc(t *testing.T) { testutils.SkipOnOldKernel(t, "5.18", "kfunc support") - testutils.Files(t, testutils.Glob(t, "testdata/kfunc-e*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kfunc-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Missing *Program `ebpf:"weak_kfunc_missing"` - Calling *Program `ebpf:"call_weak_kfunc"` - } + var obj struct { + Missing *Program `ebpf:"weak_kfunc_missing"` + Calling *Program `ebpf:"call_weak_kfunc"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatalf("%+v", err) - } - defer obj.Missing.Close() - defer obj.Calling.Close() - }) + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatalf("%+v", err) + } + defer obj.Missing.Close() + defer obj.Calling.Close() } func TestInvalidKfunc(t *testing.T) { @@ -804,164 +766,144 @@ func TestKfuncKmod(t *testing.T) { t.Skip("bpf_testmod not loaded") } - testutils.Files(t, testutils.Glob(t, "testdata/kfunc-kmod-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/kfunc-kmod-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"call_kfunc"` - } + var obj struct { + Main *Program `ebpf:"call_kfunc"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatalf("%v+", err) - } - defer obj.Main.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatalf("%v+", err) + } + defer obj.Main.Close() - ret, _, err := obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - if ret != 1 { - t.Fatalf("Expected kfunc to return value 1, got %d", ret) - } - }) + if ret != 1 { + t.Fatalf("Expected kfunc to return value 1, got %d", ret) + } } func TestSubprogRelocation(t *testing.T) { testutils.SkipOnOldKernel(t, "5.13", "bpf_for_each_map_elem") - testutils.Files(t, testutils.Glob(t, "testdata/subprog_reloc-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/subprog_reloc-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - var obj struct { - Main *Program `ebpf:"fp_relocation"` - HashMap *Map `ebpf:"hash_map"` - } + var obj struct { + Main *Program `ebpf:"fp_relocation"` + HashMap *Map `ebpf:"hash_map"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } - defer obj.Main.Close() - defer obj.HashMap.Close() + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } + defer obj.Main.Close() + defer obj.HashMap.Close() - ret, _, err := obj.Main.Test(internal.EmptyBPFContext) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal(err) - } + ret, _, err := obj.Main.Test(internal.EmptyBPFContext) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal(err) + } - if ret != 42 { - t.Fatalf("Expected subprog reloc to return value 42, got %d", ret) - } - }) + if ret != 42 { + t.Fatalf("Expected subprog reloc to return value 42, got %d", ret) + } } func TestUnassignedProgArray(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/btf_map_init-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/btf_map_init-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - // tail_main references a ProgArray that is not being assigned - // to this struct. Normally, this would clear all its entries - // and make any tail calls into the ProgArray result in a miss. - // The library needs to explicitly refuse such operations. - var obj struct { - TailMain *Program `ebpf:"tail_main"` - // ProgArray *Map `ebpf:"prog_array_init"` - } + // tail_main references a ProgArray that is not being assigned + // to this struct. Normally, this would clear all its entries + // and make any tail calls into the ProgArray result in a miss. + // The library needs to explicitly refuse such operations. + var obj struct { + TailMain *Program `ebpf:"tail_main"` + // ProgArray *Map `ebpf:"prog_array_init"` + } - err = spec.LoadAndAssign(&obj, nil) - testutils.SkipIfNotSupported(t, err) - if err == nil { - obj.TailMain.Close() - t.Fatal("Expecting LoadAndAssign to return error") - } - }) + err = spec.LoadAndAssign(&obj, nil) + testutils.SkipIfNotSupported(t, err) + if err == nil { + obj.TailMain.Close() + t.Fatal("Expecting LoadAndAssign to return error") + } } func TestIPRoute2Compat(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/iproute2_map_compat-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - ms, ok := spec.Maps["hash_map"] - if !ok { - t.Fatal("Map hash_map not found") - } + file := testutils.NativeFile(t, "testdata/iproute2_map_compat-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } - var id, pinning, innerID, innerIndex uint32 + ms, ok := spec.Maps["hash_map"] + if !ok { + t.Fatal("Map hash_map not found") + } - if ms.Extra == nil { - t.Fatal("missing extra bytes") - } + var id, pinning, innerID, innerIndex uint32 - switch { - case binary.Read(ms.Extra, spec.ByteOrder, &id) != nil: - t.Fatal("missing id") - case binary.Read(ms.Extra, spec.ByteOrder, &pinning) != nil: - t.Fatal("missing pinning") - case binary.Read(ms.Extra, spec.ByteOrder, &innerID) != nil: - t.Fatal("missing inner_id") - case binary.Read(ms.Extra, spec.ByteOrder, &innerIndex) != nil: - t.Fatal("missing inner_idx") - } + if ms.Extra == nil { + t.Fatal("missing extra bytes") + } - if id != 0 || innerID != 0 || innerIndex != 0 { - t.Fatal("expecting id, inner_id and inner_idx to be zero") - } + switch { + case binary.Read(ms.Extra, spec.ByteOrder, &id) != nil: + t.Fatal("missing id") + case binary.Read(ms.Extra, spec.ByteOrder, &pinning) != nil: + t.Fatal("missing pinning") + case binary.Read(ms.Extra, spec.ByteOrder, &innerID) != nil: + t.Fatal("missing inner_id") + case binary.Read(ms.Extra, spec.ByteOrder, &innerIndex) != nil: + t.Fatal("missing inner_idx") + } - if pinning != 2 { - t.Fatal("expecting pinning field to be 2 (PIN_GLOBAL_NS)") - } + if id != 0 || innerID != 0 || innerIndex != 0 { + t.Fatal("expecting id, inner_id and inner_idx to be zero") + } - // iproute2 (tc) pins maps in /sys/fs/bpf/tc/globals with PIN_GLOBAL_NS, - // which needs to be be configured in this library using MapOptions.PinPath. - // For the sake of the test, we use a tempdir on bpffs below. - ms.Pinning = PinByName + if pinning != 2 { + t.Fatal("expecting pinning field to be 2 (PIN_GLOBAL_NS)") + } - coll, err := NewCollectionWithOptions(spec, CollectionOptions{ - Maps: MapOptions{ - PinPath: testutils.TempBPFFS(t), - }, - }) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Can't create collection:", err) - } + // iproute2 (tc) pins maps in /sys/fs/bpf/tc/globals with PIN_GLOBAL_NS, + // which needs to be be configured in this library using MapOptions.PinPath. + // For the sake of the test, we use a tempdir on bpffs below. + ms.Pinning = PinByName - coll.Close() + coll, err := NewCollectionWithOptions(spec, CollectionOptions{ + Maps: MapOptions{ + PinPath: testutils.TempBPFFS(t), + }, }) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Can't create collection:", err) + } + + coll.Close() } var ( diff --git a/link/tracing_test.go b/link/tracing_test.go index a70f23225..f9fd16fce 100644 --- a/link/tracing_test.go +++ b/link/tracing_test.go @@ -4,47 +4,41 @@ import ( "testing" "github.com/cilium/ebpf" - "github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/testutils" ) func TestFreplace(t *testing.T) { testutils.SkipOnOldKernel(t, "5.10", "freplace") - testutils.Files(t, testutils.Glob(t, "../testdata/freplace-*.elf"), func(t *testing.T, file string) { - spec, err := ebpf.LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - - if spec.ByteOrder != internal.NativeEndian { - return - } - - target, err := ebpf.NewProgram(spec.Programs["sched_process_exec"]) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Can't create target program:", err) - } - defer target.Close() - - // Test attachment specified at load time - spec.Programs["replacement"].AttachTarget = target - replacement, err := ebpf.NewProgram(spec.Programs["replacement"]) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Can't create replacement program:", err) - } - defer replacement.Close() - - freplace, err := AttachFreplace(nil, "", replacement) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatal("Can't create freplace:", err) - } - - testLink(t, freplace, replacement) - }) + file := testutils.NativeFile(t, "../testdata/freplace-%s.elf") + spec, err := ebpf.LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } + + target, err := ebpf.NewProgram(spec.Programs["sched_process_exec"]) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Can't create target program:", err) + } + defer target.Close() + + // Test attachment specified at load time + spec.Programs["replacement"].AttachTarget = target + replacement, err := ebpf.NewProgram(spec.Programs["replacement"]) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Can't create replacement program:", err) + } + defer replacement.Close() + + freplace, err := AttachFreplace(nil, "", replacement) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatal("Can't create freplace:", err) + } + + testLink(t, freplace, replacement) } func TestFentryFexit(t *testing.T) { diff --git a/linker_test.go b/linker_test.go index e75c50c8b..39b01cf65 100644 --- a/linker_test.go +++ b/linker_test.go @@ -59,56 +59,51 @@ func TestFindReferences(t *testing.T) { } func TestForwardFunctionDeclaration(t *testing.T) { - testutils.Files(t, testutils.Glob(t, "testdata/fwd_decl-*.elf"), func(t *testing.T, file string) { - coll, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal(err) - } - - if coll.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/fwd_decl-%s.elf") + coll, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal(err) + } - spec := coll.Programs["call_fwd"] + spec := coll.Programs["call_fwd"] - // This program calls an unimplemented forward function declaration. - _, err = NewProgram(spec) - if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) { - t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err) - } + // This program calls an unimplemented forward function declaration. + _, err = NewProgram(spec) + if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) { + t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err) + } - // Append the implementation of fwd(). - spec.Instructions = append(spec.Instructions, - asm.Mov.Imm32(asm.R0, 23).WithSymbol("fwd"), - asm.Return(), - ) - - // The body of the subprog we appended does not come with BTF func_infos, - // so the verifier will reject it. Load without BTF. - for i, ins := range spec.Instructions { - if btf.FuncMetadata(&ins) != nil || ins.Source() != nil { - sym := ins.Symbol() - ref := ins.Reference() - ins.Metadata = asm.Metadata{} - spec.Instructions[i] = ins.WithSymbol(sym).WithReference(ref) - } + // Append the implementation of fwd(). + spec.Instructions = append(spec.Instructions, + asm.Mov.Imm32(asm.R0, 23).WithSymbol("fwd"), + asm.Return(), + ) + + // The body of the subprog we appended does not come with BTF func_infos, + // so the verifier will reject it. Load without BTF. + for i, ins := range spec.Instructions { + if btf.FuncMetadata(&ins) != nil || ins.Source() != nil { + sym := ins.Symbol() + ref := ins.Reference() + ins.Metadata = asm.Metadata{} + spec.Instructions[i] = ins.WithSymbol(sym).WithReference(ref) } + } - prog, err := NewProgram(spec) - testutils.SkipIfNotSupported(t, err) - if err != nil { - t.Fatalf("%+v", err) - } - defer prog.Close() + prog, err := NewProgram(spec) + testutils.SkipIfNotSupported(t, err) + if err != nil { + t.Fatalf("%+v", err) + } + defer prog.Close() - ret, _, err := prog.Test(internal.EmptyBPFContext) - if err != nil { - t.Fatal("Running program:", err) - } - if ret != 23 { - t.Fatalf("Expected 23, got %d", ret) - } - }) + ret, _, err := prog.Test(internal.EmptyBPFContext) + if err != nil { + t.Fatal("Running program:", err) + } + if ret != 23 { + t.Fatalf("Expected 23, got %d", ret) + } } func TestSplitSymbols(t *testing.T) { diff --git a/map_test.go b/map_test.go index be36721a8..673c1c32d 100644 --- a/map_test.go +++ b/map_test.go @@ -321,101 +321,106 @@ func TestMapClose(t *testing.T) { func TestBatchMapWithLock(t *testing.T) { testutils.SkipOnOldKernel(t, "5.13", "MAP BATCH BPF_F_LOCK") - testutils.Files(t, testutils.Glob(t, "./testdata/map_spin_lock-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/map_spin_lock-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } - coll, err := NewCollection(spec) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - defer coll.Close() + coll, err := NewCollection(spec) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } + defer coll.Close() - type spinLockValue struct { - Cnt uint32 - Padding uint32 - } + type spinLockValue struct { + Cnt uint32 + Padding uint32 + } - m, ok := coll.Maps["spin_lock_map"] - if !ok { - t.Fatal(err) - } + m, ok := coll.Maps["spin_lock_map"] + if !ok { + t.Fatal(err) + } - keys := []uint32{0, 1} - values := []spinLockValue{{Cnt: 42}, {Cnt: 4242}} - count, err := m.BatchUpdate(keys, values, &BatchOptions{ElemFlags: uint64(UpdateLock)}) - if err != nil { - t.Fatalf("BatchUpdate: %v", err) - } - if count != len(keys) { - t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys)) - } + keys := []uint32{0, 1} + values := []spinLockValue{{Cnt: 42}, {Cnt: 4242}} + count, err := m.BatchUpdate(keys, values, &BatchOptions{ElemFlags: uint64(UpdateLock)}) + if err != nil { + t.Fatalf("BatchUpdate: %v", err) + } + if count != len(keys) { + t.Fatalf("BatchUpdate: expected count, %d, to be %d", count, len(keys)) + } - var cursor MapBatchCursor - lookupKeys := make([]uint32, 2) - lookupValues := make([]spinLockValue, 2) - count, err = m.BatchLookup(&cursor, lookupKeys, lookupValues, &BatchOptions{ElemFlags: uint64(LookupLock)}) - if !errors.Is(err, ErrKeyNotExist) { - t.Fatalf("BatchLookup: %v", err) - } - if count != 2 { - t.Fatalf("BatchLookup: expected two keys, got %d", count) - } + var cursor MapBatchCursor + lookupKeys := make([]uint32, 2) + lookupValues := make([]spinLockValue, 2) + count, err = m.BatchLookup(&cursor, lookupKeys, lookupValues, &BatchOptions{ElemFlags: uint64(LookupLock)}) + if !errors.Is(err, ErrKeyNotExist) { + t.Fatalf("BatchLookup: %v", err) + } + if count != 2 { + t.Fatalf("BatchLookup: expected two keys, got %d", count) + } - cursor = MapBatchCursor{} - deleteKeys := []uint32{0, 1} - deleteValues := make([]spinLockValue, 2) - count, err = m.BatchLookupAndDelete(&cursor, deleteKeys, deleteValues, nil) - if !errors.Is(err, ErrKeyNotExist) { - t.Fatalf("BatchLookupAndDelete: %v", err) - } - if count != 2 { - t.Fatalf("BatchLookupAndDelete: expected two keys, got %d", count) - } - }) + cursor = MapBatchCursor{} + deleteKeys := []uint32{0, 1} + deleteValues := make([]spinLockValue, 2) + count, err = m.BatchLookupAndDelete(&cursor, deleteKeys, deleteValues, nil) + if !errors.Is(err, ErrKeyNotExist) { + t.Fatalf("BatchLookupAndDelete: %v", err) + } + if count != 2 { + t.Fatalf("BatchLookupAndDelete: expected two keys, got %d", count) + } } func TestMapWithLock(t *testing.T) { testutils.SkipOnOldKernel(t, "5.13", "MAP BPF_F_LOCK") - testutils.Files(t, testutils.Glob(t, "./testdata/map_spin_lock-*.elf"), func(t *testing.T, file string) { - spec, err := LoadCollectionSpec(file) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - if spec.ByteOrder != internal.NativeEndian { - return - } + file := testutils.NativeFile(t, "testdata/map_spin_lock-%s.elf") + spec, err := LoadCollectionSpec(file) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } - coll, err := NewCollection(spec) - if err != nil { - t.Fatal("Can't parse ELF:", err) - } - defer coll.Close() + coll, err := NewCollection(spec) + if err != nil { + t.Fatal("Can't parse ELF:", err) + } + defer coll.Close() - type spinLockValue struct { - Cnt uint32 - Padding uint32 - } + type spinLockValue struct { + Cnt uint32 + Padding uint32 + } - m, ok := coll.Maps["spin_lock_map"] - if !ok { - t.Fatal(err) - } + m, ok := coll.Maps["spin_lock_map"] + if !ok { + t.Fatal(err) + } - key := uint32(1) - value := spinLockValue{Cnt: 5} - err = m.Update(key, value, UpdateLock) - if err != nil { - t.Fatal(err) - } + key := uint32(1) + value := spinLockValue{Cnt: 5} + err = m.Update(key, value, UpdateLock) + if err != nil { + t.Fatal(err) + } + + value.Cnt = 0 + err = m.LookupWithFlags(&key, &value, LookupLock) + if err != nil { + t.Fatal(err) + } + if value.Cnt != 5 { + t.Fatalf("Want value 5, got %d", value.Cnt) + } + + t.Run("LookupAndDelete", func(t *testing.T) { + testutils.SkipOnOldKernel(t, "5.14", "LOOKUP_AND_DELETE flags") value.Cnt = 0 - err = m.LookupWithFlags(&key, &value, LookupLock) + err = m.LookupAndDeleteWithFlags(&key, &value, LookupLock) if err != nil { t.Fatal(err) } @@ -423,23 +428,10 @@ func TestMapWithLock(t *testing.T) { t.Fatalf("Want value 5, got %d", value.Cnt) } - t.Run("LookupAndDelete", func(t *testing.T) { - testutils.SkipOnOldKernel(t, "5.14", "LOOKUP_AND_DELETE flags") - - value.Cnt = 0 - err = m.LookupAndDeleteWithFlags(&key, &value, LookupLock) - if err != nil { - t.Fatal(err) - } - if value.Cnt != 5 { - t.Fatalf("Want value 5, got %d", value.Cnt) - } - - err = m.LookupWithFlags(&key, &value, LookupLock) - if err != nil && !errors.Is(err, ErrKeyNotExist) { - t.Fatal(err) - } - }) + err = m.LookupWithFlags(&key, &value, LookupLock) + if err != nil && !errors.Is(err, ErrKeyNotExist) { + t.Fatal(err) + } }) }