diff --git a/internal/btf/core_reloc_test.go b/internal/btf/core_reloc_test.go index b254efc49..c150c395a 100644 --- a/internal/btf/core_reloc_test.go +++ b/internal/btf/core_reloc_test.go @@ -90,8 +90,6 @@ func TestCORERelocationRead(t *testing.T) { } defer tgt.Close() - testutils.SkipOnOldKernel(t, "4.16", "bpf2bpf calls") - for _, progSpec := range spec.Programs { t.Run(progSpec.Name, func(t *testing.T) { if _, err := tgt.Seek(0, io.SeekStart); err != nil { @@ -101,6 +99,7 @@ func TestCORERelocationRead(t *testing.T) { prog, err := ebpf.NewProgramWithOptions(progSpec, ebpf.ProgramOptions{ TargetBTF: tgt, }) + testutils.SkipIfNotSupported(t, err) if err != nil { t.Fatal("Load program:", err) } diff --git a/linker.go b/linker.go index 60cb7a6c9..6bc00f9c4 100644 --- a/linker.go +++ b/linker.go @@ -110,6 +110,17 @@ func findReferences(progs map[string]*ProgramSpec) error { return nil } +// hasReferences returns true if insns contains one or more bpf2bpf +// function references. +func hasReferences(insns asm.Instructions) bool { + for _, i := range insns { + if i.IsFunctionReference() { + return true + } + } + return false +} + // applyRelocations collects and applies any CO-RE relocations in insns. // // Passing a nil target will relocate against the running kernel. insns are diff --git a/linker_test.go b/linker_test.go index 283a842d8..51bdf8d5e 100644 --- a/linker_test.go +++ b/linker_test.go @@ -42,9 +42,8 @@ func TestFindReferences(t *testing.T) { t.Fatal(err) } - testutils.SkipOnOldKernel(t, "4.16", "bpf2bpf calls") - prog, err := NewProgram(progs["entrypoint"]) + testutils.SkipIfNotSupported(t, err) if err != nil { t.Fatal(err) } @@ -66,8 +65,6 @@ func TestForwardFunctionDeclaration(t *testing.T) { t.Fatal(err) } - testutils.SkipOnOldKernel(t, "4.16", "bpf2bpf calls") - if coll.ByteOrder != internal.NativeEndian { return } @@ -91,6 +88,7 @@ func TestForwardFunctionDeclaration(t *testing.T) { spec.BTF = nil prog, err := NewProgram(spec) + testutils.SkipIfNotSupported(t, err) if err != nil { t.Fatal(err) } diff --git a/prog.go b/prog.go index b72c0f591..6e024e49d 100644 --- a/prog.go +++ b/prog.go @@ -361,6 +361,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand } } + if (errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM)) && hasReferences(spec.Instructions) { + if err := haveBPFToBPFCalls(); err != nil { + return nil, fmt.Errorf("load program: %w", internal.ErrorWithLog(err, logBuf, logErr)) + } + } + if errors.Is(logErr, unix.EPERM) && len(logBuf) > 0 && logBuf[0] == 0 { // EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can // check that the log is empty to reduce false positives. diff --git a/prog_test.go b/prog_test.go index 52e2400a0..147c38a5c 100644 --- a/prog_test.go +++ b/prog_test.go @@ -374,6 +374,7 @@ func TestProgramWithUnsatisfiedMap(t *testing.T) { progSpec.ByteOrder = nil _, err = NewProgram(progSpec) + testutils.SkipIfNotSupported(t, err) if !errors.Is(err, asm.ErrUnsatisfiedMapReference) { t.Fatal("Expected an error wrapping asm.ErrUnsatisfiedMapReference, got", err) }