Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Template schema

A template is a YAML file (.wpg.yaml; JSON with .wpg.json is equivalent) that describes one stream: a layer stack, optional generators that vary fields, and a transmit profile. The machine-readable definition is docs/schema/template.schema.json; print it with wpg template schema. Unknown keys are errors, so typos are caught. Check a file with wpg template lint FILE.

schema: 1                  # required
meta: { ... }              # required
variables: [ ... ]         # optional
layers: [ ... ]            # required, outermost first
packet: { ... }            # optional
stream: { ... }            # optional
tx: { ... }                # optional

meta

KeyMeaning
namerequired display name; unique within a library (the bundled library is tested for this)
descriptionfree text
descriptionsper-language text: ja: and en:
tagssearch tags. The bundled library uses protocol:<id>, layer:l2|l3|l4, scenario, malformed and topic words
author, createdfree text; created is a date or RFC 3339 timestamp

variables

Template arguments. Each entry has name, optional default (string, number or bool) and description. Use ${name} anywhere inside a field value or generator. Override at run time with --var name=value (wpg send, wpg render), or in the GUI. A variable with no default and no override is an error, and so is a ${…} that is not declared. Declared but unused variables give a warning.

Optional keys constrain the value. Without them any text is accepted:

KeyMeaning
typeuint, int, bool, string, ipv4, ipv6, mac or bytes; values use the same notation as fields (0x0800, 0200.0000.0001)
choicesthe allowed values
min, maxinclusive range, for uint and int
requireda value must be given at run time; the variable has no default
variables:
  - { name: vlan_id, type: uint, min: 1, max: 4094, default: 100 }
  - { name: target, type: ipv4, required: true }
  - { name: proto, type: uint, choices: [6, 17], default: 17 }

wpg template lint checks the default and the choices. A run-time value that does not fit (--var, or vars in the job and render API) is a template error that names the variable and what was expected: the CLI exits with status 3 and the server answers 422 invalid_template. A bool accepts true, false, 1 and 0 and is substituted as 1 or 0. The job form in the GUI shows a matching input for each variable.

layers

Each entry is protocol (an id from the catalog, see the Protocol reference), fields and generators.

fields

Fields you write are Manual; fields you omit (or set to auto) keep their default or are computed (lengths, checksums, next-protocol numbers). Values use human notation:

TypeExamples
integer64, 0x0800, 0b101
MAC / IPv4 / IPv602:00:00:00:00:01, 192.0.2.1, 2001:db8::1 (quote MACs made only of digits, such as "00:11:22:33:44:55", because YAML can read them as numbers)
bytes"00 01 02 03" (always quoted); text as '"text"' with \r, \n, \t escapes
text line (SIP lines, CRLF-terminated)start_line: '"INVITE sip:bob@example.com SIP/2.0"' (the terminator is added automatically)
enuma number or a variant name: ethertype: arp, oper: request, type: echo_request
flagsbit names joined by |: flags: syn|ack, flags: df
TLV list (TCP/IPv4 options)- mss: 1460, - sack_permitted, - nop, - timestamps: { tsval: 1, tsecr: 0 }, - { type: 99, data: "01 02" }
list / TLV list as verbatim octetsnlri: "18 c6 33 64" (a quoted hex string instead of the list; written by the import for content it cannot decode)

Deliberately wrong values are accepted: a Manual length or checksum is used as written, and wpg template lint reports the mismatch as a warning (diag-*). That is how the samples in templates/malformed/ are made.

generators

A map from field name to a generator, either the full form or the shorthand used by the GUI:

kindParametersShorthandMeaning
rangestart, end, step (default 1)192.168.1.1-192.168.5.254, 1-1024inclusive sweep; wraps around when the count is larger
range (CIDR)10.0.0.0/22host addresses of a block
listvalues1,5,9cycle through values
randommin, max, seeduniform random (integers, IPv4, IPv6)
random_macoui, seed00:11:22:*random MAC, optionally with a fixed prefix
counterstart, step, wrapincrementing value; unbounded unless wrap is set
filepathvalues read from a file
exprexprcomputed value

A generator and a fixed value on the same field produce a lint warning.

Expressions (expr)

An expr generator computes an integer for every packet. The result is written into the field like any other value, so it can fill numbers, IPv4 / IPv6 addresses and MAC addresses.

ElementMeaning
12, 0x1f, 0b101literals (decimal, hexadecimal, binary)
idxthe packet index in the stream (0, 1, 2, …)
$field, $<layer>.fieldthis packet’s value of another generated field; <layer> is written as in stream.order ($0.src and $ethernet2.src both name the src generator of the first layer; $ipv4[1].src is the second ipv4)
+ - * / %, << >>, & ^ |, unary - ~C-like operators and precedence; integer arithmetic (128-bit, wrapping)
hash(x), crc(x)FNV-1a 64 / CRC-32 of x (as 8 big-endian octets): spreads sequential values
rand(min, max)a random value between min and max, fixed per packet index and stream.seed
min(a, ...), max(a, ...)smallest / largest argument

A reference can only name a field that has a generator in the same template; fixed field values are not visible (put them in a variable and write ${name} instead, which is substituted before the expression is parsed). An expr can read another expr only if that one comes earlier in the template. Examples from the bundled library:

generators:
  chaddr: { kind: expr, expr: "$0.src" }                          # copy the Ethernet source MAC (dhcp-discover-flood)
  xid: { kind: expr, expr: "rand(0, 0xffffffff)" }               # a reproducible random transaction ID
  label: { kind: expr, expr: "${srgb_base} + ${first_index} + idx" } # SR-MPLS prefix SIDs (sr-mpls-prefix-sid-sweep)

packet

KeyDefaultMeaning
pad_to_mintruezero-pad to the 60-octet Ethernet minimum (FCS excluded)
fcsnoneauto appends a correct CRC-32, bad a wrong one, none nothing

stream

How generators combine and how long the stream is.

KeyMeaning
modezip (default, lockstep), product (last varies fastest) or nested
orderfor nested: fields from slowest to fastest as <layer>.<field>, where <layer> is a 0-based index, a protocol id unique in the stack (dot1q.vid, arp.tpa), or <protocol>[<n>] for the n-th (0-based) occurrence of a protocol that appears more than once (ipv4[1].src is the inner IPv4 of a tunnel)
countnumber of packets; default is tx.count, else the natural length of the generators
seedseed for random generators; makes the stream reproducible

Unbounded generators (a counter without wrap) need a count and cannot be in the inner position of product or nested.

tx

KeyMeaning
countpackets to send (no count and no duration_secs means run until stopped)
duration_secstime limit in seconds
rate1000pps, 1Mpps, 10Gbps, 50%, ifg=10us
burstframes sent back to back

Command-line options of wpg send override these.

Overriding values from the command line

wpg send, wpg render, wpg template show and wpg bench --template change a template for one run without editing the file:

OptionEffect
--vars-file FILEVariable values from a YAML or JSON map (dst_ip: 10.1.2.3).
--var NAME=VALUEOne variable value (repeatable). Wins over --vars-file, which wins over the template’s default.
--set LAYER.FIELD=VALUEFixes a field to a value, written as in fields:. The field becomes Manual and loses any generator.
--gen LAYER.FIELD=GENGives a field a generator and drops its fixed value.

LAYER is a protocol id (its first layer: ipv4), the n-th layer of a protocol counting from 0 (ipv4[1] is the inner header of IP-in-IP) or a 0-based layer index (2). FIELD is a field name from the protocol reference. An unknown layer or field stops with exit status 3 and lists the template’s layers or the closest field names. Every variable in --vars-file must be declared in the template, as with --var.

GEN is one of:

ShorthandGenerator
range:A..B, range:A..B/STEPrange from A to B inclusive
list:a,b,clist
random, random:MIN..MAXrandom
counter, counter:START, counter:START/STEPcounter
expr:EXPRexpr
anything elsethe shorthand of generators:: 10.0.0.1-10.0.0.9, 10.0.0.0/24, 1,5,9, 00:11:22:*
$ wpg render templates/examples/eth-ipv4-udp-range.wpg.yaml -o out.pcapng --count 100 \
    --vars-file lab.yaml --set ipv4.ttl=1 --gen udp.src_port=range:1024..1123

Payload layers

payload is not a wire protocol; its fields control generation: mode (fixed, pattern, random, counter), data, length, seed, and for counter the counter_offset, counter_width (u32 or u64) and counter_value (usually fed by a counter generator). raw places bytes as given.

Lint checks

KeySeverityMeaning
lint-schema-versionerrorunsupported schema
lint-missing-namewarningempty meta.name
lint-no-layerserrorno layers
lint-unknown-protocol, lint-unknown-fielderrornot in the catalog
lint-invalid-value, lint-invalid-generatorerrorvalue or generator does not fit the field type
lint-unknown-variable, lint-missing-variableerrorundeclared variable / variable without a value
lint-unused-variablewarningdeclared but unused
lint-next-protocol-manualwarningthe next layer is not in the previous layer’s binding table, so its next-protocol field cannot be Auto
lint-field-and-generatorwarninga field has both a fixed value and a generator
diag-*error / warningdiagnostics of the built packet, for example a checksum or length that differs from the computed value

The bundled library

templates/ is loaded as a library by default and is checked by crates/wpg-template/tests/samples.rs:

FolderContents
examples/five small starting points
protocols/l2, l3, l4, payload, frameone or more samples for every protocol in the catalog, plus jumbo, minimum-size, runt and FCS cases
scenarios/ready-made tests: ARP sweeps, SYN flood and port scan, QinQ, NDP and RA, ping and TTL sweeps, QoS matrix, MTU probe, frame-size sweep, MAC flood, SR-MPLS prefix SID sweep, DHCP DISCOVER load
interop/interop checks against real devices and FRR: OSPFv2 2-Way, RIPv2 routes, IS-IS adjacency Up, VRRPv3 preemption, PIM neighbor, LDP discovery, BFD session Up (interop tag; procedure in the operations guide, “Interop checks”)
malformed/deliberately broken packets (bad checksums, wrong lengths, truncation, bad FCS); they lint with warnings by design and are tagged malformed

List them with wpg template list templates.

Key reference (generated)

Generated from the JSON Schema of the template format (wpg template schema); the descriptions are the doc comments of the code (English). Template is the document root.

Template

A .wpg.yaml template: one packet (+ generators) = one stream.

KeyTypeRequiredDescription
layersTemplateLayer[]Layer stack, outermost first.
metaMetayesMetadata.
packetPacketOptionsFrame-level options (padding, FCS).
schemaintegeryesSchema version, see [SCHEMA_VERSION].
streamStreamOptionsStream expansion options.
txTxProfileTransmit profile.
variablesVariable[]Template variables.

FcsChoice

Frame check sequence choice.

ValueDescription
"auto"Append the correct CRC-32.
"bad"Append a deliberately wrong CRC-32.
"none"No FCS (what capture / TX backends usually expect).

FieldInput

A field value as written in YAML / JSON: a scalar in human notation or a structured value for TLV (options) and list fields.

  • scalars: 64, "192.168.1.1", 0x0800, syn|ack (flag names), ipv4 (enum variant names), auto. Hex byte strings must be quoted ("00 01 02");
  • TLV: a list of items, each a bare variant name (nop), a one-key map ({ mss: 1460 }, { timestamps: { tsval: 1, tsecr: 0 } }) or the explicit form { type: 99, data: "01 02" } / { name: mss, length: 4, fields: { value: 1 } };
  • list: a list of scalars, or of maps for lists of field groups.
ValueDescription
nullEmpty (~): e.g. an option without value.
booleantrue / false (1 / 0).
integerUnsigned integer.
integerNegative integer.
stringText in human notation.
FieldInput[]Sequence (TLV items, list elements).
map<string, FieldInput>Mapping (TLV item, field group).

Generator

Field value generator, tagged by kind.

kind: "range"

KeyTypeRequiredDescription
endstring | integeryes
kind"range"yes
startstring | integeryes
stepinteger

kind: "list"

KeyTypeRequiredDescription
kind"list"yes
values(string | integer)[]yes

kind: "random"

KeyTypeRequiredDescription
kind"random"yes
maxstring | integer
minstring | integer
seedinteger

kind: "random_mac"

KeyTypeRequiredDescription
kind"random_mac"yes
ouistring
seedinteger

kind: "counter"

KeyTypeRequiredDescription
kind"counter"yes
startinteger
stepinteger
wrapinteger

kind: "file"

KeyTypeRequiredDescription
kind"file"yes
pathstringyes

kind: "expr"

KeyTypeRequiredDescription
exprstringyes
kind"expr"yes

GeneratorSpec

A generator of a layer field: either a full [Generator] or the human shorthand of the GUI (192.168.1.1-192.168.5.254, 10.0.0.0/24, 1,5,9, 00:11:22:*).

ValueDescription
GeneratorFull form, e.g. { kind: range, start: 192.168.1.1, end: 192.168.1.254 }.
stringShorthand parsed with wpg_core::notation::parse_generator.

Meta

Template metadata.

KeyTypeRequiredDescription
authorstring | nullAuthor.
createdstring | nullCreation timestamp (RFC 3339 or a plain date).
descriptionstring | nullFree-form description.
descriptionsmap<string, ``string``>Localised descriptions keyed by language tag (ja, en).
namestringyesDisplay name.
tagsstring``[]Tags for search / grouping.

PacketOptions

Frame-level packet options.

KeyTypeRequiredDescription
fcsFcsChoiceFrame check sequence.
pad_to_minbooleanZero-pad to the minimum frame length (Ethernet: 60 octets).

Scalar

A YAML scalar; variable defaults may be written as numbers.

ValueDescription
string
integer
integer
boolean

StreamMode

How generators of several fields are combined (see wpg_core::stream::Mode).

ValueDescription
"zip"Advance all generators in lockstep.
"product"Cartesian product, the last generator varies fastest.
"nested"Product with an explicit priority given by [StreamOptions::order].

StreamOptions

Stream expansion options.

KeyTypeRequiredDescription
countinteger | nullNumber of packets; defaults to tx.count, then to the natural length.
modeStreamModeCombination mode of the generators.
orderstring``[]For nested: fields from the slowest to the fastest, as <layer>.<field> where <layer> is a 0-based index, a protocol id (ipv4.src) or the n-th occurrence of a protocol (ipv4[1].src).
seedinteger | nullSeed for random generators.

TemplateLayer

One layer of the template’s packet.

KeyTypeRequiredDescription
fieldsmap<string, FieldInput>Manually set fields in human notation (192.168.1.1, 0x0800, syn|ack, ${src_ip}). Unlisted fields use their default or Auto value; the literal auto also leaves a field Auto. TLV / list fields take structured values.
generatorsmap<string, GeneratorSpec>Generators varying fields across the stream.
protocolstringyesProtocol id from the catalog (e.g. ethernet2).

TxProfile

How the stream is transmitted.

KeyTypeRequiredDescription
burstinteger | nullBurst size in packets.
countinteger | nullNumber of packets (None together with duration_secs: None = infinite).
duration_secsnumber | nullDuration limit in seconds.
ratestring | nullRate in human notation: 1000pps, 1Mpps, 10Gbps, 50%.

VarType

Value type of a template variable (the field-type names of the protocol catalog).

ValueDescription
"uint"Unsigned integer: 64, 0x0800, 0b101.
"int"Signed integer: -1, +5, 0x10.
"bool"true / false (or 1 / 0); substituted as 1 / 0.
"string"Any text.
"ipv4"IPv4 address.
"ipv6"IPv6 address.
"mac"MAC address.
"bytes"Octets in hex: "00 01 02".

Variable

A template argument (${name} placeholder) overridable at run time.

KeyTypeRequiredDescription
choicesScalar[]Allowed values; any other value is rejected.
defaultScalar | nullDefault value (human notation; numbers and booleans are accepted too).
descriptionstring | nullDescription shown in the GUI / CLI.
maxinteger | nullLargest allowed value (type: uint / int only).
mininteger | nullSmallest allowed value (type: uint / int only).
namestringyesPlaceholder name.
requiredbooleanA value must be given at run time; the variable has no default.
typeVarType | nullValue type; values (default, --var, job vars) are checked against it. Without a type any text is accepted.