From d80a5c8dff84201c8127ef32f17fdfd1dc5906cd Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 23 Sep 2014 16:56:08 +0100 Subject: [PATCH 1/2] Revert "don't set pcap timeout, to prevent cpu churn" This reverts commit b5df59660fe83fd5a5d4d3ddd23e6b084ef56465. See issue #81 --- pcap.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcap.go b/pcap.go index 912d0fba..354ec818 100644 --- a/pcap.go +++ b/pcap.go @@ -40,6 +40,9 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca if err = inactive.SetSnapLen(snaplen); err != nil { return } + if err = inactive.SetTimeout(-1); err != nil { + return + } if err = inactive.SetImmediateMode(true); err != nil { return } From 025315363d5ea8b8265f1b3ea800f24df2be51a4 Mon Sep 17 00:00:00 2001 From: Matthias Radestock Date: Tue, 23 Sep 2014 17:54:40 +0100 Subject: [PATCH 2/2] prevent CPU churn by setting long pcap timeout pcap timeouts are a mystery. Setting the timeout to -1 used to reduce latency, but that was before we started setting immediate mode. And it turns out that with that timeout, pcap chews through a lot of CPU polling its file descriptor, checking timers, etc. However, the behaviour of setting *no* timeout is defined as, err, undefined. So instead we set a very long timeout indeed. And loop if it expires. Fixes #80 --- connection_maker.go | 5 ++--- consts.go | 2 ++ pcap.go | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/connection_maker.go b/connection_maker.go index 94064646..718b2fdc 100644 --- a/connection_maker.go +++ b/connection_maker.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "log" - "math" "math/rand" "net" "time" @@ -59,7 +58,7 @@ func (cm *ConnectionMaker) String() string { } func (cm *ConnectionMaker) queryLoop(queryChan <-chan *ConnectionMakerInteraction) { - timer := time.NewTimer(math.MaxInt64) + timer := time.NewTimer(MaxDuration) run := func() { timer.Reset(cm.checkStateAndAttemptConnections()) } for { select { @@ -131,7 +130,7 @@ func (cm *ConnectionMaker) checkStateAndAttemptConnections() time.Duration { }) now := time.Now() // make sure we catch items just added - after := time.Duration(math.MaxInt64) + after := MaxDuration for address, target := range cm.targets { if our_connected_targets[address] { delete(cm.targets, address) diff --git a/consts.go b/consts.go index e90a27ad..06add6f9 100644 --- a/consts.go +++ b/consts.go @@ -2,6 +2,7 @@ package weave import ( "time" + "math" ) const ( @@ -23,6 +24,7 @@ const ( FragTestInterval = 5 * time.Minute PMTUVerifyAttempts = 8 PMTUVerifyTimeout = 10 * time.Millisecond // gets doubled with every attempt + MaxDuration = time.Duration(math.MaxInt64) ) const ( diff --git a/pcap.go b/pcap.go index 354ec818..bcca3edd 100644 --- a/pcap.go +++ b/pcap.go @@ -40,7 +40,7 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca if err = inactive.SetSnapLen(snaplen); err != nil { return } - if err = inactive.SetTimeout(-1); err != nil { + if err = inactive.SetTimeout(MaxDuration); err != nil { return } if err = inactive.SetImmediateMode(true); err != nil { @@ -60,7 +60,12 @@ func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *Pca } func (pi *PcapIO) ReadPacket() (data []byte, err error) { - data, _, err = pi.handle.ZeroCopyReadPacketData() + for { + data, _, err = pi.handle.ZeroCopyReadPacketData() + if err == nil || err != pcap.NextErrorTimeoutExpired { + break + } + } return }