Merge pull request #1925 from safing/fix/Linux_core_bpf_compatibility
improvement(ebpf-Linux): enhance eBPF object loading for kernel compatibility
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Code generated by bpf2go; DO NOT EDIT.
|
// Code generated by bpf2go; DO NOT EDIT.
|
||||||
//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64
|
//go:build mips || mips64 || ppc64 || s390x
|
||||||
|
|
||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
// Code generated by bpf2go; DO NOT EDIT.
|
// Code generated by bpf2go; DO NOT EDIT.
|
||||||
//go:build 386 || amd64 || amd64p32 || arm || arm64 || loong64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64
|
//go:build 386 || amd64 || arm || arm64 || loong64 || mips64le || mipsle || ppc64le || riscv64
|
||||||
|
|
||||||
package ebpf
|
package ebpf
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -7,9 +7,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf"
|
||||||
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/link"
|
"github.com/cilium/ebpf/link"
|
||||||
"github.com/cilium/ebpf/ringbuf"
|
"github.com/cilium/ebpf/ringbuf"
|
||||||
"github.com/cilium/ebpf/rlimit"
|
"github.com/cilium/ebpf/rlimit"
|
||||||
@@ -35,7 +38,7 @@ func ConnectionListenerWorker(ctx context.Context, packets chan packet.Packet) e
|
|||||||
|
|
||||||
// Load pre-compiled programs and maps into the kernel.
|
// Load pre-compiled programs and maps into the kernel.
|
||||||
objs := bpfObjects{}
|
objs := bpfObjects{}
|
||||||
if err := loadBpfObjects(&objs, nil); err != nil {
|
if err := loadBpfObjects_Ex(&objs, nil); err != nil {
|
||||||
if ebpfLoadingFailed.Add(1) >= 5 {
|
if ebpfLoadingFailed.Add(1) >= 5 {
|
||||||
log.Warningf("ebpf: failed to load ebpf object 5 times, giving up with error %s", err)
|
log.Warningf("ebpf: failed to load ebpf object 5 times, giving up with error %s", err)
|
||||||
return nil
|
return nil
|
||||||
@@ -129,6 +132,97 @@ func ConnectionListenerWorker(ctx context.Context, packets chan packet.Packet) e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadBpfObjects_Ex loads eBPF objects with kernel-aware attach point selection.
|
||||||
|
// (it extends the standard loadBpfObjects())
|
||||||
|
//
|
||||||
|
// This enhanced loader automatically detects available kernel functions and selects
|
||||||
|
// appropriate attach points for maximum compatibility across kernel versions. It handles
|
||||||
|
// the transition from legacy function names (e.g., ip4_datagram_connect) to modern ones
|
||||||
|
// (e.g., udp_connect) introduced in Linux 6.13+.
|
||||||
|
func loadBpfObjects_Ex(objs interface{}, opts *ebpf.CollectionOptions) error {
|
||||||
|
// Load pre-compiled programs
|
||||||
|
spec, err := loadBpf()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("ebpf: failed to load ebpf spec: %w", err)
|
||||||
|
}
|
||||||
|
// Modify the attach points of the eBPF programs, if necessary.
|
||||||
|
if err := modifyProgramsAttachPoints(spec); err != nil {
|
||||||
|
return fmt.Errorf("ebpf: failed to modify program attach points: %w", err)
|
||||||
|
}
|
||||||
|
// Load the eBPF programs and maps into the kernel.
|
||||||
|
if err := spec.LoadAndAssign(objs, opts); err != nil {
|
||||||
|
return fmt.Errorf("ebpf: failed to load and assign ebpf objects: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// modifyProgramAttachPoints modifies the attach points of the eBPF programs, if necessary.
|
||||||
|
// This is needed to ensure compatibility with different kernel versions.
|
||||||
|
func modifyProgramsAttachPoints(spec *ebpf.CollectionSpec) error {
|
||||||
|
// Load the kernel spec
|
||||||
|
kspec, err := btf.LoadKernelSpec()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update the attach point to a single BPF program
|
||||||
|
updateIfNeeded := func(bpfProgramName, attachPoint, attachPointLegacy string) error {
|
||||||
|
ps, ok := spec.Programs[bpfProgramName]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("ebpf: program %q not found in spec", bpfProgramName)
|
||||||
|
}
|
||||||
|
var fn *btf.Func
|
||||||
|
if err := kspec.TypeByName(attachPoint, &fn); err == nil {
|
||||||
|
if !strings.EqualFold(ps.AttachTo, attachPoint) {
|
||||||
|
ps.AttachTo = attachPoint
|
||||||
|
log.Debugf("ebpf: using attach point %q for %q program", attachPoint, bpfProgramName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !strings.EqualFold(ps.AttachTo, attachPointLegacy) {
|
||||||
|
ps.AttachTo = attachPointLegacy
|
||||||
|
log.Debugf("ebpf: using legacy attach point %q for %q program", attachPointLegacy, bpfProgramName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'udp_v4_connect' program is designed to attach to the `udp_connect` function in the kernel.
|
||||||
|
// If the kernel does not support this function, we fall back to using the `ip4_datagram_connect` function.
|
||||||
|
//
|
||||||
|
// Kernel compatibility note:
|
||||||
|
// - Linux kernels < 6.13: use `ip4_datagram_connect` function
|
||||||
|
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
|
||||||
|
// - Linux kernels >= 6.13: function renamed to `udp_connect`
|
||||||
|
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
|
||||||
|
const (
|
||||||
|
udpV4ConnectProgramName = "udp_v4_connect"
|
||||||
|
udpV4ConnectAttachPoint = "udp_connect"
|
||||||
|
udpV4ConnectAttachPointLegacy = "ip4_datagram_connect"
|
||||||
|
)
|
||||||
|
if err := updateIfNeeded(udpV4ConnectProgramName, udpV4ConnectAttachPoint, udpV4ConnectAttachPointLegacy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'udp_v6_connect' program is designed to attach to the `udpv6_connect` function in the kernel.
|
||||||
|
// If the kernel does not support this function, we fall back to using the `ip6_datagram_connect` function.
|
||||||
|
//
|
||||||
|
// Kernel compatibility note:
|
||||||
|
// - Linux kernels < 6.13: use `ip6_datagram_connect` function
|
||||||
|
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
|
||||||
|
// - Linux kernels >= 6.13: function renamed to `udpv6_connect`
|
||||||
|
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
|
||||||
|
const (
|
||||||
|
udpV6ConnectProgramName = "udp_v6_connect"
|
||||||
|
udpV6ConnectAttachPoint = "udpv6_connect"
|
||||||
|
udpV6ConnectAttachPointLegacy = "ip6_datagram_connect"
|
||||||
|
)
|
||||||
|
if err := updateIfNeeded(udpV6ConnectProgramName, udpV6ConnectAttachPoint, udpV6ConnectAttachPointLegacy); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// isEventValid checks whether the given bpfEvent is valid or not.
|
// isEventValid checks whether the given bpfEvent is valid or not.
|
||||||
// It returns true if the event is valid, otherwise false.
|
// It returns true if the event is valid, otherwise false.
|
||||||
func isEventValid(event bpfEvent) bool {
|
func isEventValid(event bpfEvent) bool {
|
||||||
|
|||||||
@@ -81,9 +81,15 @@ int BPF_PROG(tcp_connect, struct sock *sk) {
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fexit(function exit) of udp_v4_connect will be executed after the ip4_datagram_connect kernel function is called.
|
// Fexit(function exit) of `udp_v4_connect` will be executed after the `udp_connect` kernel function is called.
|
||||||
// ip4_datagram_connect -> udp_v4_connect
|
//
|
||||||
SEC("fexit/ip4_datagram_connect")
|
// Kernel compatibility note:
|
||||||
|
// - Linux kernels < 6.13: use `ip4_datagram_connect` function
|
||||||
|
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
|
||||||
|
// - Linux kernels >= 6.13: function renamed to `udp_connect`
|
||||||
|
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
|
||||||
|
//
|
||||||
|
SEC("fexit/udp_connect") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())
|
||||||
int BPF_PROG(udp_v4_connect, struct sock *sk) {
|
int BPF_PROG(udp_v4_connect, struct sock *sk) {
|
||||||
// Ignore everything else then IPv4
|
// Ignore everything else then IPv4
|
||||||
if (sk->__sk_common.skc_family != AF_INET) {
|
if (sk->__sk_common.skc_family != AF_INET) {
|
||||||
@@ -128,9 +134,15 @@ int BPF_PROG(udp_v4_connect, struct sock *sk) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fentry(function enter) of udp_v6_connect will be executed after the ip6_datagram_connect kernel function is called.
|
// Fentry(function enter) of `udp_v6_connect` will be executed after the `udpv6_connect` kernel function is called.
|
||||||
// ip6_datagram_connect -> udp_v6_connect
|
//
|
||||||
SEC("fexit/ip6_datagram_connect")
|
// Kernel compatibility note:
|
||||||
|
// - Linux kernels < 6.13: use `ip6_datagram_connect` function
|
||||||
|
// https://elixir.bootlin.com/linux/v6.12.34/source/net/ipv4/udp.c#L2997
|
||||||
|
// - Linux kernels >= 6.13: function renamed to `udpv6_connect`
|
||||||
|
// https://elixir.bootlin.com/linux/v6.13-rc1/source/net/ipv4/udp.c#L3131
|
||||||
|
//
|
||||||
|
SEC("fexit/udpv6_connect") // Note: This attach point name may be overwritten (see worker.go: modifyProgramsAttachPoints())
|
||||||
int BPF_PROG(udp_v6_connect, struct sock *sk) {
|
int BPF_PROG(udp_v6_connect, struct sock *sk) {
|
||||||
// Ignore everything else then IPv6
|
// Ignore everything else then IPv6
|
||||||
if (sk->__sk_common.skc_family != AF_INET6) {
|
if (sk->__sk_common.skc_family != AF_INET6) {
|
||||||
|
|||||||
@@ -14,4 +14,9 @@ headers=(
|
|||||||
|
|
||||||
# Fetch libbpf release and extract the desired headers
|
# Fetch libbpf release and extract the desired headers
|
||||||
curl -sL "https://github.com/libbpf/libbpf/archive/refs/tags/v${LIBBPF_VERSION}.tar.gz" | \
|
curl -sL "https://github.com/libbpf/libbpf/archive/refs/tags/v${LIBBPF_VERSION}.tar.gz" | \
|
||||||
tar -xz --xform='s#.*/#bpf/#' "${headers[@]}"
|
tar -xz --xform='s#.*/#bpf/#' "${headers[@]}"
|
||||||
|
|
||||||
|
# To generate the vmlinux header file
|
||||||
|
# See "Export kernel information" at https://docs.ebpf.io/concepts/core/btf
|
||||||
|
#
|
||||||
|
# bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux-x86.h
|
||||||
|
|||||||
Reference in New Issue
Block a user