google / gopacket

Provides packet processing capabilities for Go
BSD 3-Clause "New" or "Revised" License
6.26k stars 1.12k forks source link

Did anyone do the performance test on the sniffer way of afpacket? #473

Open icestrawberryxjw opened 6 years ago

icestrawberryxjw commented 6 years ago

I'm writing a traffic sniffer and realtime-analyzer. Today I did a test on the performance of the part of writing packets. Results show that it lost packets when the speed of traffic was 200Mbps. I wonder that whether there exists problems in my codes.

Here are my codes:

package main
import (
    "fmt"
    "log"
    "time"
    "github.com/google/gopacket/afpacket"
    "os"
    "config"
    "github.com/google/gopacket/pcapgo"
    "github.com/google/gopacket/layers"
)

var (
    snapshot_len int             = 65535
    promiscuous  bool          = true
    timeout      time.Duration = -1 * time.Second
    buffersizeMb int              =500
)
func OpenAFpacket(nic string)( *afpacket.TPacket,error){
    szFrame, szBlock, numBlocks, err := afpacketComputeSize(buffersizeMb, snapshot_len, os.Getpagesize())
    if err != nil {
        log.Fatal(err)
    }
    handle, err := afpacket.NewTPacket(
        afpacket.OptInterface(nic),
        afpacket.OptFrameSize(szFrame),
        afpacket.OptBlockSize(szBlock),
        afpacket.OptNumBlocks(numBlocks),
        afpacket.OptPollTimeout(timeout))
    return handle,err
}

func afpacketComputeSize(targetSizeMb int, snaplen int, pageSize int) (
    frameSize int, blockSize int, numBlocks int, err error) {

    if snaplen < pageSize {
        frameSize = pageSize / (pageSize / snaplen)
    } else {
        frameSize = (snaplen/pageSize + 1) * pageSize
    }

    blockSize = frameSize * 128
    numBlocks = (targetSizeMb * 1024 * 1024) / blockSize

    if numBlocks == 0 {
        return 0, 0, 0, fmt.Errorf("Buffer size too small")
    }
    return frameSize, blockSize, numBlocks, nil
}

func main() {

    var packetnum int64
    h,err :=OpenAFpacket("em2")
    if err !=nil{
        log.Fatal(err)
    }
    h.TpacketVersion()
    f, _ := os.Create(config.PCAP_DIR+"/testcapture.pcap")
    w := pcapgo.NewWriter(f)
    w.WriteFileHeader(65536, layers.LinkTypeEthernet)  // new file, must do this

    for{
        data,ci,err := h.ZeroCopyReadPacketData()
        if err!=nil{
            log.Fatal(err)
        }
        err=w.WritePacket(ci, data)
        if err!=nil{
            log.Fatal(err)
        }
        packetnum++
        //fmt.Println("packet num:",packetnum)
    }
}
lightinbottle commented 5 years ago

i met the same problem as you...

gujunyan commented 5 years ago

yes, i got the same problem. i have resolve the problem by DPDK.

mpenning commented 9 months ago

it lost packets when the speed of traffic was 200Mbps.

Just offering possibilities... Is it possible that your problem is not in gopacket? Network interfaces have a fixed ring packet buffer that will overflow at a certain rate. TCP fixes this problem by simply re-transmitting lost packets, but a sniffer has no reason to do so. If this is your problem, you should rate-limit your traffic, or otherwise work around the packet drops at high speeds.

It's also possible that your CPU / scheduler simply cannot keep up... at any rate, packet sniffing on a host should be considered best-effort... sad, but true.

This one of many reasons that people can sell dedicated sniffer appliances for in-line capture off a network switch... and even those run into similar limitations, but the threshold for pain is higher in that case.