mirror of
https://github.com/soypat/lneto.git
synced 2026-08-24 00:19:03 +00:00
Reduce heap allocs 2 (#46)
* reduce heap allocations in tcp logging; omit use of AppendFloat which allocates a metric sh*tton * debugheaplog: better heap statistic logging * heap: use string for pcap.Frame.Protocol * add potential to eliminate Flags.String heap alloc, remove incorrect HEAP comments * add StackAsync.DebugErr and httpraw.SetBytes * many heap alloc reductions and replacement of bytes.Equal with internal.BytesEqual
This commit is contained in:
@@ -21,6 +21,7 @@ func (s *cbnode) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int)
|
||||
}
|
||||
|
||||
func (s *cbnode) Demux(carrierData []byte, frameOffset int) error {
|
||||
debugLog("cbnode:pre-demux")
|
||||
return s._demux(carrierData, frameOffset)
|
||||
}
|
||||
|
||||
|
||||
+53
-22
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
@@ -29,12 +30,6 @@ var (
|
||||
ErrFieldByClassNotFound = errors.New("pcap: field by class not found")
|
||||
)
|
||||
|
||||
type proto string
|
||||
|
||||
const (
|
||||
ProtoEthernet proto = "Ethernet"
|
||||
)
|
||||
|
||||
type PacketBreakdown struct {
|
||||
hdr httpraw.Header
|
||||
dmsg dns.Message
|
||||
@@ -66,8 +61,10 @@ func (pc *PacketBreakdown) initFrames() []Frame {
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:eth:start")
|
||||
if dst == nil {
|
||||
dst = pc.initFrames()
|
||||
debuglog("pcap:eth:initframes")
|
||||
}
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("ethernet must be parsed at byte boundary")
|
||||
@@ -80,8 +77,10 @@ func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset in
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
debuglog("pcap:eth:validated")
|
||||
|
||||
finfo := reclaimFrame(&dst, ProtoEthernet, bitOffset, baseEthernetFields[:])
|
||||
finfo := reclaimFrame(&dst, "Ethernet", bitOffset, baseEthernetFields[:])
|
||||
debuglog("pcap:eth:reclaimed")
|
||||
etype := efrm.EtherTypeOrSize()
|
||||
end := 14*octet + bitOffset
|
||||
if etype.IsSize() {
|
||||
@@ -102,12 +101,14 @@ func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset in
|
||||
case ethernet.TypeIPv6:
|
||||
dst, err = pc.CaptureIPv6(dst, pkt, end)
|
||||
default:
|
||||
reclaimRemainingFrame(&dst, etype, FieldClassPayload, end, octet*len(pkt))
|
||||
reclaimRemainingFrame(&dst, "Unknown Ethertype", FieldClassPayload, end, octet*len(pkt))
|
||||
}
|
||||
debuglog("pcap:eth:done")
|
||||
return dst, err
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:arp:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("ARP must be parsed at byte boundary")
|
||||
}
|
||||
@@ -120,7 +121,7 @@ func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
|
||||
finfo := reclaimFrame(&dst, ethernet.TypeARP, bitOffset, baseARPFields[:])
|
||||
finfo := reclaimFrame(&dst, "ARP", bitOffset, baseARPFields[:])
|
||||
const varstart = 8 * octet
|
||||
_, hlen := afrm.Hardware()
|
||||
_, plen := afrm.Protocol()
|
||||
@@ -154,6 +155,7 @@ func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:ipv6:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("IPv6 must be parsed at byte boundary")
|
||||
}
|
||||
@@ -165,7 +167,8 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
reclaimFrame(&dst, ethernet.TypeIPv6, bitOffset, baseIPv6Fields[:])
|
||||
reclaimFrame(&dst, "IPv6", bitOffset, baseIPv6Fields[:])
|
||||
debuglog("pcap:ipv6:reclaimed")
|
||||
proto := ifrm6.NextHeader()
|
||||
end := bitOffset + 40*octet
|
||||
var protoErrs []error
|
||||
@@ -196,6 +199,7 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:ipv4:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("IPv4 must be parsed at byte boundary")
|
||||
}
|
||||
@@ -207,9 +211,11 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
debuglog("pcap:ipv4:validated")
|
||||
// limit packet to the actual IPv4 frame size
|
||||
pkt = pkt[:bitOffset/8+int(ifrm4.TotalLength())]
|
||||
finfo := reclaimFrame(&dst, ethernet.TypeIPv4, bitOffset, baseIPv4Fields[:])
|
||||
finfo := reclaimFrame(&dst, "IPv4", bitOffset, baseIPv4Fields[:])
|
||||
debuglog("pcap:ipv4:reclaimed")
|
||||
options := ifrm4.Options()
|
||||
if len(options) > 0 {
|
||||
finfo.Fields = append(finfo.Fields, FrameField{
|
||||
@@ -221,6 +227,7 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
if ifrm4.CalculateHeaderCRC() != 0 {
|
||||
finfo.Errors = append(finfo.Errors, lneto.ErrBadCRC)
|
||||
}
|
||||
debuglog("pcap:ipv4:crc-done")
|
||||
proto := ifrm4.Protocol()
|
||||
end := bitOffset + octet*ifrm4.HeaderLength()
|
||||
var protoErrs []error
|
||||
@@ -262,10 +269,12 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
}
|
||||
}
|
||||
}
|
||||
debuglog("pcap:ipv4:proto-crc-done")
|
||||
return pc.captureIPProto(proto, dst, pkt, end, protoErrs...)
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt []byte, bitOffset int, ipProtoErrs ...error) (_ []Frame, err error) {
|
||||
debuglog("pcap:ipproto:start")
|
||||
nextFrame := len(dst)
|
||||
switch proto {
|
||||
case lneto.IPProtoTCP:
|
||||
@@ -275,20 +284,22 @@ func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt
|
||||
case lneto.IPProtoUDPLite:
|
||||
dst, err = pc.CaptureUDP(dst, pkt, bitOffset)
|
||||
if len(dst) > nextFrame {
|
||||
dst[nextFrame].Protocol = lneto.IPProtoUDPLite
|
||||
dst[nextFrame].Protocol = "UDPLite"
|
||||
}
|
||||
case lneto.IPProtoICMP:
|
||||
dst, err = pc.CaptureICMPv4(dst, pkt, bitOffset)
|
||||
default:
|
||||
reclaimRemainingFrame(&dst, proto, 0, bitOffset, octet*len(pkt))
|
||||
reclaimRemainingFrame(&dst, "unknown proto", 0, bitOffset, octet*len(pkt))
|
||||
}
|
||||
if len(ipProtoErrs) > 0 && len(dst) > nextFrame {
|
||||
dst[nextFrame].Errors = append(dst[nextFrame].Errors, ipProtoErrs...)
|
||||
}
|
||||
debuglog("pcap:ipproto:done")
|
||||
return dst, err
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:tcp:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("TCP must be parsed at byte boundary")
|
||||
}
|
||||
@@ -300,8 +311,10 @@ func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
debuglog("pcap:tcp:validated")
|
||||
end := bitOffset + octet*tfrm.HeaderLength()
|
||||
finfo := reclaimFrame(&dst, lneto.IPProtoTCP, bitOffset, baseTCPFields[:])
|
||||
finfo := reclaimFrame(&dst, "TCP", bitOffset, baseTCPFields[:])
|
||||
debuglog("pcap:tcp:reclaimed")
|
||||
options := tfrm.Options()
|
||||
if len(options) > 0 {
|
||||
finfo.Fields = append(finfo.Fields, FrameField{
|
||||
@@ -312,15 +325,19 @@ func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
}
|
||||
payload := tfrm.Payload()
|
||||
if len(payload) > 0 {
|
||||
debuglog("pcap:tcp:http-start")
|
||||
dst, err = pc.CaptureHTTP(dst, pkt, end)
|
||||
debuglog("pcap:tcp:http-done")
|
||||
if err != nil {
|
||||
reclaimRemainingFrame(&dst, unknownPayloadProto, FieldClassPayload, end, octet*len(pkt))
|
||||
}
|
||||
}
|
||||
debuglog("pcap:tcp:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:udp:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("UDP must be parsed at byte boundary")
|
||||
}
|
||||
@@ -332,7 +349,8 @@ func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().ErrPop()
|
||||
}
|
||||
reclaimFrame(&dst, lneto.IPProtoUDP, bitOffset, baseUDPFields[:])
|
||||
reclaimFrame(&dst, "UDP", bitOffset, baseUDPFields[:])
|
||||
debuglog("pcap:udp:reclaimed")
|
||||
end := bitOffset + 8*octet
|
||||
payload := ufrm.Payload()
|
||||
dstport := ufrm.DestinationPort()
|
||||
@@ -347,10 +365,12 @@ func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
if err != nil {
|
||||
reclaimRemainingFrame(&dst, unknownPayloadProto, FieldClassPayload, end, octet*len(pkt))
|
||||
}
|
||||
debuglog("pcap:udp:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureICMPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:icmp:start")
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("ICMPv4 must be parsed at byte boundary")
|
||||
}
|
||||
@@ -360,7 +380,7 @@ func (pc *PacketBreakdown) CaptureICMPv4(dst []Frame, pkt []byte, bitOffset int)
|
||||
return dst, err
|
||||
}
|
||||
|
||||
finfo := reclaimFrame(&dst, lneto.IPProtoICMP, bitOffset, baseICMPv4Fields[:])
|
||||
finfo := reclaimFrame(&dst, "ICMP", bitOffset, baseICMPv4Fields[:])
|
||||
|
||||
// Add type-specific fields.
|
||||
switch ifrm.Type() {
|
||||
@@ -541,9 +561,9 @@ func httpBodyClass(contentType, body []byte) FieldClass {
|
||||
switch {
|
||||
case bytes.HasPrefix(mediaType, []byte("text/")):
|
||||
return FieldClassText
|
||||
case bytes.Equal(mediaType, []byte("application/json")),
|
||||
bytes.Equal(mediaType, []byte("application/javascript")),
|
||||
bytes.Equal(mediaType, []byte("application/xml")):
|
||||
case internal.BytesEqual(mediaType, []byte("application/json")),
|
||||
internal.BytesEqual(mediaType, []byte("application/javascript")),
|
||||
internal.BytesEqual(mediaType, []byte("application/xml")):
|
||||
return FieldClassText
|
||||
case bytes.HasSuffix(mediaType, []byte("+json")),
|
||||
bytes.HasSuffix(mediaType, []byte("+xml")):
|
||||
@@ -562,6 +582,7 @@ func httpBodyClass(contentType, body []byte) FieldClass {
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
debuglog("pcap:http:start")
|
||||
const httpProtocol = "HTTP"
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("HTTP must be parsed at byte boundary")
|
||||
@@ -578,6 +599,7 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
debuglog("pcap:http:parsed")
|
||||
hdrLen := pc.hdr.BufferParsed()
|
||||
body, _ := pc.hdr.Body()
|
||||
bodyClass := httpBodyClass(pc.hdr.Get("Content-Type"), body)
|
||||
@@ -596,6 +618,7 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
|
||||
BitLength: len(body) * octet,
|
||||
},
|
||||
)
|
||||
debuglog("pcap:http:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -626,7 +649,7 @@ func (ff Flags) IsRightAligned() bool { return ff&FlagRightAligned != 0 }
|
||||
|
||||
type Frame struct {
|
||||
PacketBitOffset int
|
||||
Protocol any
|
||||
Protocol string
|
||||
Fields []FrameField
|
||||
Errors []error
|
||||
}
|
||||
@@ -1306,7 +1329,7 @@ var baseNTPFields = [...]FrameField{
|
||||
// reclaimFrame extends dst via [internal.SliceReclaim], resets the reclaimed Frame
|
||||
// with the given protocol and bit offset while preserving Fields and Errors
|
||||
// backing arrays, and appends baseFields. Returns the Frame for further modification.
|
||||
func reclaimFrame(dst *[]Frame, proto any, bitOffset int, baseFields []FrameField) *Frame {
|
||||
func reclaimFrame(dst *[]Frame, proto string, bitOffset int, baseFields []FrameField) *Frame {
|
||||
finfo := internal.SliceReclaim(dst)
|
||||
*finfo = Frame{
|
||||
PacketBitOffset: bitOffset,
|
||||
@@ -1319,10 +1342,18 @@ func reclaimFrame(dst *[]Frame, proto any, bitOffset int, baseFields []FrameFiel
|
||||
|
||||
// reclaimRemainingFrame extends dst via SliceReclaim and populates the reclaimed
|
||||
// Frame as a single-field "remaining payload" frame, reusing the old Fields backing array.
|
||||
func reclaimRemainingFrame(dst *[]Frame, proto any, class FieldClass, pktBitOffset, pktBitLen int) {
|
||||
func reclaimRemainingFrame(dst *[]Frame, proto string, class FieldClass, pktBitOffset, pktBitLen int) {
|
||||
finfo := reclaimFrame(dst, proto, pktBitOffset, nil)
|
||||
finfo.Fields = append(finfo.Fields, FrameField{
|
||||
Class: class,
|
||||
BitLength: pktBitLen - pktBitOffset,
|
||||
})
|
||||
}
|
||||
|
||||
const enableDebug = false
|
||||
|
||||
func debuglog(msg string) {
|
||||
if enableDebug {
|
||||
internal.LogAttrs(nil, slog.LevelDebug, msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ func TestRightAlignedFields(t *testing.T) {
|
||||
// Find IPv6 frame.
|
||||
var ipv6Frame *Frame
|
||||
for i := range frames {
|
||||
if frames[i].Protocol == ethernet.TypeIPv6 {
|
||||
if frames[i].Protocol == "IPv6" {
|
||||
ipv6Frame = &frames[i]
|
||||
break
|
||||
}
|
||||
@@ -476,15 +476,16 @@ func ExampleFormatter_dhcp() {
|
||||
// Output:
|
||||
// Ethernet len=14; destination=ff:ff:ff:ff:ff:ff; source=de:ad:be:ef:ca:fe; protocol=0x0800
|
||||
// IPv4 len=20; version=0x04; (Header Length)=5; (Type of Service)=0x00; (Total Length)=312; identification=0x6043; flags=0x4000; (Time to live)=0x40; protocol=0x11; checksum=0xd972; source=0.0.0.0; destination=255.255.255.255
|
||||
// UDP [RFC768] len=8; (Source port)=68; (Destination port)=67; size=292; checksum=0x0000
|
||||
// UDP len=8; (Source port)=68; (Destination port)=67; size=292; checksum=0x0000
|
||||
// DHCPv4 len=240; op=1; (Hardware Address Type)=0x01; (Hardware Address Length)=6; Hops=0x00; (Transaction ID)=0xdeadbeef; (Start Time)=0x0001; Flags=0x0000; (Client Address)=0.0.0.0; (Offered Address)=0.0.0.0; (Server Next Address)=255.255.255.255; (Relay Agent Address)=0.0.0.0; (Client Hardware Address)=de:ad:be:ef:ca:fe; options
|
||||
// (DHCP message type.)=1
|
||||
// (Parameter request list)=0x0102031a1c060f2a
|
||||
// (DHCP maximum message size)=558
|
||||
// (Requested IP address)=192.168.1.100
|
||||
// (Client identifier)="lneto-test"
|
||||
// (Hostname string)="myhost"
|
||||
// (DHCP message type.)=1
|
||||
// (Parameter request list)=0x0102031a1c060f2a
|
||||
// (DHCP maximum message size)=558
|
||||
// (Requested IP address)=192.168.1.100
|
||||
// (Client identifier)="lneto-test"
|
||||
// (Hostname string)="myhost"
|
||||
}
|
||||
|
||||
func writeOpt(dst []byte, opt dhcpv4.OptNum, data ...byte) int {
|
||||
dst[0] = byte(opt)
|
||||
dst[1] = byte(len(data))
|
||||
|
||||
+18
-22
@@ -4,7 +4,6 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/netip"
|
||||
"slices"
|
||||
@@ -12,8 +11,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
_ "time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/ntp"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
@@ -38,6 +37,7 @@ type Formatter struct {
|
||||
// FormatFrames appends the formatted frame data to the destination buffer according the Formatter state.
|
||||
// Is equivalent to [Formatter.FormatFrame] called on each Frame with the FrameSep inserted between frames.
|
||||
func (f *Formatter) FormatFrames(dst []byte, frms []Frame, pkt []byte) (_ []byte, err error) {
|
||||
debuglog("pcap:fmt:start")
|
||||
sep := f.frameSep()
|
||||
for ifrm := range frms {
|
||||
if ifrm != 0 {
|
||||
@@ -48,14 +48,16 @@ func (f *Formatter) FormatFrames(dst []byte, frms []Frame, pkt []byte) (_ []byte
|
||||
return dst, err
|
||||
}
|
||||
}
|
||||
debuglog("pcap:fmt:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// FormatFrame formats a single frame's protocol, fields, and errors into dst.
|
||||
func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, err error) {
|
||||
debuglog("pcap:fmtframe:start")
|
||||
sep := f.fieldSep()
|
||||
bitlen := frm.LenBits()
|
||||
dst = appendProtocol(dst, frm.Protocol)
|
||||
dst = append(dst, frm.Protocol...)
|
||||
if bitlen%8 == 0 {
|
||||
dst = append(dst, " len="...)
|
||||
dst = strconv.AppendInt(dst, int64(bitlen/8), 10)
|
||||
@@ -70,7 +72,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
continue
|
||||
}
|
||||
dst = append(dst, sep...)
|
||||
if field.Class == FieldClassFlags && frm.Protocol == lneto.IPProtoTCP {
|
||||
if field.Class == FieldClassFlags && frm.Protocol == "TCP" {
|
||||
// TCP flags pretty print special case.
|
||||
dst = append(dst, "flags="...)
|
||||
v, err := f.fieldAsUint(pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
||||
@@ -95,6 +97,7 @@ func (f *Formatter) FormatFrame(dst []byte, frm Frame, pkt []byte) (_ []byte, er
|
||||
}
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
debuglog("pcap:fmtframe:done")
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
@@ -135,6 +138,9 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
if hasSpaces {
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
if field.BitLength == 0 {
|
||||
return dst, nil
|
||||
}
|
||||
dst = append(dst, '=')
|
||||
f.mubuf.Lock()
|
||||
defer f.mubuf.Unlock()
|
||||
@@ -142,6 +148,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
debuglog("pcap:fmtfield:append-done")
|
||||
fieldBitStart := pktStartOff + field.FrameBitOffset
|
||||
switch field.Class {
|
||||
default:
|
||||
@@ -151,6 +158,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
dst = append(dst, "0x"...)
|
||||
dst = hex.AppendEncode(dst, f.buf)
|
||||
case FieldClassTimestamp:
|
||||
debuglog("pcap:fmtfield:timestamp")
|
||||
// inspired by [time.RFC3339]
|
||||
const littlerfc3339 = "2006-01-02T15:04:05.9999"
|
||||
if len(f.buf) != 8 {
|
||||
@@ -158,8 +166,13 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
||||
}
|
||||
ts := ntp.TimestampFromUint64(binary.BigEndian.Uint64(f.buf))
|
||||
dst = ts.Time().AppendFormat(dst, littlerfc3339)
|
||||
debuglog("pcap:fmtfield:timestamp-done")
|
||||
case FieldClassText:
|
||||
dst = strconv.AppendQuote(dst, string(f.buf))
|
||||
debuglog("pcap:fmtfield:text")
|
||||
if len(f.buf) > 0 {
|
||||
dst = strconv.AppendQuote(dst, unsafe.String(&f.buf[0], len(f.buf)))
|
||||
}
|
||||
debuglog("pcap:fmtfield:text-done")
|
||||
case FieldClassDst, FieldClassSrc, FieldClassSize, FieldClassAddress, FieldClassOperation:
|
||||
// IP, MAC addresses and ports.
|
||||
if field.BitLength <= 16 {
|
||||
@@ -219,20 +232,3 @@ func (f *Formatter) fieldAsUint(pkt []byte, fieldBitStart, bitlen int, rightAlig
|
||||
}
|
||||
return binary.BigEndian.Uint64(f.uintBuf[:]), nil
|
||||
}
|
||||
|
||||
// appendProtocol appends the string representation of a Frame.Protocol value
|
||||
// to dst without going through fmt.Appendf reflect machinery.
|
||||
func appendProtocol(dst []byte, p any) []byte {
|
||||
switch p := p.(type) {
|
||||
case proto:
|
||||
return append(dst, string(p)...)
|
||||
case string:
|
||||
return append(dst, p...)
|
||||
case ethernet.Type:
|
||||
return append(dst, p.String()...)
|
||||
case lneto.IPProto:
|
||||
return append(dst, p.String()...)
|
||||
default:
|
||||
return fmt.Appendf(dst, "%v", p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,3 +232,11 @@ func (l logger) debug(msg string, attrs ...slog.Attr) {
|
||||
func (l logger) trace(msg string, attrs ...slog.Attr) {
|
||||
internal.LogAttrs(l.log, internal.LevelTrace, msg, attrs...)
|
||||
}
|
||||
|
||||
const enableAllocLog = false
|
||||
|
||||
func debugLog(msg string) {
|
||||
if enableAllocLog {
|
||||
internal.LogAllocs(msg)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user