batch.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package nebula
  2. import "net/netip"
  3. // sendBatchCap is the maximum number of encrypted packets accumulated before a
  4. // flush is forced. TSO superpackets segment to at most ~45 packets on
  5. // reasonable MTUs, so 128 leaves headroom without bloating the backing
  6. // allocation.
  7. const sendBatchCap = 128
  8. // sendBatch accumulates encrypted UDP packets for a single sendmmsg flush.
  9. // One sendBatch is owned by each listenIn goroutine; no locking is needed.
  10. // The backing storage holds up to batchCap packets of slotCap bytes each;
  11. // bufs and dsts are parallel slices of committed slots.
  12. type sendBatch struct {
  13. bufs [][]byte
  14. dsts []netip.AddrPort
  15. backing []byte
  16. slotCap int
  17. batchCap int
  18. nextSlot int
  19. }
  20. func newSendBatch(batchCap, slotCap int) *sendBatch {
  21. return &sendBatch{
  22. bufs: make([][]byte, 0, batchCap),
  23. dsts: make([]netip.AddrPort, 0, batchCap),
  24. backing: make([]byte, batchCap*slotCap),
  25. slotCap: slotCap,
  26. batchCap: batchCap,
  27. }
  28. }
  29. // Next returns a zero-length slice with slotCap capacity over the next unused
  30. // slot's backing bytes. The caller writes into the returned slice and then
  31. // calls Commit with the final length and destination. Next returns nil when
  32. // the batch is full.
  33. func (b *sendBatch) Next() []byte {
  34. if b.nextSlot >= b.batchCap {
  35. return nil
  36. }
  37. start := b.nextSlot * b.slotCap
  38. return b.backing[start : start : start+b.slotCap]
  39. }
  40. // Commit records the slot just returned by Next as a packet of length n
  41. // destined for dst.
  42. func (b *sendBatch) Commit(n int, dst netip.AddrPort) {
  43. start := b.nextSlot * b.slotCap
  44. b.bufs = append(b.bufs, b.backing[start:start+n])
  45. b.dsts = append(b.dsts, dst)
  46. b.nextSlot++
  47. }
  48. // Reset clears committed slots; backing storage is retained for reuse.
  49. func (b *sendBatch) Reset() {
  50. b.bufs = b.bufs[:0]
  51. b.dsts = b.dsts[:0]
  52. b.nextSlot = 0
  53. }
  54. // Len returns the number of committed packets.
  55. func (b *sendBatch) Len() int {
  56. return len(b.bufs)
  57. }
  58. // Cap returns the maximum number of slots in the batch.
  59. func (b *sendBatch) Cap() int {
  60. return b.batchCap
  61. }