diff --git a/interface.go b/interface.go index 8232e9cc..8c1980db 100644 --- a/interface.go +++ b/interface.go @@ -304,7 +304,10 @@ func (f *Interface) listenIn(reader io.ReadWriteCloser, i int) { func (f *Interface) listenInSingle(reader io.ReadWriteCloser, i int) { packet := make([]byte, mtu) - out := make([]byte, mtu) + // Allocate out buffer with virtio header headroom (10 bytes) to avoid copies on write + const virtioNetHdrLen = 10 + outBuf := make([]byte, virtioNetHdrLen+mtu) + out := outBuf[virtioNetHdrLen:] // Use slice starting after headroom fwPacket := &firewall.Packet{} nb := make([]byte, 12, 12) @@ -328,6 +331,7 @@ func (f *Interface) listenInSingle(reader io.ReadWriteCloser, i int) { func (f *Interface) listenInBatch(reader io.ReadWriteCloser, batchReader BatchReader, i int) { batchSize := batchReader.BatchSize() + const virtioNetHdrLen = 10 // Allocate buffers for batch reading bufs := make([][]byte, batchSize) @@ -337,7 +341,9 @@ func (f *Interface) listenInBatch(reader io.ReadWriteCloser, batchReader BatchRe sizes := make([]int, batchSize) // Per-packet state (reused across batches) - out := make([]byte, mtu) + // Allocate out buffer with virtio header headroom to avoid copies on write + outBuf := make([]byte, virtioNetHdrLen+mtu) + out := outBuf[virtioNetHdrLen:] fwPacket := &firewall.Packet{} nb := make([]byte, 12, 12) diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 7c2bcd03..6bbc29e5 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -92,9 +92,24 @@ func (w *wgDeviceWrapper) Read(b []byte) (int, error) { } func (w *wgDeviceWrapper) Write(b []byte) (int, error) { - // Allocate buffer with space for virtio header - buf := make([]byte, virtioNetHdrLen+len(b)) - copy(buf[virtioNetHdrLen:], b) + // Check if buffer has the expected headroom pattern to avoid copy + var buf []byte + + if cap(b) >= len(b)+virtioNetHdrLen { + buf = b[:cap(b)] + if len(buf) == len(b)+virtioNetHdrLen { + // Perfect! Buffer has headroom, no copy needed + buf = buf[:len(b)+virtioNetHdrLen] + } else { + // Unexpected capacity, safer to copy + buf = make([]byte, virtioNetHdrLen+len(b)) + copy(buf[virtioNetHdrLen:], b) + } + } else { + // No headroom, need to allocate and copy + buf = make([]byte, virtioNetHdrLen+len(b)) + copy(buf[virtioNetHdrLen:], b) + } bufs := [][]byte{buf} n, err := w.dev.Write(bufs, virtioNetHdrLen) @@ -408,9 +423,28 @@ func (t *tun) BatchSize() int { func (t *tun) Write(b []byte) (int, error) { if t.wgDevice != nil { // Use wireguard device which handles virtio headers internally - // Allocate buffer with space for virtio header - buf := make([]byte, virtioNetHdrLen+len(b)) - copy(buf[virtioNetHdrLen:], b) + // Check if buffer has the expected headroom pattern: + // cap(b) should be len(b) + virtioNetHdrLen, indicating pre-allocated headroom + var buf []byte + + if cap(b) >= len(b)+virtioNetHdrLen { + // Buffer likely has headroom - use unsafe to access it + // Create a slice that includes the headroom by re-slicing from capacity + buf = b[:cap(b)] + // Check if we have exactly the right amount of extra capacity + if len(buf) == len(b)+virtioNetHdrLen { + // Perfect! This buffer was allocated with headroom, no copy needed + buf = buf[:len(b)+virtioNetHdrLen] + } else { + // Unexpected capacity, safer to copy + buf = make([]byte, virtioNetHdrLen+len(b)) + copy(buf[virtioNetHdrLen:], b) + } + } else { + // No headroom, need to allocate and copy + buf = make([]byte, virtioNetHdrLen+len(b)) + copy(buf[virtioNetHdrLen:], b) + } bufs := [][]byte{buf} n, err := t.wgDevice.Write(bufs, virtioNetHdrLen)