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 eab69b686..052abc1a6 100644 --- a/linker.go +++ b/linker.go @@ -169,6 +169,10 @@ func fixupAndValidate(insns asm.Instructions) error { return fmt.Errorf("instruction %d: map %s: %w", iter.Index, ins.Reference(), asm.ErrUnsatisfiedMapReference) } + if ins.IsFunctionReference() && haveBPFToBPFCalls() != nil { + return fmt.Errorf("kernel does not support bpf2bpf function calls: %w", haveBPFToBPFCalls()) + } + fixupProbeReadKernel(ins) } diff --git a/linker_test.go b/linker_test.go index 283a842d8..cfa28bb8e 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 } @@ -76,6 +73,7 @@ func TestForwardFunctionDeclaration(t *testing.T) { // This program calls an unimplemented forward function declaration. _, err = NewProgram(spec) + testutils.SkipIfNotSupported(t, err) if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) { t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err) } diff --git a/prog_test.go b/prog_test.go index 78f1e9adf..50257d1b3 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) } diff --git a/syscalls.go b/syscalls.go index ccbbe096e..a0ebab2b8 100644 --- a/syscalls.go +++ b/syscalls.go @@ -38,6 +38,21 @@ func invalidBPFObjNameChar(char rune) bool { } } +func progLoad(insns asm.Instructions, license string) (*sys.FD, error) { + buf := bytes.NewBuffer(make([]byte, 0, insns.Size())) + if err := insns.Marshal(buf, internal.NativeEndian); err != nil { + return nil, err + } + bytecode := buf.Bytes() + + return sys.ProgLoad(&sys.ProgLoadAttr{ + ProgType: sys.ProgType(Kprobe), + License: sys.NewStringPointer("GPL"), + Insns: sys.NewSlicePointer(bytecode), + InsnCnt: uint32(len(bytecode) / asm.InstructionSize), + }) +} + var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error { _, err := sys.MapCreate(&sys.MapCreateAttr{ MapType: sys.MapType(ArrayOfMaps), @@ -226,21 +241,30 @@ var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", f asm.FnProbeReadKernel.Call(), asm.Return(), } - buf := bytes.NewBuffer(make([]byte, 0, insns.Size())) - if err := insns.Marshal(buf, internal.NativeEndian); err != nil { - return err - } - bytecode := buf.Bytes() - fd, err := sys.ProgLoad(&sys.ProgLoadAttr{ - ProgType: sys.ProgType(Kprobe), - License: sys.NewStringPointer("GPL"), - Insns: sys.NewSlicePointer(bytecode), - InsnCnt: uint32(len(bytecode) / asm.InstructionSize), - }) + fd, err := progLoad(insns, "GPL") if err != nil { return internal.ErrNotSupported } _ = fd.Close() return nil }) + +var haveBPFToBPFCalls = internal.FeatureTest("bpf2bpf calls", "4.16", func() error { + insns := asm.Instructions{ + asm.Call.Label("prog2").WithSymbol("prog1"), + asm.Return(), + asm.Mov.Imm(asm.R0, 0).WithSymbol("prog2"), + asm.Return(), + } + + fd, err := progLoad(insns, "MIT") + if errors.Is(err, unix.EINVAL) { + return internal.ErrNotSupported + } + if err != nil { + return err + } + _ = fd.Close() + return nil +}) diff --git a/syscalls_test.go b/syscalls_test.go index 7ad03c079..e9735b7ff 100644 --- a/syscalls_test.go +++ b/syscalls_test.go @@ -54,3 +54,7 @@ func TestHaveInnerMaps(t *testing.T) { func TestHaveProbeReadKernel(t *testing.T) { testutils.CheckFeatureTest(t, haveProbeReadKernel) } + +func TestHaveBPFToBPFCalls(t *testing.T) { + testutils.CheckFeatureTest(t, haveBPFToBPFCalls) +}