Documentation
¶
Overview ¶
Package probes provides BPF features checks based on bpftool.
Index ¶
- Constants
- Variables
- func CreateHeaderFiles(headerDir string, probes *FeatureProbes) error
- func HaveAttachType(pt ebpf.ProgramType, at ebpf.AttachType) (err error)
- func HaveBatchAPI() error
- func HaveBoundedLoops(logger *slog.Logger) error
- func HaveDeadCodeElim() error
- func HaveIPv6Support() error
- func HaveLargeInstructionLimit(logger *slog.Logger) error
- func HaveProgramHelper(logger *slog.Logger, pt ebpf.ProgramType, helper asm.BuiltinFunc) error
- func HaveSKBAdjustRoomL2RoomMACSupport(logger *slog.Logger) (err error)
- func HaveV2ISA(logger *slog.Logger) error
- func HaveV3ISA(logger *slog.Logger) error
- func HaveWriteableQueueMapping() error
- func Jiffies() (uint64, error)
- func KernelHZ() (uint16, error)
- type FeatureProbes
- type ProgramHelper
Constants ¶
const ( NTF_EXT_LEARNED = netlink.NTF_EXT_LEARNED NTF_EXT_MANAGED = netlink.NTF_EXT_MANAGED )
Family type definitions
Variables ¶
var ErrNotSupported = errors.New("not supported")
ErrNotSupported indicates that a feature is not supported by the current kernel.
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.
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.
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.
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().
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.
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.
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 ¶
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 ¶
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
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 ¶
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 ¶
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 ¶
Jiffies returns the kernel's internal timestamp in jiffies read from /proc/schedstat.
func KernelHZ ¶
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
}