Documentation
¶
Overview ¶
Package generator turns a configuration into a stream of packets.
Every traffic pattern implements the same small Generator interface, so the dataplane's transmit loop is identical whether it is sending UDP, TCP SYNs, an IMIX or a PCAP replay. Each queue gets its own Generator instance, owned by that queue's transmit goroutine alone, so nothing here locks and nothing allocates after construction.
Index ¶
- Variables
- func Classify(frame []byte) stats.Class
- func DescribeMix(mix []MixEntry) string
- func ExpandMix(mix []MixEntry) ([]int, error)
- func MeanSize(mix []MixEntry) float64
- func UsableAddresses(p netip.Prefix) uint64
- type Finite
- type Flow
- type FlowSpec
- type FrameSource
- type Generator
- type MixEntry
- type Pacer
- type Spec
Constants ¶
This section is empty.
Variables ¶
var DefaultIMIX = []MixEntry{
{Size: 64, Weight: 7},
{Size: 594, Weight: 4},
{Size: 1518, Weight: 1},
}
DefaultIMIX is the "simple IMIX", the conventional Internet mix used by almost every traffic generator: seven small frames, four medium, one large, in a 7:4:1 ratio.
The sizes are the classic ones — a 64-byte frame (40-byte IP packet, the size of a bare TCP ack), a 594-byte frame (576-byte IP packet, the old minimum reassembly buffer), and a 1518-byte frame (1500-byte IP packet, a full Ethernet MTU). The mean is 361.8 bytes of Ethernet frame, which is the familiar ~340-byte IMIX average measured at IP level plus the 18 bytes of Ethernet header and FCS wrapped around it.
The distribution is a plain table so another mix can be dropped in without touching the generator.
Functions ¶
func Classify ¶
Classify reports the protocol bucket of a received frame. The receive loop uses it, and it is the same code path the PCAP generator uses on transmit so both directions count the same way.
func DescribeMix ¶
DescribeMix renders a mix for the review screen and the dashboard, e.g. "IMIX 7:4:1 (64/594/1518B), mean 362B".
func ExpandMix ¶
ExpandMix turns a weighted size distribution into the exact, repeating sequence of frame sizes a generator cycles through. The returned slice has one entry per unit of weight, so DefaultIMIX yields 12 sizes containing exactly seven 64s, four 594s and one 1518.
The order is smooth rather than grouped: instead of emitting all the small frames and then all the large ones, it interleaves them with a deterministic weighted round-robin (the same "smooth" scheduling nginx uses). That keeps the instantaneous bit rate close to the average rather than pulsing once per cycle, and it is fully reproducible.
func UsableAddresses ¶
UsableAddresses reports how many destination addresses a prefix contributes, following the same network/broadcast rules as the per-family steppers. It is used to tell the user how many distinct destinations a CIDR really provides. An IPv6 prefix of /64 or shorter is reported as the max uint64.
Types ¶
type Finite ¶
type Finite interface {
// Remaining returns how many packets are left, or -1 when unbounded.
Remaining() int
}
Finite is implemented by generators that can run out of packets — currently only a one-pass PCAP replay. The transmit loop asks how many packets are still available so it never requests a batch it cannot fill, and stops when nothing is left.
type Flow ¶
Flow is one flow's tuple. The other tuple components — IP protocol and VLAN ID — are fixed for a run and live in the packet template.
type FlowSpec ¶
type FlowSpec struct {
SrcIP netip.Addr // fixed for every flow
Dst netip.Prefix // /32 for a single destination; wider to cycle
// SrcPort is the first source port; flow n uses SrcPort+n.
SrcPort uint16
// DstPort is the destination port. It is fixed unless VaryDstPort is set,
// because the usual test points many flows at one server port.
DstPort uint16
VaryDstPort bool
// Flows is how many distinct flows exist. Must be at least 1.
Flows int
// Scatter walks the flow space in a scrambled order instead of counting
// through it. The set of flows is identical either way, and the order is
// still completely deterministic — it just stops consecutive packets
// carrying consecutive ports, which some receivers hash badly.
Scatter bool
// contains filtered or unexported fields
}
FlowSpec describes the deterministic flow space a run walks.
Flow n is a pure function of n: the same configuration always produces the same tuples in the same order, whatever the queue count, which is what makes a test reproducible and a capture comparable between runs.
type FrameSource ¶
type FrameSource interface {
// Len is how many frames the capture holds.
Len() int
// Frame returns the i-th frame's bytes and the gap since the frame before
// it (zero for the first). The returned slice must not be modified.
Frame(i int) (data []byte, gap time.Duration)
// MaxLen and MeanLen are the largest and mean frame lengths in bytes.
MaxLen() int
MeanLen() int
// Describe summarises the capture for the review screen.
Describe() string
// Warnings lists anything about the capture worth telling the user before
// replaying it, such as packets truncated by the capture's snaplen.
Warnings() []string
}
FrameSource supplies the frames of a loaded capture. It is an interface so the generator can be tested without touching a file, and so the PCAP reader stays in its own package.
type Generator ¶
type Generator interface {
// Next writes the next packet into frame and returns how many bytes it
// wrote — the Ethernet frame length excluding the FCS the NIC appends —
// along with the protocol class for statistics.
Next(frame []byte) (int, stats.Class)
// AvgWireBytes is the mean on-the-wire size of a packet, including the 20
// bytes of preamble, start-frame delimiter and interframe gap. The rate
// limiter charges this per packet up front and reconciles against the real
// sizes afterwards, so it only has to be a good estimate.
AvgWireBytes() int
// MaxFrameLen is the largest frame this generator can emit, so the
// dataplane can check it fits in a UMEM frame before attaching anything.
MaxFrameLen() int
// Describe is a short human-readable summary of the packet-size behaviour,
// e.g. "fixed 64-byte frames" or "IMIX 7:4:1 (64/594/1518B)".
Describe() string
}
Generator produces the packets one queue transmits.
A Generator is owned by exactly one transmit goroutine. Implementations must not allocate in Next: the whole point is that a 10 Gbit/s run does no per-packet memory work.
type MixEntry ¶
type MixEntry struct {
// Size is the total Ethernet frame size in bytes, including the 4-byte
// FCS — the same units as --packet-size.
Size int
// Weight is how many packets of this size appear per cycle.
Weight int
}
MixEntry is one frame size in a size distribution and how often it occurs relative to the others.
type Pacer ¶
type Pacer interface {
// Delay is how long to wait before producing the next packet.
Delay() time.Duration
}
Pacer is implemented by generators that carry their own timing, currently only PCAP replay preserving a capture's original inter-packet gaps. When a Generator also implements Pacer the transmit loop sends one packet at a time and waits the returned delay in between, obeying whichever of the pacer and the rate limiter is slower.
type Spec ¶
type Spec struct {
Cfg *config.Config
SrcMAC [6]byte
DstMAC [6]byte
SrcIP netip.Addr
Dst netip.Prefix
// Queue and Queues place this generator in the flow space.
Queue, Queues int
// Frames is the PCAP replay source, required for config.ModePCAP.
Frames FrameSource
}
Spec is everything the factory needs to build a queue's generator. The addressing is already resolved: discovery has picked the source address and the next-hop MAC before this point.