diff --git a/batch.go b/batch.go deleted file mode 100644 index 02d86bc7..00000000 --- a/batch.go +++ /dev/null @@ -1,70 +0,0 @@ -package nebula - -import "net/netip" - -// sendBatchCap is the maximum number of encrypted packets accumulated before a -// flush is forced. TSO superpackets segment to at most ~45 packets on -// reasonable MTUs, so 128 leaves headroom without bloating the backing -// allocation. -const sendBatchCap = 128 - -// sendBatch accumulates encrypted UDP packets for a single sendmmsg flush. -// One sendBatch is owned by each listenIn goroutine; no locking is needed. -// The backing storage holds up to batchCap packets of slotCap bytes each; -// bufs and dsts are parallel slices of committed slots. -type sendBatch struct { - bufs [][]byte - dsts []netip.AddrPort - backing []byte - slotCap int - batchCap int - nextSlot int -} - -func newSendBatch(batchCap, slotCap int) *sendBatch { - return &sendBatch{ - bufs: make([][]byte, 0, batchCap), - dsts: make([]netip.AddrPort, 0, batchCap), - backing: make([]byte, batchCap*slotCap), - slotCap: slotCap, - batchCap: batchCap, - } -} - -// Next returns a zero-length slice with slotCap capacity over the next unused -// slot's backing bytes. The caller writes into the returned slice and then -// calls Commit with the final length and destination. Next returns nil when -// the batch is full. -func (b *sendBatch) Next() []byte { - if b.nextSlot >= b.batchCap { - return nil - } - start := b.nextSlot * b.slotCap - return b.backing[start : start : start+b.slotCap] -} - -// Commit records the slot just returned by Next as a packet of length n -// destined for dst. -func (b *sendBatch) Commit(n int, dst netip.AddrPort) { - start := b.nextSlot * b.slotCap - b.bufs = append(b.bufs, b.backing[start:start+n]) - b.dsts = append(b.dsts, dst) - b.nextSlot++ -} - -// Reset clears committed slots; backing storage is retained for reuse. -func (b *sendBatch) Reset() { - b.bufs = b.bufs[:0] - b.dsts = b.dsts[:0] - b.nextSlot = 0 -} - -// Len returns the number of committed packets. -func (b *sendBatch) Len() int { - return len(b.bufs) -} - -// Cap returns the maximum number of slots in the batch. -func (b *sendBatch) Cap() int { - return b.batchCap -} diff --git a/batch_test.go b/batch_test.go deleted file mode 100644 index ee72c63e..00000000 --- a/batch_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package nebula - -import ( - "net/netip" - "testing" -) - -func TestSendBatchBookkeeping(t *testing.T) { - b := newSendBatch(4, 32) - if b.Len() != 0 || b.Cap() != 4 { - t.Fatalf("fresh batch: len=%d cap=%d", b.Len(), b.Cap()) - } - - ap := netip.MustParseAddrPort("10.0.0.1:4242") - for i := 0; i < 4; i++ { - slot := b.Next() - if slot == nil { - t.Fatalf("slot %d: Next returned nil before cap", i) - } - if cap(slot) != 32 || len(slot) != 0 { - t.Fatalf("slot %d: got len=%d cap=%d want len=0 cap=32", i, len(slot), cap(slot)) - } - // Write a marker byte. - slot = append(slot, byte(i), byte(i+1), byte(i+2)) - b.Commit(len(slot), ap) - } - if b.Next() != nil { - t.Fatalf("Next should return nil when full") - } - if b.Len() != 4 { - t.Fatalf("Len=%d want 4", b.Len()) - } - for i, buf := range b.bufs { - if len(buf) != 3 || buf[0] != byte(i) { - t.Errorf("buf %d: %x", i, buf) - } - if b.dsts[i] != ap { - t.Errorf("dst %d: got %v want %v", i, b.dsts[i], ap) - } - } - - // Reset returns empty and Next works again. - b.Reset() - if b.Len() != 0 { - t.Fatalf("after Reset Len=%d want 0", b.Len()) - } - slot := b.Next() - if slot == nil || cap(slot) != 32 { - t.Fatalf("after Reset Next nil or wrong cap: %v cap=%d", slot == nil, cap(slot)) - } -} - -func TestSendBatchSlotsDoNotOverlap(t *testing.T) { - b := newSendBatch(3, 8) - ap := netip.MustParseAddrPort("10.0.0.1:80") - - // Fill three slots, each with its own sentinel byte. - for i := 0; i < 3; i++ { - s := b.Next() - s = append(s, byte(0xA0+i), byte(0xB0+i)) - b.Commit(len(s), ap) - } - - for i, buf := range b.bufs { - if buf[0] != byte(0xA0+i) || buf[1] != byte(0xB0+i) { - t.Errorf("slot %d corrupted: %x", i, buf) - } - } -}