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.
This commit is contained in:
世界 2026-07-06 21:06:45 +08:00
parent 8403cdb937
commit fcbb7c473b
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -228,8 +228,11 @@ again:
func (s *StdNetBind) putMessages(msgs *[]ipv6.Message) { func (s *StdNetBind) putMessages(msgs *[]ipv6.Message) {
for i := range *msgs { for i := range *msgs {
(*msgs)[i].OOB = (*msgs)[i].OOB[:0] buffers := (*msgs)[i].Buffers
(*msgs)[i] = ipv6.Message{Buffers: (*msgs)[i].Buffers, OOB: (*msgs)[i].OOB} for j := range buffers {
buffers[j] = nil
}
(*msgs)[i] = ipv6.Message{Buffers: buffers[:1], OOB: (*msgs)[i].OOB[:0]}
} }
s.msgsPool.Put(msgs) s.msgsPool.Put(msgs)
} }
@ -491,6 +494,7 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offs
var ( var (
base = -1 // index of msg we are currently coalescing into base = -1 // index of msg we are currently coalescing into
gsoSize int // segmentation size of msgs[base] 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] dgramCnt int // number of dgrams coalesced into msgs[base]
endBatch bool // tracking flag to start a new batch on next iteration of bufs 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:] buf = buf[offset:]
if i > 0 { if i > 0 {
msgLen := len(buf) msgLen := len(buf)
baseLenBefore := len(msgs[base].Buffers[0]) if msgLen+totalLen <= maxPayloadLen &&
freeBaseCap := cap(msgs[base].Buffers[0]) - baseLenBefore
if msgLen+baseLenBefore <= maxPayloadLen &&
msgLen <= gsoSize && msgLen <= gsoSize &&
msgLen <= freeBaseCap &&
dgramCnt < udpSegmentMaxDatagrams && dgramCnt < udpSegmentMaxDatagrams &&
!endBatch { !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 { if i == len(bufs)-1 {
setGSO(&msgs[base].OOB, uint16(gsoSize)) setGSO(&msgs[base].OOB, uint16(gsoSize))
} }
@ -530,8 +534,9 @@ func coalesceMessages(addr *net.UDPAddr, ep *StdNetEndpoint, bufs [][]byte, offs
endBatch = false endBatch = false
base++ base++
gsoSize = len(buf) gsoSize = len(buf)
totalLen = len(buf)
setSrcControl(&msgs[base].OOB, ep) setSrcControl(&msgs[base].OOB, ep)
msgs[base].Buffers[0] = buf msgs[base].Buffers = append(msgs[base].Buffers[:0], buf)
msgs[base].Addr = addr msgs[base].Addr = addr
dgramCnt = 1 dgramCnt = 1
} }