Skip to content

Repository files navigation

sflowgen

A small synthetic sFlow v5 generator intended for FastNetMon testing, demonstrations, dashboards, and attack-detection validation.

The generator does not transmit real application traffic. It sends sFlow FlowSample records containing RawPacketFlow data with synthetic Ethernet, IPv4 or IPv6, and TCP, UDP, ICMP, or ICMPv6 headers. FastNetMon can then estimate the represented traffic volume using the configured sampling rate and original frame length.

Warning

This is a synthetic traffic test tool. Review its configuration and validate the resulting telemetry before using it in shared or production-like environments.

AI authorship disclosure

This test tool was vibe-coded with OpenAI GPT-5.6 Thinking.

The project requirements and testing direction were provided by the maintainer. The Go implementation, tests, configuration examples, and documentation were generated and iteratively refined through conversations with the model rather than written manually line by line.

Features

  • sFlow v5 export over UDP.
  • Simultaneous IPv4 and IPv6 background traffic.
  • Separate ambient and attack processes.
  • Infinite ambient generation by default.
  • Bidirectional ambient traffic with configurable incoming/outgoing proportions.
  • Smooth per-host variation using correlated AR(1) noise.
  • Stable but non-uniform top talkers using Zipf-distributed base weights.
  • Smooth attack ramp-up, hold, and ramp-down phases.
  • TCP, UDP, ICMP, and ICMPv6 packet headers.
  • Deterministic generation through a configurable random seed.
  • Strict YAML parsing and standalone configuration validation.
  • Runtime statistics for target and represented traffic rates.

Operating modes

Ambient mode

ambient continuously produces background traffic for one or more internal IPv4 or IPv6 networks.

go run . ambient --config examples/ambient.yaml

By default, ambient mode runs indefinitely until the process receives SIGINT or SIGTERM.

To run it for a limited period, add a duration to the ambient configuration:

duration: "2m"

Ambient mode is designed to keep the total network rate relatively stable while allowing individual host rates to move smoothly over time. Incoming and outgoing traffic for the same internal host use the same changing host weight, making the two directions correlated rather than independent.

Attack mode

attack is a separate finite process that adds traffic on top of an optional ambient process. All generated attack traffic is associated with a single victim address.

go run . attack --config examples/attack-ipv4.yaml
go run . attack --config examples/attack-ipv6.yaml

The attack profile consists of:

  1. smooth ramp-up using a smoothstep curve;
  2. a constant hold period at peak_rate;
  3. smooth ramp-down;
  4. process termination.

Ambient and attack configurations normally use different sub_agent_id values, allowing both processes to use the same sFlow agent address and collector simultaneously.

Requirements

  • Go 1.22 or newer.
  • A reachable sFlow collector, such as FastNetMon listening on UDP port 6343.

Build and test

go mod tidy
make test
make vet
make build

The resulting binary is created at:

bin/sflowgen

Run it with:

./bin/sflowgen ambient --config examples/ambient.yaml
./bin/sflowgen attack --config examples/attack-ipv4.yaml

Validate a configuration without sending traffic:

./bin/sflowgen validate --mode ambient --config examples/ambient.yaml
./bin/sflowgen validate --mode attack --config examples/attack-ipv4.yaml

FastNetMon preparation

FastNetMon must be configured to receive sFlow from the generator. The internal CIDRs used in the generator should also be present in the FastNetMon monitored networks list.

For example, when the ambient configuration contains:

networks:
  - cidr: "10.10.0.0/24"
  - cidr: "2001:db8:10::/64"

FastNetMon should classify those networks as internal. Addresses selected from peer_networks or source_networks should normally remain external.

Configuration

Exporter

The exporter section is shared by ambient and attack modes:

exporter:
  collector: "127.0.0.1:6343"
  agent_ip: "192.0.2.10"
  sub_agent_id: 0
  sampling_rate: 4096
  tick: "100ms"
  samples_per_datagram: 8
  seed: 42
Field Description
collector Destination address of the sFlow collector.
agent_ip Address reported as the sFlow agent. It is independent of the sampled IPv4 or IPv6 packet addresses.
sub_agent_id Logical sub-agent identifier. Use different values for concurrently running ambient and attack processes.
sampling_rate Number of represented packets per generated sample.
tick Internal traffic-model update interval.
samples_per_datagram Maximum number of samples grouped into one sFlow UDP datagram.
seed Random seed used for reproducible runs.

The generator estimates represented traffic approximately as:

frame_length × sampling_rate × 8

The sFlow sample_pool is incremented by sampling_rate for every generated sample.

Keeping samples_per_datagram around 4 to 10 is generally reasonable for this test tool and helps avoid unnecessarily large UDP datagrams.

Packet-size distribution

packet:
  mean_size: 900
  stddev: 220
  min_size: 64
  max_size: 1518

Frame lengths are generated from a bounded normal distribution. The minimum size is also adjusted when necessary to fit the selected IP and transport headers.

Protocol mix

protocols:
  tcp: 0.65
  udp: 0.30
  icmp: 0.05

Protocol values are relative weights and are normalized internally. They do not need to add up to exactly 1.0.

For IPv6 traffic, the ICMP weight produces ICMPv6 headers.

Ambient configuration

A complete ambient configuration may contain multiple IPv4 and IPv6 networks:

# Omit duration to run indefinitely.
exporter:
  collector: "127.0.0.1:6343"
  agent_ip: "192.0.2.10"
  sub_agent_id: 0
  sampling_rate: 4096
  tick: "100ms"
  samples_per_datagram: 8
  seed: 42

packet:
  mean_size: 900
  stddev: 220
  min_size: 64
  max_size: 1518

protocols:
  tcp: 0.65
  udp: 0.30
  icmp: 0.05

log_interval: "1s"
max_samples_per_tick: 100000

networks:
  - cidr: "10.10.0.0/24"
    rate: "2Gbps"
    incoming_share: 0.75
    outgoing_share: 0.25
    hosts: 128
    zipf: 1.10
    total_noise: 0.015
    host_noise: 0.25
    correlation: 0.98
    peer_networks:
      - "198.18.0.0/15"

  - cidr: "2001:db8:10::/64"
    rate: "1Gbps"
    incoming_share: 0.70
    outgoing_share: 0.30
    hosts: 128
    zipf: 1.10
    total_noise: 0.015
    host_noise: 0.25
    correlation: 0.98
    peer_networks:
      - "2001:db8:ffff::/48"

Ambient network fields

Field Description
cidr Internal network represented by this profile.
rate Average combined incoming and outgoing rate for the network.
incoming_share Relative share of traffic entering the internal network.
outgoing_share Relative share of traffic leaving the internal network.
hosts Number of active internal addresses selected from the CIDR.
zipf Skew of the base host distribution. 0 gives equal base weights.
total_noise Variation applied to the total rate of the network.
host_noise Variation applied to individual host shares.
correlation AR(1) persistence. Values around 0.95 to 0.99 produce smooth movement.
peer_networks External networks used to generate remote source and destination addresses.

Incoming and outgoing proportions

The two share values are normalized automatically. Both examples below produce a 75/25 split:

incoming_share: 0.75
outgoing_share: 0.25
incoming_share: 3
outgoing_share: 1

At least one share must be positive. Set one share to 1 and the other to 0 for single-direction traffic.

Per-host behavior

Each host receives:

  • a stable base weight;
  • an optional Zipf rank bias;
  • a smoothly changing AR(1) noise component.

Host scores are normalized after every model tick. As a result, individual host rates can change visibly while the total rate remains much more stable.

The same host weight is applied to both incoming and outgoing rates. This creates correlated request/response-like behavior, although the test tool does not maintain real sessions or matching five-tuples.

Peer networks

peer_networks must use the same address family as the corresponding internal cidr.

A peer is selected by first choosing one configured prefix and then choosing a random address within it. Prefix entries currently receive equal selection probability regardless of prefix size.

For example:

peer_networks:
  - "198.18.0.0/15"

provides roughly 131,000 usable IPv4 peer addresses.

A very broad prefix is technically accepted:

peer_networks:
  - "0.0.0.0/0"

However, the current implementation does not exclude private, loopback, link-local, multicast, documentation, or other reserved address ranges. Using 0.0.0.0/0 can therefore produce peers that FastNetMon classifies unexpectedly. Explicit external test ranges are safer and more reproducible.

Attack configuration

Example IPv4 UDP flood:

exporter:
  collector: "127.0.0.1:6343"
  agent_ip: "192.0.2.10"
  sub_agent_id: 1
  sampling_rate: 4096
  tick: "100ms"
  samples_per_datagram: 8
  seed: 1001

packet:
  mean_size: 900
  stddev: 220
  min_size: 64
  max_size: 1518

protocols:
  tcp: 0
  udp: 1
  icmp: 0

victim: "10.10.0.42"
direction: incoming
peak_rate: "15Gbps"
ramp_up: "20s"
hold: "3m"
ramp_down: "30s"
source_networks:
  - "198.18.0.0/15"
destination_port: 443
tcp_flags: syn

log_interval: "1s"
max_samples_per_tick: 100000

Attack fields

Field Description
victim Internal IPv4 or IPv6 address receiving or originating the attack traffic.
direction incoming or outgoing, from the perspective of the internal victim.
peak_rate Maximum represented attack rate.
ramp_up Time spent increasing from zero to peak_rate.
hold Time spent at peak_rate.
ramp_down Time spent decreasing from peak_rate to zero.
source_networks Remote networks used for generated peers. They must match the victim address family.
destination_port Transport destination port used in generated TCP or UDP headers.
tcp_flags syn, ack, or syn-ack. Used when TCP is selected.

A TCP SYN flood profile can be represented as:

protocols:
  tcp: 1
  udp: 0
  icmp: 0

tcp_flags: syn

An ICMP or ICMPv6 flood can be represented as:

protocols:
  tcp: 0
  udp: 0
  icmp: 1

Runtime output

Ambient example:

mode=ambient target=3.01Gbps target_in=2.25Gbps target_out=758.00Mbps estimated=3.00Gbps estimated_in=2.24Gbps estimated_out=760.00Mbps samples=102 datagrams=13 top=10.10.0.17@402.10Mbps

Attack example:

mode=attack victim=10.10.0.42 target=9.62Gbps estimated=9.59Gbps samples=326 datagrams=41 phase=ramp-up

target is the traffic rate requested by the model. estimated is the traffic volume represented by the emitted samples, not the actual bandwidth consumed by the generator's UDP datagrams.

Safety limits

max_samples_per_tick limits the amount of work performed during a single model update:

max_samples_per_tick: 100000

A configuration with a very high represented rate, a low sampling rate, small frames, or a very short tick can reach this limit. The generator then emits a warning and caps the generated sample count for that tick.

Current limitations

  • This is a sampled-header generator, not a real packet or application traffic generator.
  • No payload data is generated. The represented original size is carried in FrameLength.
  • Transport checksums are minimal or synthetic because the expected consumer parses headers rather than forwarding the packets through a network stack.
  • There is no stateful TCP, UDP, or request/response session model.
  • Incoming and outgoing ambient traffic is correlated by host weight but not matched by five-tuple.
  • There is no VLAN tagging, fragmentation, tunneled traffic, counter samples, PCAP replay, or BGP metadata.
  • Peer-prefix selection is uniform by configured prefix, not weighted by the number of addresses in each prefix.
  • Reserved or non-public addresses are not automatically excluded from broad peer prefixes.
  • The pinned github.com/Cistern/sflow version has reversed source-ID bit-field handling during encoding. exporter.go contains a local workaround for data-source interface indexes 1 and 2. Recheck this workaround before updating the dependency.

License

The source code is licensed under the Apache License 2.0.

Third-party dependencies retain their respective licenses. Required notices, including the BSD 3-Clause notice for github.com/Cistern/sflow, are included in THIRD_PARTY_NOTICES.md.

About

A small synthetic sFlow v5 generator intended for FastNetMon testing, demonstrations, dashboards, and attack-detection validation.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages