Explicitly encode the pcap packet headers to reduce CPU cost of pcap generation.

PiperOrigin-RevId: 387513118
This commit is contained in:
gVisor bot
2021-07-28 22:46:06 -07:00
parent 72c2b74ac3
commit 095b0d8348
2 changed files with 46 additions and 43 deletions
+38 -18
View File
@@ -14,7 +14,14 @@
package sniffer
import "time"
import (
"encoding"
"encoding/binary"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
type pcapHeader struct {
// MagicNumber is the file magic number.
@@ -39,25 +46,38 @@ type pcapHeader struct {
Network uint32
}
type pcapPacketHeader struct {
// Seconds is the timestamp seconds.
Seconds uint32
var _ encoding.BinaryMarshaler = (*pcapPacket)(nil)
// Microseconds is the timestamp microseconds.
Microseconds uint32
// IncludedLength is the number of octets of packet saved in file.
IncludedLength uint32
// OriginalLength is the actual length of packet.
OriginalLength uint32
type pcapPacket struct {
timestamp time.Time
packet *stack.PacketBuffer
maxCaptureLen int
}
func newPCAPPacketHeader(now time.Time, incLen, orgLen uint32) pcapPacketHeader {
return pcapPacketHeader{
Seconds: uint32(now.Unix()),
Microseconds: uint32(now.Nanosecond() / 1000),
IncludedLength: incLen,
OriginalLength: orgLen,
func (p *pcapPacket) MarshalBinary() ([]byte, error) {
packetSize := p.packet.Size()
captureLen := p.maxCaptureLen
if packetSize < captureLen {
captureLen = packetSize
}
b := make([]byte, 16+captureLen)
binary.BigEndian.PutUint32(b[0:4], uint32(p.timestamp.Unix()))
binary.BigEndian.PutUint32(b[4:8], uint32(p.timestamp.Nanosecond()/1000))
binary.BigEndian.PutUint32(b[8:12], uint32(captureLen))
binary.BigEndian.PutUint32(b[12:16], uint32(packetSize))
w := tcpip.SliceWriter(b[16:])
for _, v := range p.packet.Views() {
if captureLen == 0 {
break
}
if len(v) > captureLen {
v = v[:captureLen]
}
n, err := w.Write(v)
if err != nil {
panic(err)
}
captureLen -= n
}
return b, nil
}
+8 -25
View File
@@ -151,33 +151,16 @@ func (e *endpoint) dumpPacket(dir direction, protocol tcpip.NetworkProtocolNumbe
logPacket(e.logPrefix, dir, protocol, pkt)
}
if writer != nil && atomic.LoadUint32(&LogPacketsToPCAP) == 1 {
totalLength := pkt.Size()
length := totalLength
if max := int(e.maxPCAPLen); length > max {
length = max
packet := pcapPacket{
timestamp: time.Now(),
packet: pkt,
maxCaptureLen: int(e.maxPCAPLen),
}
packetHeader := newPCAPPacketHeader(time.Now(), uint32(length), uint32(totalLength))
packet := make([]byte, binary.Size(packetHeader)+length)
{
writer := tcpip.SliceWriter(packet)
if err := binary.Write(&writer, binary.BigEndian, packetHeader); err != nil {
panic(err)
}
for _, b := range pkt.Views() {
if length == 0 {
break
}
if len(b) > length {
b = b[:length]
}
n, err := writer.Write(b)
if err != nil {
panic(err)
}
length -= n
}
b, err := packet.MarshalBinary()
if err != nil {
panic(err)
}
if _, err := writer.Write(packet); err != nil {
if _, err := writer.Write(b); err != nil {
panic(err)
}
}