Documentation
¶
Overview ¶
Package dataplane owns everything AF_XDP: opening the fleet, the per-queue transmit and receive loops, and the safety checks that run before an XDP program is attached to a live interface.
It is the only package that imports go-afxdp. Everything above it — configuration, the TUI, the CLI — deals in plain Go types.
Index ¶
- func MemoryNeeded(queues, numFrames, frameSize int) uint64
- func RaiseMemlock() (uint64, error)
- type Check
- type DefaultFilterBuilder
- type Environment
- type FilterBuilder
- type FilterPlan
- type Info
- type Level
- type Options
- type Preflight
- type PreflightInput
- type Runner
- func (r *Runner) AdjustRate(factor float64) (pps, bps uint64)
- func (r *Runner) Collector() *stats.Collector
- func (r *Runner) Info() Info
- func (r *Runner) Paused() bool
- func (r *Runner) Plan() FilterPlan
- func (r *Runner) Preflight(src discovery.Source) *Preflight
- func (r *Runner) Queues() int
- func (r *Runner) Rate() (pps, bps uint64)
- func (r *Runner) Run(ctx context.Context) error
- func (r *Runner) SetPaused(p bool)
- func (r *Runner) SetRate(pps, bps uint64)
- func (r *Runner) Start(ctx context.Context) error
- func (r *Runner) Stats() *stats.Snapshot
- func (r *Runner) Stop()
- func (r *Runner) Wait() error
- type Session
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MemoryNeeded ¶
MemoryNeeded estimates the locked memory a run will need: one UMEM per queue, plus slack for the rings and BPF maps.
func RaiseMemlock ¶
RaiseMemlock tries to lift this process's RLIMIT_MEMLOCK soft limit to the hard limit. That is a change to Wireblast's own process, not to the host, so it is done automatically; anything beyond it is the user's call.
Types ¶
type Check ¶
type Check struct {
Level Level
Title string
Detail string
// Fix is a command the user could run. Wireblast only ever suggests these:
// it never reconfigures the host itself.
Fix string
}
Check is one preflight finding.
type DefaultFilterBuilder ¶
type DefaultFilterBuilder struct{}
DefaultFilterBuilder maps Wireblast's receive modes onto the matches go-afxdp provides today.
func (DefaultFilterBuilder) Plan ¶
func (DefaultFilterBuilder) Plan(cfg *config.Config, res *discovery.Resolved) (FilterPlan, error)
Plan builds the filter for a run.
type Environment ¶
type Environment struct {
// Euid is the effective user ID; 0 means root.
Euid int
// HasNetRaw reports whether the process holds CAP_NET_RAW.
HasNetRaw bool
// MemlockCur and MemlockMax are the RLIMIT_MEMLOCK soft and hard limits in
// bytes. MemlockUnlimited short-circuits both.
MemlockCur uint64
MemlockMax uint64
MemlockUnlimited bool
// SSHConnection is the value of $SSH_CONNECTION, if any.
SSHConnection string
// DefaultRouteLink is the interface index owning the default route.
DefaultRouteLink int
HasDefaultRoute bool
}
Environment is the host state preflight inspects, injected so the checks can be unit-tested without root, a real NIC or a real SSH session.
func HostEnvironment ¶
func HostEnvironment(src discovery.Source) Environment
HostEnvironment reads the real environment.
type FilterBuilder ¶
type FilterBuilder interface {
Plan(cfg *config.Config, res *discovery.Resolved) (FilterPlan, error)
}
FilterBuilder turns a receive mode into an XDP filter.
It is an interface on purpose, so an alternative mapping can be dropped in without touching the rest of Wireblast. go-afxdp's matches combine with OR; the one exclusion it offers is WithKeepManagement, which the keep-management mode uses to take everything except the traffic that keeps the box reachable.
type FilterPlan ¶
type FilterPlan struct {
// Matches is what gets handed to afxdp.WithFilter.
Matches []afxdp.Match
// Summary is the short form for the dashboard, e.g. "udp/9000".
Summary string
// Redirects describes in plain language what leaves the kernel stack.
Redirects string
// Limitations are honest notes about what the filter does NOT do, so the
// UI never claims more precision than the filter really has.
Limitations []string
// Warnings are things the user should think about before saying yes.
Warnings []string
// Dangerous marks the match-all filter, which needs an extra confirmation
// on top of any --yes.
Dangerous bool
// KeepManagement asks the library to spare the traffic that keeps the box
// reachable (ARP, IPv6 ND, SSH and DNS to and from this host) even though
// the filter otherwise redirects everything. Set only by the
// keep-management receive mode.
KeepManagement bool
// contains filtered or unexported fields
}
FilterPlan is the XDP filter a run will install, together with a plain description of what it takes away from the kernel.
Receiving through AF_XDP means those packets stop reaching the normal network stack. That is a big enough deal that Wireblast always states, in words, exactly what will be redirected before it attaches anything.
func (FilterPlan) Receives ¶
func (p FilterPlan) Receives() bool
Receives reports whether a plan takes any traffic from the kernel at all.
type Info ¶
type Info struct {
Interface string
Driver string
Queues int
XDPMode string // "native", "generic", ...
ZeroCopy bool
Filter string
FrameSize int
NumFrames int
// Tuning is what the library did to the interface's NAPI settings to make
// the receive path keep up, e.g. "defer=2 flush=200ms", or "untuned". These
// are host settings the library restores on close; worth showing.
Tuning string
// Pattern and PacketSizes describe the traffic, e.g. "udp" and
// "fixed 64-byte frames".
Pattern string
PacketSizes string
// LinkWait is how long the interface actually took to come back after the
// XDP attach. The library polls for carrier rather than sleeping a fixed
// amount, so this is the driver's real renegotiation time. Zero when the
// attachment was reused and no wait was needed.
LinkWait time.Duration
// Reused is true when this run inherited an XDP program that was already
// attached, and so started instantly.
Reused bool
}
Info describes how the fleet ended up running, for the dashboard and the startup banner.
type Level ¶
type Level int
Level is how serious a preflight finding is.
const ( // LevelInfo is worth knowing but needs no decision. LevelInfo Level = iota // LevelWarn is something the user should see before starting. LevelWarn // LevelDanger could cut the user off from the machine. It requires an // explicit confirmation that --yes does not provide. LevelDanger // LevelFatal cannot be continued past. LevelFatal )
type Options ¶
type Options struct {
// Frames is the loaded capture for --mode pcap.
Frames generator.FrameSource
// Logf receives occasional dataplane messages. Optional.
Logf func(format string, args ...any)
// NumFrames and FrameSize override the UMEM geometry. Zero means default.
NumFrames int
FrameSize int
// Session keeps the XDP program attached across runs. Set it for an
// interactive session; leave it nil for a one-shot run.
Session *Session
}
Options configures a Runner.
type Preflight ¶
type Preflight struct {
Checks []Check
}
Preflight is the result of every check run before an XDP program is attached.
func RunPreflight ¶
func RunPreflight(in PreflightInput) *Preflight
RunPreflight performs every check that must happen before an XDP program touches the interface.
It reads and reports; it never changes the host. Where a change would help, it prints the command for the user to run.
func (*Preflight) NeedsConfirmation ¶
NeedsConfirmation reports whether a human has to say yes before starting, regardless of --yes.
type PreflightInput ¶
type PreflightInput struct {
Cfg *config.Config
Res *discovery.Resolved
Plan FilterPlan
Env Environment
Queues int
// MaxFrameLen is the largest frame the generator will emit, in bytes
// written (excluding the FCS).
MaxFrameLen int
NumFrames int
FrameSize int
// AllLinks is every interface on the host, used to place the SSH session.
AllLinks []discovery.Link
}
PreflightInput is everything the checks need to make their decisions.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner owns an AF_XDP run end to end: it opens the fleet, drives one transmit goroutine (and optionally one receive goroutine) per queue, and tears everything down cleanly.
Exactly one goroutine owns each socket's transmit side and at most one owns its receive side, which is the concurrency contract go-afxdp requires.
func New ¶
New prepares a run. It resolves the queue count, builds the filter plan and sizes the UMEM, but attaches nothing: call Runner.Preflight and then Runner.Run.
func (*Runner) AdjustRate ¶
AdjustRate scales both limits, for the +/- hotkeys. An unlimited limit stays unlimited, so which constraint is binding does not change.
func (*Runner) Collector ¶
Collector exposes the stats collector, for a front end that wants to reset the interval counters.
func (*Runner) Info ¶
Info returns how the run is configured, filled in with what the kernel actually granted once Runner.Run has opened the fleet.
func (*Runner) Plan ¶
func (r *Runner) Plan() FilterPlan
Plan returns the filter that will be installed.
func (*Runner) Run ¶
Run is Start followed by Wait: it transmits until the duration expires or ctx is cancelled, then shuts everything down cleanly.
func (*Runner) SetPaused ¶
SetPaused stops or resumes transmission. Receiving and the dashboard keep going either way.
func (*Runner) Start ¶
Start attaches the XDP program, waits for the link, and spawns the workers. It returns as soon as traffic is flowing, so a caller can display what the kernel actually granted (see Runner.Info) before waiting.
Every Start must be paired with a Runner.Wait, which is what tears everything down.
func (*Runner) Stop ¶
func (r *Runner) Stop()
Stop asks the run to wind down. Runner.Wait then returns once everything has drained.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session keeps an AF_XDP fleet attached across several runs.
Without it, every rerun detaches the XDP program and attaches it again, which reinitialises the driver's queues and drops carrier for the better part of ten seconds on a 10G NIC. Since almost nothing people change between runs — the rate, the duration, the flow count, the packet contents — has any bearing on the attachment, that wait is nearly always avoidable.
A Session is owned by the interactive front end and closed when it exits. The one-shot --no-tui path does not use one: it runs once and leaves.
func NewSession ¶
func NewSession() *Session
NewSession returns an empty session. Nothing is attached until the first run asks for a fleet.
func (*Session) Close ¶
Close detaches whatever is currently held. It is safe to call more than once.
func (*Session) Fleet ¶
func (s *Session) Fleet(key fleetKey, open func() (*afxdp.Fleet, error)) (*afxdp.Fleet, bool, error)
Fleet returns a fleet matching key, reusing the one already attached when it matches and opening a new one otherwise. It reports whether the fleet was reused, which is how the caller knows it can skip waiting for the link.
open is only called when a new attach is genuinely needed.