-
-
Save gsitgithub/db33aa76f54d3a3a87187f8f156ac5e0 to your computer and use it in GitHub Desktop.
Go + DPDK in < 100 lines with packetio - Sending 148 million packets/sec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //go:build dpdk | |
| // Blast dummy UDP packets over several queues (one core each) and print | |
| // packets/sec. ~45 lines of Go driving DPDK through github.com/atoonk/packetio, | |
| // hitting 64-byte line rate on a 100G ConnectX. | |
| // | |
| // Build & run (needs libdpdk installed, e.g. `apt install libdpdk-dev`): | |
| // | |
| // mkdir blast && cd blast # drop this file in as main.go | |
| // go mod init blast | |
| // go get github.com/atoonk/packetio | |
| // go build -tags dpdk -o blast . | |
| // sudo ./blast // needs root for DPDK | |
| // | |
| // Example output (4 queues, 64-byte frames, ConnectX-6 Dx at 100G): | |
| // | |
| // 148.0 Mpps | |
| // 148.7 Mpps | |
| // 148.7 Mpps | |
| // 148.7 Mpps | |
| // 148.7 Mpps | |
| // | |
| // One queue does ~58 Mpps; more queues = more cores = more pps, up to the wire. | |
| // The same code runs on mlx5, AF_XDP or AF_PACKET by changing the import. | |
| package main | |
| import ( | |
| "fmt" | |
| "log" | |
| "sync" | |
| "sync/atomic" | |
| "time" | |
| "github.com/atoonk/packetio" | |
| "github.com/atoonk/packetio/dpdk" | |
| ) | |
| const ( | |
| device = "0000:c1:00.0" // your NIC's PCI address | |
| queues = 4 // one core each; more queues = more cores = more pps | |
| seconds = 5 | |
| ) | |
| // Empty UDP datagram to 192.0.2.2, routed via the gateway. | |
| var packet = []byte{ | |
| 0xb0, 0x8b, 0xcf, 0x4b, 0xcf, 0x3d, // dst: router MAC (your next hop) | |
| 0x7c, 0xc2, 0x55, 0xbe, 0xf4, 0xe0, // src: this NIC's MAC | |
| 0x08, 0x00, // IPv4 | |
| 0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0xb6, 0xcd, | |
| 0xc0, 0x00, 0x02, 0x01, // src IP 192.0.2.1 | |
| 0xc0, 0x00, 0x02, 0x02, // dst IP 192.0.2.2 | |
| 0x30, 0x39, 0x23, 0x28, 0x00, 0x08, 0x00, 0x00, // UDP :12345 -> :9000, empty | |
| } | |
| func main() { | |
| d, err := dpdk.Open(device, dpdk.WithTxQueues(queues)) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer d.Close() | |
| var sent atomic.Uint64 | |
| var wg sync.WaitGroup | |
| start := time.Now() | |
| // One goroutine per queue: each runs on its own core. | |
| for q := 0; q < queues; q++ { | |
| wg.Add(1) | |
| go func(tx packetio.TxQueue) { | |
| defer wg.Done() | |
| for time.Since(start) < seconds*time.Second { | |
| n, err := tx.SendFunc(256, func(i int, frame []byte) int { | |
| return copy(frame, packet) | |
| }) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| sent.Add(uint64(n)) | |
| } | |
| }(d.TxQueue(q)) | |
| } | |
| // Print the running rate once a second. | |
| go func() { | |
| last := uint64(0) | |
| for range time.Tick(time.Second) { | |
| now := sent.Load() | |
| fmt.Printf("%.1f Mpps\n", float64(now-last)/1e6) | |
| last = now | |
| } | |
| }() | |
| wg.Wait() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment