Go + DPDK in < 100 lines with packetio - Sending 148 million packets/sec

//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()
}
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论