Add full-duplex raw-Ethernet 10G cable stress tester
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
etherType = 0x88b5
|
||||
ethHdrLen = 14
|
||||
hdrLen = 24
|
||||
hdrMagic = 0x43424c54
|
||||
minFrame = ethHdrLen + hdrLen
|
||||
maxFrame = 9216
|
||||
)
|
||||
|
||||
var crcTable = crc32.MakeTable(crc32.Castagnoli)
|
||||
|
||||
type pattern struct {
|
||||
name string
|
||||
fill func([]byte)
|
||||
}
|
||||
|
||||
var patterns = []pattern{
|
||||
{"zeros", func(b []byte) { clear(b) }},
|
||||
{"ones", func(b []byte) {
|
||||
for i := range b {
|
||||
b[i] = 0xff
|
||||
}
|
||||
}},
|
||||
{"alt", func(b []byte) {
|
||||
for i := range b {
|
||||
if i%2 == 0 {
|
||||
b[i] = 0x55
|
||||
} else {
|
||||
b[i] = 0xaa
|
||||
}
|
||||
}
|
||||
}},
|
||||
{"incr", func(b []byte) {
|
||||
for i := range b {
|
||||
b[i] = byte(i)
|
||||
}
|
||||
}},
|
||||
{"prbs", func(b []byte) {
|
||||
s := uint64(0x0123456789abcdef)
|
||||
for i := range b {
|
||||
s ^= s << 13
|
||||
s ^= s >> 7
|
||||
s ^= s << 17
|
||||
b[i] = byte(s)
|
||||
}
|
||||
}},
|
||||
{"random", func(b []byte) {
|
||||
r := rand.New(rand.NewPCG(0xc0ffee, 0x5eed))
|
||||
for i := range b {
|
||||
b[i] = byte(r.Uint32())
|
||||
}
|
||||
}},
|
||||
}
|
||||
|
||||
func patternIndex(name string) (int, error) {
|
||||
for i, p := range patterns {
|
||||
if p.name == name {
|
||||
return i, nil
|
||||
}
|
||||
}
|
||||
names := make([]string, len(patterns))
|
||||
for i, p := range patterns {
|
||||
names[i] = p.name
|
||||
}
|
||||
return 0, fmt.Errorf("unknown pattern %q (have %v)", name, names)
|
||||
}
|
||||
|
||||
type frameSpec struct {
|
||||
patIdx int
|
||||
ref []byte
|
||||
crcFor map[int]uint32
|
||||
dstMAC [6]byte
|
||||
srcMAC [6]byte
|
||||
sizes []int
|
||||
maxSize int
|
||||
}
|
||||
|
||||
func newFrameSpec(patIdx int, dst, src [6]byte, sizes []int) *frameSpec {
|
||||
maxSize := 0
|
||||
for _, s := range sizes {
|
||||
if s > maxSize {
|
||||
maxSize = s
|
||||
}
|
||||
}
|
||||
ref := make([]byte, maxSize-minFrame)
|
||||
patterns[patIdx].fill(ref)
|
||||
crcFor := make(map[int]uint32, len(sizes))
|
||||
for _, s := range sizes {
|
||||
crcFor[s] = crc32.Checksum(ref[:s-minFrame], crcTable)
|
||||
}
|
||||
return &frameSpec{
|
||||
patIdx: patIdx,
|
||||
ref: ref,
|
||||
crcFor: crcFor,
|
||||
dstMAC: dst,
|
||||
srcMAC: src,
|
||||
sizes: sizes,
|
||||
maxSize: maxSize,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *frameSpec) prefill(buf []byte) {
|
||||
copy(buf[0:6], f.dstMAC[:])
|
||||
copy(buf[6:12], f.srcMAC[:])
|
||||
binary.BigEndian.PutUint16(buf[12:14], etherType)
|
||||
copy(buf[minFrame:], f.ref)
|
||||
}
|
||||
|
||||
func putHeader(buf []byte, patIdx int, stream uint16, seq uint64, payLen int, crc uint32) {
|
||||
h := buf[ethHdrLen:]
|
||||
binary.BigEndian.PutUint32(h[0:4], hdrMagic)
|
||||
h[4] = 1
|
||||
h[5] = byte(patIdx)
|
||||
binary.BigEndian.PutUint16(h[6:8], stream)
|
||||
binary.BigEndian.PutUint64(h[8:16], seq)
|
||||
binary.BigEndian.PutUint16(h[16:18], uint16(payLen))
|
||||
binary.BigEndian.PutUint16(h[18:20], 0)
|
||||
binary.BigEndian.PutUint32(h[20:24], crc)
|
||||
}
|
||||
|
||||
type parsed struct {
|
||||
patIdx int
|
||||
stream uint16
|
||||
seq uint64
|
||||
payLen int
|
||||
crc uint32
|
||||
}
|
||||
|
||||
func parseHeader(buf []byte) (parsed, bool) {
|
||||
var p parsed
|
||||
if len(buf) < minFrame {
|
||||
return p, false
|
||||
}
|
||||
h := buf[ethHdrLen:]
|
||||
if binary.BigEndian.Uint32(h[0:4]) != hdrMagic {
|
||||
return p, false
|
||||
}
|
||||
p.patIdx = int(h[5])
|
||||
p.stream = binary.BigEndian.Uint16(h[6:8])
|
||||
p.seq = binary.BigEndian.Uint64(h[8:16])
|
||||
p.payLen = int(binary.BigEndian.Uint16(h[16:18]))
|
||||
p.crc = binary.BigEndian.Uint32(h[20:24])
|
||||
if minFrame+p.payLen > len(buf) {
|
||||
return p, false
|
||||
}
|
||||
return p, true
|
||||
}
|
||||
|
||||
func firstDiff(got, want []byte) (int, int) {
|
||||
n := len(got)
|
||||
if len(want) < n {
|
||||
n = len(want)
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if got[i] != want[i] {
|
||||
bits := 0
|
||||
x := got[i] ^ want[i]
|
||||
for x != 0 {
|
||||
bits += int(x & 1)
|
||||
x >>= 1
|
||||
}
|
||||
return i, bits
|
||||
}
|
||||
}
|
||||
return -1, 0
|
||||
}
|
||||
Reference in New Issue
Block a user