Skip to content

Commit

Permalink
refactor packet dumper
Browse files Browse the repository at this point in the history
  • Loading branch information
pirog-spb committed Sep 24, 2024
1 parent e0a554c commit c74943c
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 50 deletions.
59 changes: 9 additions & 50 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"encoding/binary"
"fmt"
"net"
"os"
Expand All @@ -10,9 +9,6 @@ import (
"time"

"github.com/edgecomllc/eupf/cmd/core/service"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"

"github.com/edgecomllc/eupf/cmd/api/rest"
"github.com/edgecomllc/eupf/cmd/server"
Expand All @@ -21,8 +17,8 @@ import (
"github.com/edgecomllc/eupf/cmd/ebpf"

"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/perf"
"github.com/edgecomllc/eupf/cmd/config"
"github.com/edgecomllc/eupf/cmd/utils"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
Expand Down Expand Up @@ -57,51 +53,15 @@ func main() {
}
}

if rd, err := perf.NewReader(bpfObjects.TraceMap, 4096); err == nil {
defer rd.Close()

go func() {
// Write a new file:
traceFileName := fmt.Sprintf("/tmp/%s-trace.pcap", time.Now().Format(time.RFC3339))
f, _ := os.Create(traceFileName)
defer f.Close()

w := pcapgo.NewWriterNanos(f)
_ = w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this.

var rec perf.Record
for {
if err := rd.ReadInto(&rec); err != nil {
log.Error().Msgf(" can't read from perf map: %s", err.Error())
return
}

sampleLength := len(rec.RawSample)
if sampleLength < 9 {
log.Error().Msgf(" perf sample too small: %d", sampleLength)
}

magic := binary.LittleEndian.Uint16(rec.RawSample[:2])
if magic != 0xdead {
continue
}

packetLength := binary.LittleEndian.Uint16(rec.RawSample[2:4])
packetIface := binary.LittleEndian.Uint32(rec.RawSample[4:8])
packet := rec.RawSample[8 : 8+packetLength]

//pack := gopacket.NewPacket(packet, layers.LayerTypeEthernet, gopacket.Default)
//log.Trace().Msgf("Sample lost=%d, remaining=%d, len=%d, packet: %s", rec.LostSamples, rec.Remaining, packetLength, pack.Dump())
var err error
traceFileName := fmt.Sprintf("dumps/%s-trace.pcap", time.Now().Format(time.RFC3339))
dumper, err := utils.NewPacketDumper(traceFileName, bpfObjects.TraceMap)

if err := w.WritePacket(gopacket.CaptureInfo{
Length: int(packetLength),
CaptureLength: int(packetLength),
InterfaceIndex: int(packetIface),
}, packet); err != nil {
log.Error().Msgf(" can't write perf sample to pcap dump: %s", err.Error())
}
}
}()
if err != nil {
log.Error().Msgf("Can't start dumper: %s", err.Error())
} else {
defer dumper.Close()
go dumper.Run()
}

defer bpfObjects.Close()
Expand All @@ -127,7 +87,6 @@ func main() {
}

log.Info().Msgf("Initialize resources: UEIP pool (CIDR: \"%s\"), TEID pool (size: %d)", config.Conf.UEIPPool, config.Conf.FTEIDPool)
var err error
resourceManager, err := service.NewResourceManager(config.Conf.UEIPPool, config.Conf.FTEIDPool)
if err != nil {
log.Error().Msgf("failed to create ResourceManager - err: %v", err)
Expand Down
120 changes: 120 additions & 0 deletions cmd/utils/packet_dumper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package utils

import (
"encoding/binary"
"fmt"
"os"
"runtime"

"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/perf"
"github.com/google/gopacket"
"github.com/rs/zerolog/log"
)

type PacketDumper struct {
praceMap *ebpf.Map
f *os.File
w *pcapgo.NgWriter
}

func NewPacketDumper(dumpPath string, praceMap *ebpf.Map) (*PacketDumper, error) {

f, _ := os.Create(dumpPath)

//w := pcapgo.NewWriterNanos(f)
//_ = w.WriteFileHeader(65536, layers.LinkTypeEthernet) // new file, must do this.
w, err := pcapgo.NewNgWriter(f, layers.LinkTypeEthernet)
if err != nil {
f.Close()
return nil, fmt.Errorf("can't create ng pcap writer: %s", err.Error())
}

_, err = w.AddInterface(pcapgo.NgInterface{
Name: "in",
OS: runtime.GOOS,
SnapLength: 0, //unlimited
TimestampResolution: 9,
LinkType: layers.LinkTypeEthernet})
if err != nil {
f.Close()
return nil, fmt.Errorf("can't add in ng pcap interface:: %s", err.Error())
}

_, err = w.AddInterface(pcapgo.NgInterface{
Name: "out",
OS: runtime.GOOS,
SnapLength: 0, //unlimited
TimestampResolution: 9,
LinkType: layers.LinkTypeEthernet})
if err != nil {
f.Close()
return nil, fmt.Errorf("can't add out ng pcap interface:: %s", err.Error())
}

return &PacketDumper{
praceMap: praceMap,
f: f,
w: w,
}, nil
}

func (dumper *PacketDumper) Run() {

rd, err := perf.NewReader(dumper.praceMap, 4096)
if err != nil {
log.Error().Msgf(" can't create perf reader: %s", err.Error())
return
}
defer rd.Close()

var rec perf.Record
for {
if err := rd.ReadInto(&rec); err != nil {
log.Error().Msgf(" can't read from perf map: %s", err.Error())
return
}

if rec.LostSamples > 0 {
log.Warn().Msgf(" lost samples from perf map: %d", rec.LostSamples)
}

sampleLength := len(rec.RawSample)
if sampleLength < 9 {
log.Error().Msgf(" perf sample too small: %d", sampleLength)
}

magic := binary.LittleEndian.Uint16(rec.RawSample[:2])
if magic != 0xdead {
continue
}

packetLength := binary.LittleEndian.Uint16(rec.RawSample[2:4])
packetIface := binary.LittleEndian.Uint32(rec.RawSample[4:8]) + 1
packet := rec.RawSample[8 : 8+packetLength]

//pack := gopacket.NewPacket(packet, layers.LayerTypeEthernet, gopacket.Default)
//log.Trace().Msgf("Sample lost=%d, remaining=%d, len=%d, packet: %s", rec.LostSamples, rec.Remaining, packetLength, pack.Dump())

if err := dumper.w.WritePacket(gopacket.CaptureInfo{
Length: int(packetLength),
CaptureLength: int(packetLength),
InterfaceIndex: int(packetIface),
}, packet); err != nil {
log.Error().Msgf(" can't write perf sample to pcap dump: %s", err.Error())
}
}
}

func (dumper *PacketDumper) Close() {
if dumper.w != nil {
dumper.w.Flush()
}

if dumper.f != nil {
dumper.f.Close()
}
}

0 comments on commit c74943c

Please sign in to comment.