aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go')
-rw-r--r--vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go247
1 files changed, 247 insertions, 0 deletions
diff --git a/vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go b/vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go
new file mode 100644
index 0000000..cbcae17
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcap/gopacket_benchmark/benchmark.go
@@ -0,0 +1,247 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+// This benchmark reads in file <tempdir>/gopacket_benchmark.pcap and measures
+// the time it takes to decode all packets from that file. If the file doesn't
+// exist, it's pulled down from a publicly available location. However, you can
+// feel free to substitute your own file at that location, in which case the
+// benchmark will run on your own data.
+//
+// It's also useful for figuring out which packets may be causing errors. Pass
+// in the --printErrors flag, and it'll print out error layers for each packet
+// that has them. This includes any packets that it's just unable to decode,
+// which is a great way to find new protocols to decode, and get test packets to
+// write tests for them.
+package main
+
+import (
+ "compress/gzip"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "github.com/google/gopacket/tcpassembly"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+)
+
+var decodeLazy *bool = flag.Bool("lazy", false, "If true, use lazy decoding")
+var decodeNoCopy *bool = flag.Bool("nocopy", true, "If true, avoid an extra copy when decoding packets")
+var printErrors *bool = flag.Bool("printErrors", false, "If true, check for and print error layers.")
+var printLayers *bool = flag.Bool("printLayers", false, "If true, print out the layers of each packet")
+var repeat *int = flag.Int("repeat", 5, "Read over the file N times")
+var cpuProfile *string = flag.String("cpuprofile", "", "If set, write CPU profile to filename")
+var url *string = flag.String("url", "http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/tuesday/inside.tcpdump.gz", "URL to gzip'd pcap file")
+
+type BufferPacketSource struct {
+ index int
+ data [][]byte
+ ci []gopacket.CaptureInfo
+}
+
+func NewBufferPacketSource(p gopacket.PacketDataSource) *BufferPacketSource {
+ start := time.Now()
+ b := &BufferPacketSource{}
+ for {
+ data, ci, err := p.ReadPacketData()
+ if err == io.EOF {
+ break
+ }
+ b.data = append(b.data, data)
+ b.ci = append(b.ci, ci)
+ }
+ duration := time.Since(start)
+ fmt.Printf("Reading packet data into memory: %d packets in %v, %v per packet\n", len(b.data), duration, duration/time.Duration(len(b.data)))
+ return b
+}
+
+func (b *BufferPacketSource) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
+ if b.index >= len(b.data) {
+ err = io.EOF
+ return
+ }
+ data = b.data[b.index]
+ ci = b.ci[b.index]
+ b.index++
+ return
+}
+
+func (b *BufferPacketSource) Reset() {
+ runtime.GC()
+ b.index = 0
+}
+
+func main() {
+ flag.Parse()
+ filename := os.TempDir() + string(os.PathSeparator) + "gopacket_benchmark.pcap"
+ if _, err := os.Stat(filename); err != nil {
+ // This URL points to a publicly available packet data set from a DARPA
+ // intrusion detection evaluation. See
+ // http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/index.html
+ // for more details.
+ fmt.Println("Local pcap file", filename, "doesn't exist, reading from", *url)
+ if resp, err := http.Get(*url); err != nil {
+ panic(err)
+ } else if out, err := os.Create(filename); err != nil {
+ panic(err)
+ } else if gz, err := gzip.NewReader(resp.Body); err != nil {
+ panic(err)
+ } else if n, err := io.Copy(out, gz); err != nil {
+ panic(err)
+ } else if err := gz.Close(); err != nil {
+ panic(err)
+ } else if err := out.Close(); err != nil {
+ panic(err)
+ } else {
+ fmt.Println("Successfully read", n, "bytes from url, unzipped to local storage")
+ }
+ }
+ fmt.Println("Reading file once through to hopefully cache most of it")
+ if f, err := os.Open(filename); err != nil {
+ panic(err)
+ } else if n, err := io.Copy(ioutil.Discard, f); err != nil {
+ panic(err)
+ } else if err := f.Close(); err != nil {
+ panic(err)
+ } else {
+ fmt.Println("Read in file", filename, ", total of", n, "bytes")
+ }
+ if *cpuProfile != "" {
+ if cpu, err := os.Create(*cpuProfile); err != nil {
+ panic(err)
+ } else if err := pprof.StartCPUProfile(cpu); err != nil {
+ panic(err)
+ } else {
+ defer func() {
+ pprof.StopCPUProfile()
+ cpu.Close()
+ }()
+ }
+ }
+ var packetDataSource *BufferPacketSource
+ var packetSource *gopacket.PacketSource
+ fmt.Printf("Opening file %q for read\n", filename)
+ if h, err := pcap.OpenOffline(filename); err != nil {
+ panic(err)
+ } else {
+ fmt.Println("Reading all packets into memory with BufferPacketSource.")
+ start := time.Now()
+ packetDataSource = NewBufferPacketSource(h)
+ duration := time.Since(start)
+ fmt.Printf("Time to read packet data into memory from file: %v\n", duration)
+ packetSource = gopacket.NewPacketSource(packetDataSource, h.LinkType())
+ packetSource.DecodeOptions.Lazy = *decodeLazy
+ packetSource.DecodeOptions.NoCopy = *decodeNoCopy
+ }
+ fmt.Println()
+ for i := 0; i < *repeat; i++ {
+ packetDataSource.Reset()
+ fmt.Printf("Benchmarking decode %d/%d\n", i+1, *repeat)
+ benchmarkPacketDecode(packetSource)
+ }
+ fmt.Println()
+ for i := 0; i < *repeat; i++ {
+ packetDataSource.Reset()
+ fmt.Printf("Benchmarking decoding layer parser %d/%d\n", i+1, *repeat)
+ benchmarkLayerDecode(packetDataSource, false)
+ }
+ fmt.Println()
+ for i := 0; i < *repeat; i++ {
+ packetDataSource.Reset()
+ fmt.Printf("Benchmarking decoding layer parser with assembly %d/%d\n", i+1, *repeat)
+ benchmarkLayerDecode(packetDataSource, true)
+ }
+}
+
+func benchmarkPacketDecode(packetSource *gopacket.PacketSource) {
+ count, errors := 0, 0
+ start := time.Now()
+ for packet, err := packetSource.NextPacket(); err != io.EOF; packet, err = packetSource.NextPacket() {
+ if err != nil {
+ fmt.Println("Error reading in packet:", err)
+ continue
+ }
+ count++
+ var hasError bool
+ if *printErrors && packet.ErrorLayer() != nil {
+ fmt.Println("\n\n\nError decoding packet:", packet.ErrorLayer().Error())
+ fmt.Println(hex.Dump(packet.Data()))
+ fmt.Printf("%#v\n", packet.Data())
+ errors++
+ hasError = true
+ }
+ if *printLayers || hasError {
+ fmt.Printf("\n=== PACKET %d ===\n", count)
+ for _, l := range packet.Layers() {
+ fmt.Printf("--- LAYER %v ---\n%#v\n\n", l.LayerType(), l)
+ }
+ fmt.Println()
+ }
+ }
+ duration := time.Since(start)
+ fmt.Printf("\tRead in %v packets in %v, %v per packet\n", count, duration, duration/time.Duration(count))
+ if *printErrors {
+ fmt.Printf("%v errors, successfully decoded %.02f%%\n", errors, float64(count-errors)*100.0/float64(count))
+ }
+}
+
+type streamFactory struct {
+}
+
+func (s *streamFactory) New(netFlow, tcpFlow gopacket.Flow) tcpassembly.Stream {
+ return s
+}
+func (s *streamFactory) Reassembled([]tcpassembly.Reassembly) {
+}
+func (s *streamFactory) ReassemblyComplete() {
+}
+
+func benchmarkLayerDecode(source *BufferPacketSource, assemble bool) {
+ var tcp layers.TCP
+ var ip layers.IPv4
+ var eth layers.Ethernet
+ var udp layers.UDP
+ var icmp layers.ICMPv4
+ var payload gopacket.Payload
+ parser := gopacket.NewDecodingLayerParser(
+ layers.LayerTypeEthernet,
+ &eth, &ip, &icmp, &tcp, &udp, &payload)
+ pool := tcpassembly.NewStreamPool(&streamFactory{})
+ assembler := tcpassembly.NewAssembler(pool)
+ var decoded []gopacket.LayerType
+ start := time.Now()
+ packets, decodedlayers, assembled := 0, 0, 0
+ for {
+ packets++
+ data, ci, err := source.ReadPacketData()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ fmt.Println("Error reading packet: ", err)
+ continue
+ }
+ err = parser.DecodeLayers(data, &decoded)
+ for _, typ := range decoded {
+ decodedlayers++
+ if typ == layers.LayerTypeTCP && assemble {
+ assembled++
+ assembler.AssembleWithTimestamp(ip.NetworkFlow(), &tcp, ci.Timestamp)
+ }
+ }
+ }
+ if assemble {
+ assembler.FlushAll()
+ }
+ duration := time.Since(start)
+ fmt.Printf("\tRead in %d packets in %v, decoded %v layers, assembled %v packets: %v per packet\n", packets, duration, decodedlayers, assembled, duration/time.Duration(packets))
+}