diff --git a/frame.go b/frame.go index c5ee585..4a8fef5 100644 --- a/frame.go +++ b/frame.go @@ -9,7 +9,7 @@ import ( const ( etherBase = 0x88b5 ethHdrLen = 14 - hdrLen = 24 + hdrLen = 20 hdrMagic = 0x43424c54 minFrame = ethHdrLen + hdrLen maxFrame = 9216 @@ -88,7 +88,7 @@ func newFrameSpec(dst, src [6]byte, etherType uint16, sizes []int) *frameSpec { fill(ref) crcFor := make(map[int]uint32, len(sizes)) for _, s := range sizes { - crcFor[s] = crc32.Checksum(ref[:s-minFrame], crcTable) + crcFor[s-minFrame] = crc32.Checksum(ref[:s-minFrame], crcTable) } f.refs = append(f.refs, ref) f.crcFor = append(f.crcFor, crcFor) @@ -103,7 +103,17 @@ func (f *frameSpec) prefill(buf []byte, patIdx int) { copy(buf[minFrame:], f.refs[patIdx]) } -func putHeader(buf []byte, patIdx int, stream uint16, seq uint64, payLen int, crc uint32) { +// Looked up rather than read from the frame: a checksum travelling beside the +// bytes it covers is only ever compared against itself. +func (f *frameSpec) expectedCRC(patIdx, payLen int) (uint32, bool) { + if patIdx < 0 || patIdx >= len(f.crcFor) { + return 0, false + } + crc, ok := f.crcFor[patIdx][payLen] + return crc, ok +} + +func putHeader(buf []byte, patIdx int, stream uint16, seq uint64, payLen int) { h := buf[ethHdrLen:] binary.BigEndian.PutUint32(h[0:4], hdrMagic) h[4] = 1 @@ -112,7 +122,6 @@ func putHeader(buf []byte, patIdx int, stream uint16, seq uint64, payLen int, cr 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 { @@ -120,7 +129,6 @@ type parsed struct { stream uint16 seq uint64 payLen int - crc uint32 } func parseHeader(buf []byte) (parsed, bool) { @@ -136,7 +144,6 @@ func parseHeader(buf []byte) (parsed, bool) { 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 } diff --git a/probe.go b/probe.go index ab521b5..73c8c47 100644 --- a/probe.go +++ b/probe.go @@ -156,8 +156,7 @@ func (p *probeSender) run(done *atomic.Bool, startTx <-chan struct{}) { } } - putHeader(buf, probePattern, probeStream, seq, probeSize-minFrame, - p.spec.crcFor[probePattern][probeSize]) + putHeader(buf, probePattern, probeStream, seq, probeSize-minFrame) err := unix.Send(p.fd, buf, 0) // The sequence advances even when a probe fails, so a stale receive half // can never be paired with a later probe that reused its number. diff --git a/rx.go b/rx.go index df97cd2..5bc0ff7 100644 --- a/rx.go +++ b/rx.go @@ -61,12 +61,13 @@ func (w *rxWorker) run(done *atomic.Bool) { w.streams[p.stream].observe(p.seq) } - if p.payLen > w.spec.maxPay { + want, ok := w.spec.expectedCRC(p.patIdx, p.payLen) + if !ok { w.stats.badLen.Add(1) continue } pay := buf[minFrame : minFrame+p.payLen] - if crc32.Checksum(pay, crcTable) != p.crc { + if crc32.Checksum(pay, crcTable) != want { w.stats.crcErr.Add(1) } } diff --git a/tx.go b/tx.go index 292cc57..e2d6b8e 100644 --- a/tx.go +++ b/tx.go @@ -48,8 +48,7 @@ func (w *txWorker) run(done *atomic.Bool) { si = 0 } sizes[i] = size - putHeader(bufs[i], pats[i], w.stream, seq+uint64(i), size-minFrame, - w.spec.crcFor[pats[i]][size]) + putHeader(bufs[i], pats[i], w.stream, seq+uint64(i), size-minFrame) iovs[i].Len = uint64(size) }