what about with bad GRO on UDP

This commit is contained in:
JackDoan
2025-11-10 14:47:38 -06:00
parent 42591c2042
commit c645a45438
8 changed files with 411 additions and 223 deletions

23
packet/outpacket.go Normal file
View File

@@ -0,0 +1,23 @@
package packet
type OutPacket struct {
Segments [][]byte
//todo virtio header?
SegSize int
SegCounter int
Valid bool
wasSegmented bool
Scratch []byte
}
func NewOut() *OutPacket {
out := new(OutPacket)
const numSegments = 64
out.Segments = make([][]byte, numSegments)
for i := 0; i < numSegments; i++ { //todo this is dumb
out.Segments[i] = make([]byte, Size)
}
out.Scratch = make([]byte, Size)
return out
}

117
packet/packet.go Normal file
View File

@@ -0,0 +1,117 @@
package packet
import (
"encoding/binary"
"iter"
"net/netip"
"golang.org/x/sys/unix"
)
const Size = 0xffff
type Packet struct {
Payload []byte
Control []byte
Name []byte
SegSize int
//todo should this hold out as well?
OutLen int
wasSegmented bool
isV4 bool
//Addr netip.AddrPort
}
func New(isV4 bool) *Packet {
return &Packet{
Payload: make([]byte, Size),
Control: make([]byte, unix.CmsgSpace(2)),
Name: make([]byte, unix.SizeofSockaddrInet6),
isV4: isV4,
}
}
func (p *Packet) AddrPort() netip.AddrPort {
var ip netip.Addr
// Its ok to skip the ok check here, the slicing is the only error that can occur and it will panic
if p.isV4 {
ip, _ = netip.AddrFromSlice(p.Name[4:8])
} else {
ip, _ = netip.AddrFromSlice(p.Name[8:24])
}
return netip.AddrPortFrom(ip.Unmap(), binary.BigEndian.Uint16(p.Name[2:4]))
}
func (p *Packet) updateCtrl(ctrlLen int) {
p.SegSize = len(p.Payload)
p.wasSegmented = false
if ctrlLen == 0 {
return
}
if len(p.Control) == 0 {
return
}
cmsgs, err := unix.ParseSocketControlMessage(p.Control)
if err != nil {
return // oh well
}
for _, c := range cmsgs {
if c.Header.Level == unix.SOL_UDP && c.Header.Type == unix.UDP_GRO && len(c.Data) >= 2 {
p.wasSegmented = true
p.SegSize = int(binary.LittleEndian.Uint16(c.Data[:2]))
return
}
}
}
// Update sets a Packet into "just received, not processed" state
func (p *Packet) Update(ctrlLen int) {
p.OutLen = -1
p.updateCtrl(ctrlLen)
}
func (p *Packet) Segments() iter.Seq[[]byte] {
return func(yield func([]byte) bool) {
//cursor := 0
for offset := 0; offset < len(p.Payload); offset += p.SegSize {
end := offset + p.SegSize
if end > len(p.Payload) {
end = len(p.Payload)
}
if !yield(p.Payload[offset:end]) {
return
}
}
//if p.SegSize > 0 && p.SegSize < len(p.Payload) {
//
//} else {
// f.readOutsidePackets(p.Addr, nil, result2[:0], p.Payload, h, fwPacket2, lhh, nb2, i, conntrackCache.Get(f.l))
//}
}
}
//type Pool struct {
// pool sync.Pool
//}
//
//var bigPool = &Pool{
// pool: sync.Pool{New: func() any { return New() }},
//}
//
//func GetPool() *Pool {
// return bigPool
//}
//
//func (p *Pool) Get() *Packet {
// return p.pool.Get().(*Packet)
//}
//
//func (p *Pool) Put(x *Packet) {
// x.Payload = x.Payload[:Size]
// p.pool.Put(x)
//}