summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-12 22:39:06 +0200
committerPaul Buetow <paul@buetow.org>2026-03-12 22:39:06 +0200
commit13e7970afb3eeac69f82df833f030711e5cf12ec (patch)
tree098c4fb8c5a8c8f27547f03f40c9fee0be63fe35 /internal
parent1b21e818a69bf73fde3ca60f89d2dc82a79fd605 (diff)
internal: embed BPF object into ior binary
Diffstat (limited to 'internal')
-rw-r--r--internal/bpfembed.go31
-rw-r--r--internal/ior.go4
-rw-r--r--internal/ior_setup_test.go97
3 files changed, 130 insertions, 2 deletions
diff --git a/internal/bpfembed.go b/internal/bpfembed.go
new file mode 100644
index 0000000..fce784c
--- /dev/null
+++ b/internal/bpfembed.go
@@ -0,0 +1,31 @@
+package internal
+
+import (
+ _ "embed"
+ "os"
+
+ bpf "github.com/aquasecurity/libbpfgo"
+)
+
+const (
+ bpfObjectOverrideEnv = "IOR_BPF_OBJECT"
+ embeddedBPFObjectName = "ior.bpf.o"
+)
+
+//go:embed c/ior.bpf.o
+var embeddedBPFObject []byte
+
+var (
+ newBPFModuleFromFile = bpf.NewModuleFromFile
+ newBPFModuleFromBuffer = bpf.NewModuleFromBuffer
+)
+
+func loadBPFModule() (*bpf.Module, string, error) {
+ if path := os.Getenv(bpfObjectOverrideEnv); path != "" {
+ module, err := newBPFModuleFromFile(path)
+ return module, "load module from override file", err
+ }
+
+ module, err := newBPFModuleFromBuffer(embeddedBPFObject, embeddedBPFObjectName)
+ return module, "load embedded module", err
+}
diff --git a/internal/ior.go b/internal/ior.go
index c14ab37..3f145a9 100644
--- a/internal/ior.go
+++ b/internal/ior.go
@@ -342,9 +342,9 @@ func setupBPFModuleError(stage string, err error) error {
func setupBPFModule(parentCtx context.Context, cfg flags.Config) (*bpf.Module, *probemanager.Manager, func(), error) {
releaseBindings := func() {}
- bpfModule, err := bpf.NewModuleFromFile("ior.bpf.o")
+ bpfModule, stage, err := loadBPFModule()
if err != nil {
- return nil, nil, releaseBindings, setupBPFModuleError("load module from file", err)
+ return nil, nil, releaseBindings, setupBPFModuleError(stage, err)
}
if err := resizeBPFMaps(cfg, bpfModule); err != nil {
bpfModule.Close()
diff --git a/internal/ior_setup_test.go b/internal/ior_setup_test.go
index 9c8b1b3..9c804c7 100644
--- a/internal/ior_setup_test.go
+++ b/internal/ior_setup_test.go
@@ -1,8 +1,12 @@
package internal
import (
+ "bytes"
"errors"
+ "os"
"testing"
+
+ bpf "github.com/aquasecurity/libbpfgo"
)
func TestSetupBPFModuleErrorWrapsStage(t *testing.T) {
@@ -25,3 +29,96 @@ func TestSetupBPFModuleErrorNil(t *testing.T) {
t.Fatalf("expected nil error passthrough, got %v", err)
}
}
+
+func TestLoadBPFModuleUsesEmbeddedObjectByDefault(t *testing.T) {
+ origFile := newBPFModuleFromFile
+ origBuffer := newBPFModuleFromBuffer
+ origOverride, hadOverride := os.LookupEnv(bpfObjectOverrideEnv)
+ t.Cleanup(func() {
+ newBPFModuleFromFile = origFile
+ newBPFModuleFromBuffer = origBuffer
+ if hadOverride {
+ os.Setenv(bpfObjectOverrideEnv, origOverride)
+ return
+ }
+ os.Unsetenv(bpfObjectOverrideEnv)
+ })
+ os.Unsetenv(bpfObjectOverrideEnv)
+
+ wantErr := errors.New("buffer load failed")
+ newBPFModuleFromFile = func(string) (*bpf.Module, error) {
+ t.Fatal("expected embedded loader, not file loader")
+ return nil, nil
+ }
+
+ var gotBytes []byte
+ var gotName string
+ newBPFModuleFromBuffer = func(data []byte, name string) (*bpf.Module, error) {
+ gotBytes = append([]byte(nil), data...)
+ gotName = name
+ return nil, wantErr
+ }
+
+ module, stage, err := loadBPFModule()
+ if module != nil {
+ t.Fatalf("expected nil module from stubbed loader, got %v", module)
+ }
+ if got, want := stage, "load embedded module"; got != want {
+ t.Fatalf("stage = %q, want %q", got, want)
+ }
+ if !errors.Is(err, wantErr) {
+ t.Fatalf("expected embedded loader error, got %v", err)
+ }
+ if !bytes.Equal(gotBytes, embeddedBPFObject) {
+ t.Fatalf("embedded loader received unexpected object bytes")
+ }
+ if got, want := gotName, embeddedBPFObjectName; got != want {
+ t.Fatalf("embedded loader name = %q, want %q", got, want)
+ }
+}
+
+func TestLoadBPFModuleUsesOverridePathWhenConfigured(t *testing.T) {
+ origFile := newBPFModuleFromFile
+ origBuffer := newBPFModuleFromBuffer
+ origOverride, hadOverride := os.LookupEnv(bpfObjectOverrideEnv)
+ t.Cleanup(func() {
+ newBPFModuleFromFile = origFile
+ newBPFModuleFromBuffer = origBuffer
+ if hadOverride {
+ os.Setenv(bpfObjectOverrideEnv, origOverride)
+ return
+ }
+ os.Unsetenv(bpfObjectOverrideEnv)
+ })
+
+ overridePath := "/tmp/custom-ior.bpf.o"
+ if err := os.Setenv(bpfObjectOverrideEnv, overridePath); err != nil {
+ t.Fatalf("set override env: %v", err)
+ }
+
+ wantErr := errors.New("file load failed")
+ newBPFModuleFromBuffer = func([]byte, string) (*bpf.Module, error) {
+ t.Fatal("expected file loader, not embedded loader")
+ return nil, nil
+ }
+
+ var gotPath string
+ newBPFModuleFromFile = func(path string) (*bpf.Module, error) {
+ gotPath = path
+ return nil, wantErr
+ }
+
+ module, stage, err := loadBPFModule()
+ if module != nil {
+ t.Fatalf("expected nil module from stubbed loader, got %v", module)
+ }
+ if got, want := stage, "load module from override file"; got != want {
+ t.Fatalf("stage = %q, want %q", got, want)
+ }
+ if !errors.Is(err, wantErr) {
+ t.Fatalf("expected override loader error, got %v", err)
+ }
+ if got, want := gotPath, overridePath; got != want {
+ t.Fatalf("override path = %q, want %q", got, want)
+ }
+}