diff --git a/README.md b/README.md index e4cc01fff..46a0d08f2 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,12 @@ See [Documentation](https://grafana.com/docs/beyla/) and the [tutorials](https:/ enabled. BTF became enabled by default on most Linux distributions with kernel 5.14 or higher. You can check if your kernel has BTF enabled by verifying if `/sys/kernel/btf/vmlinux` exists on your system. If you need to recompile your kernel to enable BTF, the configuration option `CONFIG_DEBUG_INFO_BTF=y` must be - set. -- eBPF enabled on the host + set. +- Beyla supports Linux distributions running RedHat Enterprise Linux 4.18 kernels build 348 and above as they have the required kernel backports. These include CentOS, AlmaLinux, and Oracle Linux. +- eBPF enabled on the host. - For instrumenting Go programs, they must have been compiled with at least Go 1.17. We currently support Go applications built with a major **Go version no earlier than 3 versions** behind the current - stable major release. + stable major release. - Some level of elevated permissions to execute the instrumenter: - On host systems, running Beyla requires `sudo`. - For Kubernetes we have detailed configuration example on how to run with minimum diff --git a/docs/sources/_index.md b/docs/sources/_index.md index 8815452c9..7d499dd23 100644 --- a/docs/sources/_index.md +++ b/docs/sources/_index.md @@ -45,6 +45,7 @@ Beyla offers the following features: You can check if your kernel has BTF enabled by verifying if `/sys/kernel/btf/vmlinux` exists on your system. If you need to recompile your kernel to enable BTF, the configuration option `CONFIG_DEBUG_INFO_BTF=y` must be set. +- Alternatively, RHEL 4.18 Linux kernels (at least build 348) are also supported, due to their heavily backported nature. - eBPF enabled in the host. - For instrumenting Go programs, they must have been compiled with at least Go 1.17. We currently support Go applications built with a major **Go version no earlier than 3 versions** behind the current diff --git a/pkg/beyla/os.go b/pkg/beyla/os.go index 31d5154ef..b6833ce82 100644 --- a/pkg/beyla/os.go +++ b/pkg/beyla/os.go @@ -12,11 +12,15 @@ import ( "github.com/grafana/beyla/pkg/internal/helpers" ) -// Minimum required Kernel version: 5.8 -const minKernMaj, minKernMin = 5, 8 +// Minimum required Kernel version: 4.18 +const minKernMaj, minKernMin = 4, 18 var kernelVersion = ebpfcommon.KernelVersion +func KernelVersion() (major, minor int) { + return kernelVersion() +} + // CheckOSSupport returns an error if the running operating system does not support // the minimum required Beyla features. func CheckOSSupport() error { diff --git a/pkg/beyla/os_test.go b/pkg/beyla/os_test.go index efafacf86..8b6db04dc 100644 --- a/pkg/beyla/os_test.go +++ b/pkg/beyla/os_test.go @@ -42,8 +42,8 @@ func TestCheckOSSupport_Unsupported(t *testing.T) { for _, tc := range []testCase{ {maj: 0, min: 0}, {maj: 3, min: 11}, - {maj: 5, min: 0}, - {maj: 5, min: 7}, + {maj: 4, min: 0}, + {maj: 4, min: 17}, } { t.Run(fmt.Sprintf("%d.%d", tc.maj, tc.min), func(t *testing.T) { overrideKernelVersion(tc) diff --git a/pkg/internal/ebpf/instrumenter.go b/pkg/internal/ebpf/instrumenter.go index af85b5011..7f4f66efc 100644 --- a/pkg/internal/ebpf/instrumenter.go +++ b/pkg/internal/ebpf/instrumenter.go @@ -92,7 +92,11 @@ func (i *instrumenter) kprobes(p KprobesTracer) error { log.Debug("going to add kprobe to function", "function", kfunc, "probes", kprobes) if err := i.kprobe(kfunc, kprobes); err != nil { - return fmt.Errorf("instrumenting function %q: %w", kfunc, err) + if kprobes.Required { + return fmt.Errorf("instrumenting function %q: %w", kfunc, err) + } + + log.Debug("error instrumenting kprobe", "function", kfunc, "error", err) } p.AddCloser(i.closables...) } diff --git a/pkg/internal/ebpf/ktracer/ktracer.go b/pkg/internal/ebpf/ktracer/ktracer.go index 055b0a7ac..b3f0ea561 100644 --- a/pkg/internal/ebpf/ktracer/ktracer.go +++ b/pkg/internal/ebpf/ktracer/ktracer.go @@ -250,7 +250,7 @@ func (p *Tracer) KProbes() map[string]ebpfcommon.FunctionPrograms { End: p.bpfObjects.KretprobeSysClone, }, "sys_clone3": { - Required: true, + Required: false, End: p.bpfObjects.KretprobeSysClone, }, "sys_exit": { diff --git a/test/integration/multiprocess_test.go b/test/integration/multiprocess_test.go index 44f695ef5..f623b0cb2 100644 --- a/test/integration/multiprocess_test.go +++ b/test/integration/multiprocess_test.go @@ -88,7 +88,7 @@ func TestMultiProcess(t *testing.T) { assert.Empty(t, results) }) - if kprobeTraces { + if kprobeTracesEnabled() { t.Run("Nested traces with kprobes: rust -> java -> node -> go -> python -> rails", func(t *testing.T) { testNestedHTTPTracesKProbes(t) }) diff --git a/test/integration/red_test_nodeclient.go b/test/integration/red_test_nodeclient.go index a03fe3b8d..51c261056 100644 --- a/test/integration/red_test_nodeclient.go +++ b/test/integration/red_test_nodeclient.go @@ -96,7 +96,7 @@ func testNodeClientWithMethodAndStatusCode(t *testing.T, method string, statusCo We check that the traceID has that 16 character 0 suffix and then we use the first 16 characters for looking up by Parent span. */ - if kprobeTraces { + if kprobeTracesEnabled() { assert.NotEmpty(t, span.TraceID) assert.Truef(t, strings.HasSuffix(span.TraceID, traceIDLookup), "string %q should have suffix %q", span.TraceID, traceIDLookup) diff --git a/test/integration/red_test_rust.go b/test/integration/red_test_rust.go index 6ace298ff..67101396e 100644 --- a/test/integration/red_test_rust.go +++ b/test/integration/red_test_rust.go @@ -84,7 +84,7 @@ func testREDMetricsForRustHTTPLibrary(t *testing.T, url, comm, namespace string, require.Len(t, res, 1) parent := res[0] require.NotEmpty(t, parent.TraceID) - if kprobeTraces { + if kprobeTracesEnabled() { require.Equal(t, traceID, parent.TraceID) // Validate that "parent" is a CHILD_OF the traceparent's "parent-id" childOfPID := trace.ChildrenOf(parentID) diff --git a/test/integration/suites_test.go b/test/integration/suites_test.go index 49d2899db..15d52922e 100644 --- a/test/integration/suites_test.go +++ b/test/integration/suites_test.go @@ -11,10 +11,15 @@ import ( "github.com/stretchr/testify/require" + "github.com/grafana/beyla/pkg/beyla" "github.com/grafana/beyla/test/integration/components/docker" ) -var kprobeTraces = true // allow tests to run distributed traces tests +func kprobeTracesEnabled() bool { + major, minor := beyla.KernelVersion() + + return major > 5 || (major == 5 && minor >= 17) +} func TestSuite(t *testing.T) { compose, err := docker.ComposeSuite("docker-compose.yml", path.Join(pathOutput, "test-suite.log")) @@ -492,6 +497,11 @@ func TestSuite_OverrideServiceName(t *testing.T) { } func TestSuiteNodeClient(t *testing.T) { + if !kprobeTracesEnabled() { + t.Skip("distributed traces not supported") + return + } + compose, err := docker.ComposeSuite("docker-compose-nodeclient.yml", path.Join(pathOutput, "test-suite-nodeclient.log")) compose.Env = append(compose.Env, `BEYLA_EXECUTABLE_NAME=node`, `NODE_APP=client`) require.NoError(t, err) @@ -505,6 +515,11 @@ func TestSuiteNodeClient(t *testing.T) { } func TestSuiteNodeClientTLS(t *testing.T) { + if !kprobeTracesEnabled() { + t.Skip("distributed traces not supported") + return + } + compose, err := docker.ComposeSuite("docker-compose-nodeclient.yml", path.Join(pathOutput, "test-suite-nodeclient-tls.log")) compose.Env = append(compose.Env, `BEYLA_EXECUTABLE_NAME=node`, `NODE_APP=client_tls`) require.NoError(t, err) diff --git a/test/integration/traces_test.go b/test/integration/traces_test.go index 39daca1a4..d2b979957 100644 --- a/test/integration/traces_test.go +++ b/test/integration/traces_test.go @@ -370,7 +370,7 @@ func testHTTPTracesKProbes(t *testing.T) { require.Len(t, res, 1) parent := res[0] require.NotEmpty(t, parent.TraceID) - if kprobeTraces { + if kprobeTracesEnabled() { require.Equal(t, traceID, parent.TraceID) // Validate that "parent" is a CHILD_OF the traceparent's "parent-id" childOfPID := trace.ChildrenOf(parentID)