probes

package
v1.18.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2025 License: Apache-2.0 Imports: 25 Imported by: 7

Documentation

Overview

Package probes provides BPF features checks based on bpftool.

Index

Constants

View Source
const (
	NTF_EXT_LEARNED = netlink.NTF_EXT_LEARNED
	NTF_EXT_MANAGED = netlink.NTF_EXT_MANAGED
)

Family type definitions

Variables

View Source
var ErrNotSupported = errors.New("not supported")

ErrNotSupported indicates that a feature is not supported by the current kernel.

View Source
var HaveAttachCgroup = sync.OnceValue(func() error {

	spec := &ebpf.ProgramSpec{
		Type:       ebpf.CGroupSKB,
		AttachType: ebpf.AttachCGroupInetIngress,
		Instructions: asm.Instructions{
			asm.LoadImm(asm.R0, 0, asm.DWord),
			asm.Return(),
		},
	}

	p, err := ebpf.NewProgramWithOptions(spec, ebpf.ProgramOptions{
		LogDisabled: true,
	})
	if err != nil {
		return fmt.Errorf("create cgroup program: %w: %w", err, ebpf.ErrNotSupported)
	}
	defer p.Close()

	_, err = link.AttachCgroup(link.CgroupOptions{Path: "/dev/null", Program: p, Attach: spec.AttachType})
	if errors.Is(err, unix.EBADF) {

		return nil
	}
	if err != nil {

		return fmt.Errorf("link cgroup program to /dev/null: %w: %w", err, ebpf.ErrNotSupported)
	}

	return errors.New("attaching prog to /dev/null did not result in error")
})

HaveAttachCgroup returns nil if the kernel is compiled with CONFIG_CGROUP_BPF.

It's only an approximation and doesn't execute a successful cgroup attachment under the hood. If any unexpected errors are encountered, the original error is returned.

View Source
var HaveBPF = sync.OnceValue(func() error {
	prog, err := newProgram(ebpf.SocketFilter)
	if err != nil {
		return err
	}
	defer prog.Close()

	return nil
})

HaveBPF returns nil if the running kernel supports loading BPF programs.

View Source
var HaveBPFJIT = sync.OnceValue(func() error {
	prog, err := newProgram(ebpf.SocketFilter)
	if err != nil {
		return err
	}
	defer prog.Close()

	info, err := prog.Info()
	if err != nil {
		return fmt.Errorf("get prog info: %w", err)
	}
	if _, err := info.JitedSize(); err != nil {
		return fmt.Errorf("get JITed prog size: %w", err)
	}

	return nil
})

HaveBPFJIT returns nil if the running kernel features a BPF JIT and if it is enabled in the kernel configuration.

View Source
var HaveManagedNeighbors = sync.OnceValue(func() error {
	ns, err := netns.New()
	if err != nil {
		return fmt.Errorf("create netns: %w", err)
	}
	defer ns.Close()

	return ns.Do(func() error {

		veth := &netlink.Veth{
			LinkAttrs: netlink.LinkAttrs{Name: "veth0"},
			PeerName:  "veth1",
		}

		if err := netlink.LinkAdd(veth); err != nil {
			return fmt.Errorf("failed to add dummy veth: %w", err)
		}

		neigh := netlink.Neigh{
			LinkIndex: veth.Index,
			IP:        net.IPv4(0, 0, 0, 1),
			Flags:     NTF_EXT_LEARNED,
			FlagsExt:  NTF_EXT_MANAGED,
		}

		if err := netlink.NeighAdd(&neigh); err != nil {
			return fmt.Errorf("failed to add neighbor: %w", err)
		}

		nl, err := safenetlink.NeighList(veth.Index, 0)
		if err != nil {
			return fmt.Errorf("failed to list neighbors: %w", err)
		}

		for _, n := range nl {
			if !n.IP.Equal(neigh.IP) {
				continue
			}
			if n.Flags != NTF_EXT_LEARNED {
				continue
			}
			if n.FlagsExt != NTF_EXT_MANAGED {
				continue
			}

			return nil
		}

		return ErrNotSupported
	})
})

HaveManagedNeighbors returns nil if the host supports managed neighbor entries (NTF_EXT_MANAGED). On unexpected probe results this function will terminate with log.Fatal().

View Source
var HaveNetkit = sync.OnceValue(func() error {
	prog, err := newProgram(ebpf.SchedCLS)
	if err != nil {
		return err
	}
	defer prog.Close()

	ns, err := netns.New()
	if err != nil {
		return fmt.Errorf("create netns: %w", err)
	}
	defer ns.Close()

	return ns.Do(func() error {
		l, err := link.AttachNetkit(link.NetkitOptions{
			Program:   prog,
			Attach:    ebpf.AttachNetkitPrimary,
			Interface: math.MaxInt,
		})

		if errors.Is(err, unix.ENODEV) {
			return nil
		}
		if err != nil {
			return fmt.Errorf("creating link: %w", err)
		}
		if err := l.Close(); err != nil {
			return fmt.Errorf("closing link: %w", err)
		}

		return fmt.Errorf("unexpected success: %w", err)
	})
})

HaveNetkit returns nil if the running kernel supports attaching bpf programs to netkit devices.

View Source
var HaveTCBPF = sync.OnceValue(func() error {
	prog, err := newProgram(ebpf.SchedCLS)
	if err != nil {
		return err
	}
	defer prog.Close()

	ns, err := netns.New()
	if err != nil {
		return fmt.Errorf("create netns: %w", err)
	}
	defer ns.Close()

	qdisc := &netlink.Clsact{
		QdiscAttrs: netlink.QdiscAttrs{
			LinkIndex: 1,
			Handle:    netlink.MakeHandle(0xffff, 0),
			Parent:    netlink.HANDLE_CLSACT,
		},
	}

	filter := &netlink.BpfFilter{
		FilterAttrs: netlink.FilterAttrs{
			LinkIndex: 1,
			Parent:    netlink.HANDLE_MIN_INGRESS,
			Handle:    1,
			Protocol:  unix.ETH_P_ALL,
		},
		Fd:           prog.FD(),
		DirectAction: true,
	}

	return ns.Do(func() error {
		if err := netlink.QdiscReplace(qdisc); err != nil {
			return fmt.Errorf("creating clsact qdisc: %w: %w", err, ErrNotSupported)
		}

		if err := netlink.FilterReplace(filter); err != nil {
			return fmt.Errorf("attaching bpf tc filter: %w: %w", err, ErrNotSupported)
		}

		return nil
	})
})

HaveTCBPF returns nil if the running kernel supports attaching a bpf filter to a clsact qdisc.

View Source
var HaveTCX = sync.OnceValue(func() error {
	prog, err := newProgram(ebpf.SchedCLS)
	if err != nil {
		return err
	}
	defer prog.Close()

	ns, err := netns.New()
	if err != nil {
		return fmt.Errorf("create netns: %w", err)
	}
	defer ns.Close()

	return ns.Do(func() error {
		l, err := link.AttachTCX(link.TCXOptions{
			Program:   prog,
			Attach:    ebpf.AttachTCXIngress,
			Interface: 1,
			Anchor:    link.Tail(),
		})
		if err != nil {
			return fmt.Errorf("creating link: %w", err)
		}
		if err := l.Close(); err != nil {
			return fmt.Errorf("closing link: %w", err)
		}

		return nil
	})
})

HaveTCX returns nil if the running kernel supports attaching bpf programs to tcx hooks.

Functions

func CreateHeaderFiles

func CreateHeaderFiles(headerDir string, probes *FeatureProbes) error

CreateHeaderFiles creates C header files with macros indicating which BPF features are available in the kernel.

func HaveAttachType

func HaveAttachType(pt ebpf.ProgramType, at ebpf.AttachType) (err error)

HaveAttachType returns nil if the given program/attach type combination is supported by the underlying kernel. Returns ebpf.ErrNotSupported if loading a program with the given Program/AttachType fails. If the probe is inconclusive due to an unrecognized return code, the original error is returned.

Note that program types that don't use attach types will silently succeed if an attach type is specified.

Probe results are cached by the package and shouldn't be memoized by the caller.

func HaveBatchAPI added in v1.16.0

func HaveBatchAPI() error

HaveBatchAPI checks if kernel supports batched bpf map lookup API.

func HaveBoundedLoops

func HaveBoundedLoops(logger *slog.Logger) error

HaveBoundedLoops is a wrapper around features.HaveBoundedLoops() to check if the kernel supports bounded loops in BPF programs. On unexpected probe results this function will terminate with log.Fatal().

func HaveDeadCodeElim added in v1.16.0

func HaveDeadCodeElim() error

HaveDeadCodeElim tests whether the kernel supports dead code elimination.

func HaveIPv6Support

func HaveIPv6Support() error

HaveIPv6Support tests whether kernel can open an IPv6 socket. This will also implicitly auto-load IPv6 kernel module if available and not yet loaded.

func HaveLargeInstructionLimit

func HaveLargeInstructionLimit(logger *slog.Logger) error

HaveLargeInstructionLimit is a wrapper around features.HaveLargeInstructions() to check if the kernel supports the 1 Million instruction limit. On unexpected probe results this function will terminate with log.Fatal().

func HaveProgramHelper

func HaveProgramHelper(logger *slog.Logger, pt ebpf.ProgramType, helper asm.BuiltinFunc) error

HaveProgramHelper is a wrapper around features.HaveProgramHelper() to check if a certain BPF program/helper combination is supported by the kernel. On unexpected probe results this function will terminate with log.Fatal().

func HaveSKBAdjustRoomL2RoomMACSupport added in v1.15.0

func HaveSKBAdjustRoomL2RoomMACSupport(logger *slog.Logger) (err error)

HaveSKBAdjustRoomL2RoomMACSupport tests whether the kernel supports the `bpf_skb_adjust_room` helper with the `BPF_ADJ_ROOM_MAC` mode. To do so, we create a program that requests the passed in SKB to be expanded by 20 bytes. The helper checks the `mode` argument and will return -ENOSUPP if the mode is unknown. Otherwise it should resize the SKB by 20 bytes and return 0.

func HaveV2ISA

func HaveV2ISA(logger *slog.Logger) error

HaveV2ISA is a wrapper around features.HaveV2ISA() to check if the kernel supports the V2 ISA. On unexpected probe results this function will terminate with log.Fatal().

func HaveV3ISA

func HaveV3ISA(logger *slog.Logger) error

HaveV3ISA is a wrapper around features.HaveV3ISA() to check if the kernel supports the V3 ISA. On unexpected probe results this function will terminate with log.Fatal().

func HaveWriteableQueueMapping added in v1.17.0

func HaveWriteableQueueMapping() error

HaveWriteableQueueMapping checks if kernel has 74e31ca850c1 ("bpf: add skb->queue_mapping write access from tc clsact") which is 5.1+. This got merged in the same kernel as the bpf_skb_ecn_set_ce() helper.

func Jiffies

func Jiffies() (uint64, error)

Jiffies returns the kernel's internal timestamp in jiffies read from /proc/schedstat.

func KernelHZ

func KernelHZ() (uint16, error)

KernelHZ attempts to estimate the kernel's CONFIG_HZ compile-time value by making snapshots of the kernel timestamp with a time interval in between.

Blocks for at least 100ms while the measurement is in progress. Can block significantly longer under some hypervisors like VirtualBox due to buggy clocks, interrupt coalescing and low timer resolution.

Types

type FeatureProbes

type FeatureProbes struct {
	ProgramHelpers map[ProgramHelper]bool
}

func ExecuteHeaderProbes

func ExecuteHeaderProbes(logger *slog.Logger) *FeatureProbes

ExecuteHeaderProbes probes the kernel for a specific set of BPF features which are currently used to generate various feature macros for the datapath. The probe results returned in FeatureProbes are then used in the respective function that writes the actual C macro definitions. Further needed probes should be added here, while new macro strings need to be added in the correct `write*Header()` function.

type ProgramHelper

type ProgramHelper struct {
	Program ebpf.ProgramType
	Helper  asm.BuiltinFunc
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL