mirror of
https://github.com/soypat/lneto.git
synced 2026-08-21 15:09:05 +00:00
Further reduce heap allocs (#56)
* work on tracking more heap allocations down * write own heapless IP AppendFormatAddr functions * remove potential Error method allocations * more logging
This commit is contained in:
+33
-16
@@ -172,31 +172,31 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
|
||||
debuglog("pcap:ipv6:reclaimed")
|
||||
proto := ifrm6.NextHeader()
|
||||
end := bitOffset + 40*octet
|
||||
var protoErrs []error
|
||||
var protoErr error
|
||||
var crc lneto.CRC791
|
||||
ifrm6.CRCWritePseudo(&crc)
|
||||
switch proto {
|
||||
case lneto.IPProtoTCP:
|
||||
if crc.PayloadSum16(ifrm6.Payload()) != 0 {
|
||||
protoErrs = append(protoErrs, lneto.ErrBadCRC)
|
||||
protoErr = lneto.ErrBadCRC
|
||||
}
|
||||
case lneto.IPProtoUDP, lneto.IPProtoUDPLite:
|
||||
ufrm, err := udp.NewFrame(ifrm6.Payload())
|
||||
if err != nil {
|
||||
protoErrs = append(protoErrs, err)
|
||||
protoErr = err
|
||||
break
|
||||
}
|
||||
ufrm.ValidateSize(pc.validator())
|
||||
if err = pc.validator().ErrPop(); err != nil {
|
||||
protoErrs = append(protoErrs, err)
|
||||
protoErr = err
|
||||
break
|
||||
}
|
||||
frameLen := ufrm.Length()
|
||||
if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
|
||||
protoErrs = append(protoErrs, lneto.ErrBadCRC)
|
||||
protoErr = lneto.ErrBadCRC
|
||||
}
|
||||
}
|
||||
return pc.captureIPProto(proto, dst, pkt, end, protoErrs...)
|
||||
return pc.captureIPProto(proto, dst, pkt, end, protoErr)
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
@@ -231,8 +231,9 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
debuglog("pcap:ipv4:crc-done")
|
||||
proto := ifrm4.Protocol()
|
||||
end := bitOffset + octet*ifrm4.HeaderLength()
|
||||
var protoErrs []error
|
||||
var crc lneto.CRC791
|
||||
|
||||
var ipProtoErr error
|
||||
payload := ifrm4.Payload()
|
||||
switch proto {
|
||||
case lneto.IPProtoTCP:
|
||||
@@ -244,7 +245,7 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
}
|
||||
ifrm4.CRCWriteTCPPseudo(&crc)
|
||||
if crc.PayloadSum16(payload) != 0 {
|
||||
protoErrs = append(protoErrs, lneto.ErrBadCRC)
|
||||
ipProtoErr = lneto.ErrBadCRC
|
||||
}
|
||||
}
|
||||
case lneto.IPProtoUDP:
|
||||
@@ -258,7 +259,7 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
frameLen := ufrm.Length()
|
||||
ifrm4.CRCWriteUDPPseudo(&crc, frameLen)
|
||||
if crc.PayloadSum16(ufrm.RawData()[:frameLen]) != 0 {
|
||||
protoErrs = append(protoErrs, lneto.ErrBadCRC)
|
||||
ipProtoErr = lneto.ErrBadCRC
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -266,15 +267,15 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
_, err := icmpv4.NewFrame(payload)
|
||||
if err == nil {
|
||||
if crc.PayloadSum16(payload) != 0 {
|
||||
protoErrs = append(protoErrs, lneto.ErrBadCRC)
|
||||
ipProtoErr = lneto.ErrBadCRC
|
||||
}
|
||||
}
|
||||
}
|
||||
debuglog("pcap:ipv4:proto-crc-done")
|
||||
return pc.captureIPProto(proto, dst, pkt, end, protoErrs...)
|
||||
return pc.captureIPProto(proto, dst, pkt, end, ipProtoErr)
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt []byte, bitOffset int, ipProtoErrs ...error) (_ []Frame, err error) {
|
||||
func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt []byte, bitOffset int, ipProtoErr error) (_ []Frame, err error) {
|
||||
debuglog("pcap:ipproto:start")
|
||||
nextFrame := len(dst)
|
||||
switch proto {
|
||||
@@ -292,8 +293,8 @@ func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt
|
||||
default:
|
||||
reclaimRemainingFrame(&dst, "unknown proto", 0, bitOffset, octet*len(pkt))
|
||||
}
|
||||
if len(ipProtoErrs) > 0 && len(dst) > nextFrame {
|
||||
dst[nextFrame].Errors = append(dst[nextFrame].Errors, ipProtoErrs...)
|
||||
if ipProtoErr != nil && len(dst) > nextFrame {
|
||||
dst[nextFrame].Errors = append(dst[nextFrame].Errors, ipProtoErr)
|
||||
}
|
||||
debuglog("pcap:ipproto:done")
|
||||
return dst, err
|
||||
@@ -441,15 +442,19 @@ func (pc *PacketBreakdown) CaptureDNS(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
if err != nil && !incomplete {
|
||||
return dst, err
|
||||
}
|
||||
debuglog("pcap:dns-decode")
|
||||
finfo := reclaimFrame(&dst, "DNS", bitOffset, nil)
|
||||
if incomplete {
|
||||
finfo.Errors = append(finfo.Errors, ErrLimitExceeded)
|
||||
}
|
||||
finfo.Fields = append(finfo.Fields[:0], FrameField{
|
||||
field := internal.SliceReclaim(&finfo.Fields)
|
||||
*field = FrameField{
|
||||
Name: "Data",
|
||||
FrameBitOffset: 0,
|
||||
BitLength: int(off) * octet,
|
||||
})
|
||||
SubFields: field.SubFields[:0], // Reuse subfields.
|
||||
}
|
||||
debuglog("pcap:dns-done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -463,6 +468,7 @@ func (pc *PacketBreakdown) CaptureNTP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
return dst, err
|
||||
}
|
||||
reclaimFrame(&dst, "NTP", bitOffset, baseNTPFields[:])
|
||||
debuglog("pcap:ntp")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -490,6 +496,7 @@ func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int)
|
||||
SubFields: optfield.SubFields[:0],
|
||||
Name: "options",
|
||||
}
|
||||
debuglog("pcap:dhcp-opt0")
|
||||
err = dfrm.ForEachOption(func(optoff int, opt dhcpv4.OptNum, data []byte) error {
|
||||
if len(optfield.SubFields) >= pc.SubfieldLimit {
|
||||
return ErrLimitExceeded
|
||||
@@ -541,11 +548,13 @@ func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int)
|
||||
optfield.SubFields = append(optfield.SubFields, field)
|
||||
return nil
|
||||
})
|
||||
debuglog("pcap:dhcp-opt1")
|
||||
// optfield already in finfo.Fields via SliceReclaim, no append needed.
|
||||
if err != nil {
|
||||
finfo.Errors = append(finfo.Errors, err)
|
||||
}
|
||||
}
|
||||
debuglog("pcap:dhcp-done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -739,6 +748,7 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
||||
}
|
||||
// Optimized path: field starts at byte boundary.
|
||||
dst = append(dst, pkt[octetsStart:octetsStart+octets]...)
|
||||
debuglog("pcap:appendField:optpath")
|
||||
if lastOctetExcessBits != 0 {
|
||||
dst[len(dst)-1] >>= lastOctetExcessBits
|
||||
}
|
||||
@@ -750,7 +760,9 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
||||
if lastOctetExcessBits == 0 {
|
||||
// Right aligned with no loose trailing bits. i.e: TCP flags.
|
||||
dst = append(dst, pkt[octetsStart]&mask)
|
||||
debuglog("pcap:appendField:rightalign1")
|
||||
dst = append(dst, pkt[octetsStart+1:octetsStart+octets]...)
|
||||
debuglog("pcap:appendField:rightalign2")
|
||||
return dst, nil
|
||||
}
|
||||
// Right aligned with trailing bits. i.e: IPv6 Traffic Class.
|
||||
@@ -762,6 +774,7 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
||||
b := (pkt[octetsStart+i] & mask) << (8 - firstBitOffset)
|
||||
b |= pkt[octetsStart+i+1] >> firstBitOffset
|
||||
dst = append(dst, b)
|
||||
debuglog("pcap:appendField:rightalign3")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
@@ -772,10 +785,12 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
||||
b := pkt[i+octetsStart] & mask
|
||||
b |= pkt[i+octetsStart+1] >> firstBitOffset
|
||||
dst = append(dst, b)
|
||||
debuglog("pcap:appendField:leftalign1")
|
||||
}
|
||||
lastOctet := pkt[octetsStart+octets-1] & mask
|
||||
lastOctet >>= lastOctetExcessBits
|
||||
dst = append(dst, lastOctet)
|
||||
debuglog("pcap:appendField:leftalign2")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -1341,6 +1356,7 @@ func reclaimFrame(dst *[]Frame, proto string, bitOffset int, baseFields []FrameF
|
||||
Fields: append(finfo.Fields[:0], baseFields...),
|
||||
Errors: finfo.Errors[:0],
|
||||
}
|
||||
debuglog("pcap:reclaim")
|
||||
return finfo
|
||||
}
|
||||
|
||||
@@ -1352,6 +1368,7 @@ func reclaimRemainingFrame(dst *[]Frame, proto string, class FieldClass, pktBitO
|
||||
Class: class,
|
||||
BitLength: pktBitLen - pktBitOffset,
|
||||
})
|
||||
debuglog("pcap:reclaim-rem")
|
||||
}
|
||||
|
||||
const enableDebug = internal.HeapAllocDebugging
|
||||
|
||||
+12
-3
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -14,6 +13,8 @@ import (
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/ipv6"
|
||||
"github.com/soypat/lneto/ntp"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
@@ -65,6 +66,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
dst = append(dst, " bitlen="...)
|
||||
dst = strconv.AppendInt(dst, int64(bitlen), 10)
|
||||
}
|
||||
debuglog("pcap:FormatFrame:int")
|
||||
|
||||
for ifield := range frm.Fields {
|
||||
field := frm.Fields[ifield]
|
||||
@@ -94,6 +96,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
dst = append(dst, ';')
|
||||
}
|
||||
dst = append(dst, err.Error()...)
|
||||
debuglog("pcap:fmtframe:error")
|
||||
}
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
@@ -122,6 +125,7 @@ func (f *Formatter) FormatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
dst, err = f.formatField(dst, pktStartOff, field.SubFields[i], pkt)
|
||||
}
|
||||
}
|
||||
debuglog("pcap:FormatField:end")
|
||||
return dst, err
|
||||
}
|
||||
|
||||
@@ -181,15 +185,20 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
return dst, err
|
||||
}
|
||||
dst = strconv.AppendUint(dst, v, 10)
|
||||
debuglog("pcap:fmtfield:uint")
|
||||
} else if field.BitLength == 4*8 {
|
||||
dst = netip.AddrFrom4([4]byte(f.buf)).AppendTo(dst)
|
||||
dst = ipv4.AppendFormatAddr(dst, [4]byte(f.buf))
|
||||
debuglog("pcap:fmtfield:addr4")
|
||||
} else if field.BitLength == 6*8 {
|
||||
dst = ethernet.AppendAddr(dst, [6]byte(f.buf))
|
||||
debuglog("pcap:fmtfield:addr6")
|
||||
} else if field.BitLength == 16*8 {
|
||||
dst = netip.AddrFrom16([16]byte(f.buf)).AppendTo(dst)
|
||||
dst = ipv6.AppendFormatAddr(dst, [16]byte(f.buf))
|
||||
debuglog("pcap:fmtfield:addr16")
|
||||
} else {
|
||||
dst = append(dst, "0x"...)
|
||||
dst = hex.AppendEncode(dst, f.buf)
|
||||
debuglog("pcap:fmtfield:addrN")
|
||||
}
|
||||
}
|
||||
return dst, err
|
||||
|
||||
Reference in New Issue
Block a user