xdp-trafficgen(8)

πŸ’– xdp-trafficgen(8) β€” An XDP-based traffic generator πŸ’–

okay bestie, sit down, hydrate, because we're about to talk about xdp-trafficgen β€” the little packet generator that could, and honestly did. It's an XDP-based traffic generator and it is so much faster than whatever you were using before, I promise.


✨ NAME ✨

xdp-trafficgen β€” an XDP-based traffic generator πŸ¦‹


✨ SYNOPSIS ✨

XDP-trafficgen is a packet generator that uses the XDP kernel subsystem to make packets and yeet them out a network interface. The packets get generated dynamically and transmitted inside the kernel, which is the whole reason it's got that millions of packets per second per core energy. No cap. πŸ”₯

It supports generating UDP traffic with fixed or dynamic destination ports, and it also has basic support for generating dummy TCP traffic on a single flow (that's the whole TCP situation, don't get your hopes up, it's giving "basic").

πŸƒ Running xdp-traffigen

The syntax for running xdp-trafficgen is:

Usage: xdp-trafficgen COMMAND [options]

COMMAND can be one of:
       udp         - run in UDP mode
       xsk-udp     - run in UDP mode (using AF_XDP sockets)
       tcp         - run in TCP mode
       probe       - probe kernel support

Every command and its options are explained down below, bestie. Or honestly, if you want the options for just one command, hit it with xdp-trafficgen COMMAND --help and it'll spill everything for that one. πŸ‘‘


🌸 The UDP command 🌸

The udp command generates UDP traffic to a destination IP you pick, and either a fixed destination port or a range of port numbers. Heads up though: only IPv6 traffic is supported, and the generated packets get their IP hop limit set to 1, so like... they cannot be routed. They live and die locally. It's giving homebody. πŸ’…

The syntax for the udp command is:

xdp-trafficgen udp [options] <ifname>

Where <ifname> is the name of the destination interface the packets get transmitted on. And bestie, listen: the network driver of this interface must support being the target of XDP redirects β€” it has to implement the ndo_xdp_xmit driver operation. If it doesn't, this whole thing is a no. 🫢

The supported options are:

⭐ OPTIONS (UDP) ⭐

  • -m, --dst-mac <mac addr> β€” sets the destination MAC address on the generated packets. Default vibe: all-zero destination MAC. πŸŽ€
  • -M, --src-mac <mac addr> β€” sets the source MAC address on the generated packets. Default is to just use the MAC address of the interface the packets go out on. Efficient, honestly.
  • -a, --dst-addr <addr> β€” the destination IP address of the generated packets. Defaults to the link-local fe80::2 address. 🌈
  • -A, --src-addr <addr> β€” the source IP address of the generated packets. Defaults to the link-local fe80::1 address.
  • -p, --dst-port <port> β€” destination UDP port of the generated packets, or the first port in the range if you're running with --dyn-ports set. Defaults to 1.
  • -P, --src-port <port> β€” source UDP port of the generated packets. Defaults to 1.
  • -d, --dyn-ports <num ports> β€” turns on dynamic port mode, where the destination port varies across a range of <num ports> starting from whatever you passed to --dst-port. Iconic.
  • -n, --num-packets <num packets> β€” how many packets to send before exiting. If you don't supply it, xdp-trafficgen just keeps going forever until you interrupt it. It will simply not stop. Periodt. πŸ’€
  • -s, --pkt-size <bytes> β€” size of each UDP packet being sent, including the Ethernet header and checksum. Since xdp-trafficgen generates IPv6 traffic, the minimum size β€” which is also the default β€” is 66 bytes.
⚠️ Lore drop: older versions of xdp-trafficgen failed to account for the four-byte ethernet checksum that gets added at the end of the packet, which meant 64 was allowed (and was the default) for the size, even though it actually generated 68-byte packets on the wire. To fix this bug without breaking existing users, values of 64 or 65 get clamped to the actual minimum value of 66 with a warning, instead of throwing an error. So you get a little scolding, not a crash. πŸ’–
  • -t, --threads <threads> β€” number of simultaneous threads to transmit from. Each thread gets pinned to its own CPU core if possible. Defaults to 1.
  • -I, --interval <s> β€” output transmission statistics at this interval, in seconds. πŸ•
  • -v, --verbose β€” enable verbose logging. Pass it twice (-vv) for more verbose.
  • --version β€” display version information and exit. bye! πŸ‘‹
  • -h, --help β€” display a summary of the available options.

πŸ¦‹ The XSK-UDP command πŸ¦‹

The xsk-udp command also generates UDP traffic, but it does it using an AF_XDP socket and generates the traffic in userspace. So if you want to test and benchmark AF_XDP sockets for transmitting, this is your girl. 🌸

The code for this command is derived from the xdpsock utility that used to live in the kernel sources, and more recently in the bpf-examples repository. This command corresponds to the --txonly option of xdpsock. So like, it has ancestors. Slay. πŸ‘‘

The syntax for this command is:

xdp-trafficgen xsk-udp [options] <ifname>

The supported options are:

⭐ OPTIONS (XSK-UDP) ⭐

  • -m, --dst-mac <mac addr> β€” sets the destination MAC address of the generated packets. Default is all-zero destination MAC, as always. πŸ’…
  • -M, --src-mac <mac addr> β€” sets the source MAC address of the generated packets. Default is to use the MAC address of the interface the packets are transmitted on.
  • -y, --timestamp β€” adds a timestamp to each packet, using the exact same header format the kernel pktgen utility uses. ✨
  • -V, --vlan-tag β€” adds a vlan tag to packets, using the ID and PRI you specify with the --vlan-id and --vlan-pri options.
  • -J, --vlan-id β€” sets the vlan ID used for packets. Only does anything when --vlan-tag is set. Default: 1.
  • -K, --vlan-pri β€” sets the vlan PRI used for packets. Only does anything when --vlan-tag is set. Default: 0.
  • -P, --fill-pattern <pattern> β€” use this pattern to fill the packet data. The pattern is given as a 32-bit hex value, and defaults to 0.
  • -T, --tx-cycle-time <us> β€” sets an interval between packet bursts, in microseconds. Each interval, a burst of --batch-size packets gets sent. Default is 0 β€” which means send as fast as humanly (machine-ly?) possible. πŸ”₯
  • -q, --queue <queue> β€” selects the hardware receive queue to use for the test. The AF_XDP socket is bound to this queue, which means xdp-trafficgen will process all packets arriving on it. Default is queue 0.
  • -i, --interval <seconds> β€” sets the polling interval for collecting all the statistics and printing them to the output. Default interval is 2 seconds.
  • -O, --retries <number> β€” sets the maximum number of retries when completing the last packets of a test run. When ending a run, xdp-trafficgen tries to release the last packet ring descriptors before exiting, retrying this many times with a 1-second interval in between. This is only used when --pkt-count is set.
  • -f, --frame-size <size> β€” sets the size of the memory frames used to transmit packets. Packets always use a memory chunk of this size, no matter how big the packet actually is on the wire. The size has to be a power of two, unless you're using --unaligned. Default is 4096 bytes, which corresponds to the page size on most systems. πŸŽ€
  • -s, --pkt-size <size> β€” sets the size of the packets being transmitted. Has to be between 64 and 9728 bytes, and defaults to 64.
  • -d, --duration <seconds> β€” sets the test duration in seconds. Default is 0, which means run forever, or until --pkt-count packets have been sent. 😭
  • -c, --pkt-count <number> β€” sets the total number of packets to transmit before exiting. Default is 0, which means run forever, or until --duration is reached.
  • -b, --batch-size <packets> β€” sets the batch size for the packet processing loop. This is how many packets get sent at once each time the loop runs. Default is 64 packets. Also go peek at --tx-cycle-time. πŸ‘€
  • -I, --irq-string <irq-string> β€” enables printing of interrupt statistics for the interrupt number associated with irq-string in /proc/interrupts. The string finds a matching IRQ number by simple substring matching. No default, which means no IRQ statistics get printed.
  • -p, --poll β€” use the poll() system call to get notifications for when a socket is ready to transmit new packets, instead of running in a loop constantly attempting to transmit. Rest, bestie. 🫢
  • -m, --no-need-wakeup β€” don't set the XDP_USE_NEED_WAKEUP flag when binding the AF_XDP socket. The flag is set by default, and it makes the kernel driver occasionally go to sleep and yield the CPU to the userspace application while processing packets.
  • -u, --unaligned β€” support sending unaligned packets, i.e., packets that aren't aligned to the beginning of a data frame. When set, xdp-trafficgen enables huge pages for the userspace memory buffer that holds the packet data being transmitted. Setting this option also enables frame sizes that are not a power of two (see --frame-size).
  • -M, --shared-umem β€” enable shared userspace memory across multiple AF_XDP sockets. When this is set, xdp-trafficgen creates four sockets that share the same userspace memory buffer, and packets get sent on each socket in a round-robin fashion. πŸ‘‘
  • -x, --extra-stats β€” print extra packet statistics at each output interval.
  • -Q, --quiet β€” don't print any statistics at each output interval. 🀫
  • -a, --app-stats β€” print additional application-level statistics at each output interval.
  • -C, --copy-mode <mode> β€” select the copying mode for the packets. Set it to one of auto, copy, or zero-copy. Default is auto, which lets the kernel pick. Using zero-copy requires kernel and driver support, and can only be used when attaching the XDP program in native mode (see --attach-mode). πŸ’€
  • -w, --clock <clock> β€” choose the clock used for all timer events in the application. Valid values are MONOTONIC, REALTIME, TAI and BOOTTIME, and the default is MONOTONIC.
  • -W, --policy <policy> β€” set the scheduler policy for the application before running. Valid values are SCHED_OTHER and SCHED_FIFO, and the default is SCHED_OTHER.
  • -U, --schpri <priority> β€” set the scheduler priority when using SCHED_FIFO. Defaults to 0.
  • -A, --attach-mode <mode> β€” set the XDP program attach mode (native or skb) of the XDP program that xdp-trafficgen attaches to the interface to enable XDP support. Default is native mode. Note that zero-copy can only be used in native mode. πŸŽ€
  • -v, --verbose β€” enable verbose logging. Supply it twice to also get verbose logging from the underlying libxdp and libbpf libraries.
  • --version β€” show the application version and exit.
  • -h, --help β€” display a summary of the available options.

okay and that's part one, bestie β€” there's more coming, so don't go anywhere πŸ’–

πŸ’« The TCP command πŸ’«

okay so this is the one where things get real: the TCP command generates dummy TCP traffic in a single TCP flow πŸŽ€. But β€” and this is the tea β˜• β€” it can't just do it by itself. It relies on first installing an ingress XDP program on the interface used to transmit on. Then a regular TCP socket connection is established from userspace, and once the handshake is done, the XDP program literally takes over and starts generating traffic on that flow tuple. main character behaviour, fr fr πŸ‘‘

And the ingress XDP program? It intercepts ACK packets coming back from the receiver and keeps track of the receive window. Very hands-on. Very attentive. 🫢

Now the part you need to know before you fall in love: this traffic generator has no congestion control, and only very basic retransmit tracking. Like, in essence: any duplicate ACKs from the receiver make the sender reset its send sequence number to the last ACKed value and restart from there. The exact same thing happens if no progress on the window is made within two seconds 😭. So yeah β€” it can generate a huge amount of dummy traffic, but if there's packet loss, a lot of what you're sending can just be retransmissions. Not a scam, just literally how it works πŸ’€

The syntax for the tcp command is:

xdp-trafficgen tcp [options] -i <ifname> <hostname>

Where <ifname> is the name of the destination interface that packets will be transmitted on, and <hostname> is the peer hostname or IP address to connect to (only IPv6 is supported, iykyk 🌈).

⚠️ heads up bestie: the network driver of this network interface must support being the target of XDP redirects β€” it has to implement the ndo_xdp_xmit driver operation. No ndo_xdp_xmit, no traffic. periodt.

✨ The supported options ✨

  • -p, --dst-port <port> β€” connect to destination <port>. Default is 10000. πŸ’…
  • -m, --mode <mode> β€” load the ingress XDP program in <mode>; the default is native. Valid values: native, skb, hw.
  • -n, --num-packets <port> β€” the number of packets to send before exiting. If you don't supply it, xdp-trafficgen will keep sending packets until it's interrupted. Forever girlie 🌸
  • -I, --interval <s> β€” output transmission statistics with this interval (in seconds). So you can watch the numbers go up. obsessed πŸ“ˆ
  • -v, --verbose β€” enable verbose logging (-vv for even more verbose). Spill the details πŸ”₯
  • --version β€” display version information and exit.
  • -h, --help β€” display a summary of the available options.

πŸ” The PROBE command πŸ”

bestie, this one is a vibe check for your kernel 🧚. The PROBE command probes the kernel to discover whether it supports the features needed to run xdp-trafficgen. So you can find out whether the running kernel is compatible with xdp-trafficgen, and whether a particular interface supports sending packets generated by xdp-trafficgen. Two birds, one probe πŸ¦‹

The syntax for the probe command is:

xdp-trafficgen probe [options]

After probing, xdp-trafficgen will print the results of the probing of the kernel, and β€” if an interface name is supplied β€” whether the interface supports sending packets generated by xdp-trafficgen. The exit code will be 0 if all probes succeed, and 1 otherwise. Simple as that πŸ’œ

⚠️ real talk though: the probing relies on the kernel XDP feature reporting, which was added after the XDP support itself. Which means that with some older kernel versions, the probing may fail even though xdp-trafficgen would in fact be able to transmit packets. So a fail here isn't always the whole story, ok?! Don't let it gaslight you 😭

✨ The supported options ✨

  • -i, --ifname <ifname> β€” probe the supplied interface name, in addition to doing the general kernel probing. πŸŽ€
  • -v, --verbose β€” enable verbose logging (-vv for even more verbose).
  • --version β€” display version information and exit.
  • -h, --help β€” display a summary of the available options.

πŸ› BUGS πŸ›

found a bug? spill it, bestie β€” please report any bugs on Github: https://github.com/xdp-project/xdp-tools/issues πŸ’–


πŸ‘‘ AUTHOR πŸ‘‘

xdp-trafficgen and this man page were written by Toke Høiland-Jørgensen. an absolute icon, we stan 🫢✨


and that's the whole page babes β€” this was xdp-trafficgen(8) version V1.6.3, dated FEBRUARY 19, 2026. slay, go generate some traffic, and stay hydrated πŸ’…πŸŒΈπŸ’–

πŸ“¦ where this page comes from