Add full-duplex raw-Ethernet 10G cable stress tester
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type rxStats struct {
|
||||
frames atomic.Uint64
|
||||
bytes atomic.Uint64
|
||||
badMagic atomic.Uint64
|
||||
badLen atomic.Uint64
|
||||
crcErr atomic.Uint64
|
||||
_ [24]byte
|
||||
}
|
||||
|
||||
type streamState struct {
|
||||
maxSeq atomic.Uint64
|
||||
count atomic.Uint64
|
||||
_ [48]byte
|
||||
}
|
||||
|
||||
type rxWorker struct {
|
||||
fd int
|
||||
batch int
|
||||
cpu int
|
||||
verify bool
|
||||
spec *frameSpec
|
||||
stats *rxStats
|
||||
streams []streamState
|
||||
reports chan string
|
||||
ready *sync.WaitGroup
|
||||
}
|
||||
|
||||
func (w *rxWorker) run(done *atomic.Bool) {
|
||||
pinTo(w.cpu)
|
||||
|
||||
bufs := make([][]byte, w.batch)
|
||||
for i := range bufs {
|
||||
bufs[i] = make([]byte, maxFrame)
|
||||
for j := 0; j < maxFrame; j += 4096 {
|
||||
bufs[i][j] = 0
|
||||
}
|
||||
}
|
||||
hdrs, _ := newMmsghdrs(bufs)
|
||||
|
||||
w.ready.Done()
|
||||
|
||||
for !done.Load() {
|
||||
n, err := recvmmsg(w.fd, hdrs, unix.MSG_WAITFORONE)
|
||||
if n <= 0 {
|
||||
if err != nil && err != unix.EAGAIN && err != unix.EINTR {
|
||||
w.report(fmt.Sprintf("recvmmsg: %v", err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
buf := bufs[i][:int(hdrs[i].len)]
|
||||
p, ok := parseHeader(buf)
|
||||
if !ok {
|
||||
w.stats.badMagic.Add(1)
|
||||
continue
|
||||
}
|
||||
w.stats.frames.Add(1)
|
||||
w.stats.bytes.Add(uint64(len(buf)))
|
||||
|
||||
if int(p.stream) < len(w.streams) {
|
||||
st := &w.streams[p.stream]
|
||||
st.count.Add(1)
|
||||
for {
|
||||
old := st.maxSeq.Load()
|
||||
if p.seq <= old || st.maxSeq.CompareAndSwap(old, p.seq) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !w.verify {
|
||||
continue
|
||||
}
|
||||
if p.payLen > len(w.spec.ref) {
|
||||
w.stats.badLen.Add(1)
|
||||
continue
|
||||
}
|
||||
pay := buf[minFrame : minFrame+p.payLen]
|
||||
if crc32.Checksum(pay, crcTable) == p.crc {
|
||||
continue
|
||||
}
|
||||
w.stats.crcErr.Add(1)
|
||||
off, bits := firstDiff(pay, w.spec.ref[:p.payLen])
|
||||
w.report(fmt.Sprintf("payload mismatch stream=%d seq=%d len=%d first-diff-offset=%d bits=%d",
|
||||
p.stream, p.seq, p.payLen, off, bits))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *rxWorker) report(msg string) {
|
||||
select {
|
||||
case w.reports <- msg:
|
||||
default:
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user