From fcbb7c473b483653e279c4f86250bd48efa855e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 6 Jul 2026 21:06:45 +0800 Subject: [PATCH] Coalesce UDP GSO segments as iovecs coalesceMessages copied every additional datagram into the spare capacity of the first buffer, which no longer exists now that element buffers are sized to their packet; append the datagrams as iovecs instead, which also removes the copy. --- conn/bind_std.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/conn/bind_std.go b/conn/bind_std.go index 4dadb0d..3ff0408 100644 --- a/conn/bind_std.go +++ b/conn/bind_std.go @@ -228,8 +228,11 @@ again: func (s *StdNetBind) putMessages(msgs *[]ipv6.Message) { for i := range *msgs { - (*msgs)[i].OOB = (*msgs)[i].OOB[:0] - (*msgs)[i] = ipv6.Message{Buffers: (*msgs)[i].Buffers, OOB: (*msgs)[i].OOB} + buffers := (*msgs)[i].Buffers + for j := range buffers { + buffers[j] = nil + } + (*msgs)[i] = ipv6.Message{Buffers: buffers[:1], OOB: (*msgs)[i].OOB[:0]} } s.msgsPool.Put(msgs) } @@ -491,6 +494,7 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offs var ( base = -1 // index of msg we are currently coalescing into gsoSize int // segmentation size of msgs[base] + totalLen int // length of all dgrams coalesced into msgs[base] dgramCnt int // number of dgrams coalesced into msgs[base] endBatch bool // tracking flag to start a new batch on next iteration of bufs ) @@ -502,14 +506,14 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offs buf = buf[offset:] if i > 0 { msgLen := len(buf) - baseLenBefore := len(msgs[base].Buffers[0]) - freeBaseCap := cap(msgs[base].Buffers[0]) - baseLenBefore - if msgLen+baseLenBefore <= maxPayloadLen && + if msgLen+totalLen <= maxPayloadLen && msgLen <= gsoSize && - msgLen <= freeBaseCap && dgramCnt < udpSegmentMaxDatagrams && !endBatch { - msgs[base].Buffers[0] = append(msgs[base].Buffers[0], buf...) + // Coalesce as an additional iovec instead of copying: element + // buffers are sized to their packet and have no spare capacity. + msgs[base].Buffers = append(msgs[base].Buffers, buf) + totalLen += msgLen if i == len(bufs)-1 { setGSO(&msgs[base].OOB, uint16(gsoSize)) } @@ -530,8 +534,9 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offs endBatch = false base++ gsoSize = len(buf) + totalLen = len(buf) setSrcControl(&msgs[base].OOB, ep) - msgs[base].Buffers[0] = buf + msgs[base].Buffers = append(msgs[base].Buffers[:0], buf) msgs[base].Addr = addr dgramCnt = 1 }