tx_batch.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package batch
  2. import (
  3. "net/netip"
  4. "github.com/slackhq/nebula/util"
  5. )
  6. const SendBatchCap = 128
  7. // batchWriter is the minimal subset of udp.Conn needed by SendBatch to flush.
  8. type batchWriter interface {
  9. WriteBatch(bufs [][]byte, addrs []netip.AddrPort, outerECNs []byte) error
  10. }
  11. // SendBatch accumulates encrypted UDP packets and flushes them via WriteBatch.
  12. // One SendBatch is owned by each listenIn goroutine; no locking is needed.
  13. // Slot bytes are borrowed from the injected Arena and remain valid until
  14. // Flush, which Resets the arena.
  15. type SendBatch struct {
  16. out batchWriter
  17. bufs [][]byte
  18. dsts []netip.AddrPort
  19. ecns []byte
  20. arena *util.Arena
  21. }
  22. // NewSendBatch makes a SendBatch with batchCap slots backed by arena.
  23. func NewSendBatch(out batchWriter, batchCap int, arena *util.Arena) *SendBatch {
  24. return &SendBatch{
  25. out: out,
  26. bufs: make([][]byte, 0, batchCap),
  27. dsts: make([]netip.AddrPort, 0, batchCap),
  28. ecns: make([]byte, 0, batchCap),
  29. arena: arena,
  30. }
  31. }
  32. func (b *SendBatch) Reserve(sz int) []byte {
  33. return b.arena.Reserve(sz)
  34. }
  35. func (b *SendBatch) Commit(pkt []byte, dst netip.AddrPort, outerECN byte) {
  36. b.bufs = append(b.bufs, pkt)
  37. b.dsts = append(b.dsts, dst)
  38. b.ecns = append(b.ecns, outerECN)
  39. }
  40. func (b *SendBatch) Flush() error {
  41. var err error
  42. if len(b.bufs) > 0 {
  43. err = b.out.WriteBatch(b.bufs, b.dsts, b.ecns)
  44. }
  45. clear(b.bufs)
  46. b.bufs = b.bufs[:0]
  47. b.dsts = b.dsts[:0]
  48. b.ecns = b.ecns[:0]
  49. b.arena.Reset()
  50. return err
  51. }