Open herrin opened 3 years ago
I have met the same issue. Are there any solution to bypass such issues ?
goroutine profile: total 8
1 @ 0x408a6b 0x81f20d 0x821a6c 0x820b6b 0x81d591 0x81d39b 0x7972b8 0x797515 0x46c171
# 0x81f20c github.com/google/gopacket/pcap._Cfunc_pcap_next_ex_escaping+0x4c _cgo_gotypes.go:549
# 0x821a6b github.com/google/gopacket/pcap.(*Handle).pcapNextPacketEx.func1+0x7b /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap_unix.go:398
# 0x820b6a github.com/google/gopacket/pcap.(*Handle).pcapNextPacketEx+0x2a /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap_unix.go:398
# 0x81d590 github.com/google/gopacket/pcap.(*Handle).getNextBufPtrLocked+0x60 /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap.go:312
# 0x81d39a github.com/google/gopacket/pcap.(*Handle).ReadPacketData+0x8a /home/stack/fetrace/vendor/github.com/google/gopacket/pcap/pcap.go:252
# 0x7972b7 github.com/google/gopacket.(*PacketSource).NextPacket+0x47 /home/stack/fetrace/vendor/github.com/google/gopacket/packet.go:801
# 0x797514 github.com/google/gopacket.(*PacketSource).packetsToChannel+0x64 /home/stack/fetrace/vendor/github.com/google/gopacket/packet.go:818
handle.Close()--> p.mu.Lock() But the lock is held by packetsToChannel->p.Nextpacket()->p.source.ReadPacketData()
func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
**p.mu.Lock()**
err = p.getNextBufPtrLocked(&ci)
if err == nil {
data = make([]byte, ci.CaptureLength)
copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
}
p.mu.Unlock()
if err == NextErrorTimeoutExpired {
runtime.Gosched()
}
return
}
getNextBufPtrLocked()->p.pcapNextPacketEx()-->C.pcap_next_ex_escaping
The root cause is C.pcap_next_ex_escaping is blocked unless there is a new packet arrives.
It have the same issue is #862
From what I can tell this can be solved by calling:
_ = unix.Shutdown(int(handle), unix.SHUT_RDWR)
to close the handle without getting a packet and therefore unlocking the goroutine and the lock. I prepared a PR for this and some other things but didn't get any feedback on it...might be helpful anyway for you :blush:
I prepared a PR for this and some other things but didn't get any feedback on it...might be helpful anyway for you blush
Got a link to the PR for this? Would love to check this out...
The PR is #893 - at some point I assumed that I won't merge it anyway hence I reworked a bit more to tweak memory consumption and support cancellation with context.Context
but I'm using this already for months in production :sweat_smile:
Awesome! So, with this patch, you're able to stop packet capture even when no packets show up?
I'm pretty sure this should work, yes, because that was exactly my issue when running in my CI environment :smile: give it a try and let me know if you encounter any issue and I'll see what I can do
Will give it a try today... Very much appreciate the quick response. Will let you know how it works out, either way.
Just out of curiosity: how did it go?
We managed to get things working... thank you!
https://github.com/google/gopacket/issues/1089#issuecomment-1501148868 try this solution
Stupid question but how do I stop pcap?
If I set a timeout in pcap.OpenLive, ReadPacketData waits until the timeout (regardless of packets received) and then gives me only the first packet it captured. This seems weird and broken.
If I set pcap.BlockForever, ReadPacketData doesn't return until it receives a packet. If no packet arrives, it doesn't stop. I can empty the BPF in another thread but if there are no packets at all on the NIC, it doesn't stop.
Close() blocks until ReadPacketData returns.
The only thing I've found so far is if I intentionally send a matching packet out the interface, ReadPacketData will return it, subsequently allowing me to shut down pcap. Surely there's a better way?
In C I think I would pcap_breakloop() but that doesn't seem to be exposed in gopacket pcap?