|
|
|
|
@ -20,6 +20,7 @@ import ( |
|
|
|
|
"io" |
|
|
|
|
"io/ioutil" |
|
|
|
|
"log" |
|
|
|
|
"math" |
|
|
|
|
"math/big" |
|
|
|
|
"math/rand" |
|
|
|
|
"os" |
|
|
|
|
@ -27,6 +28,7 @@ import ( |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"sync" |
|
|
|
|
"sync/atomic" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"go4.org/mem" |
|
|
|
|
@ -120,6 +122,7 @@ type Server struct { |
|
|
|
|
multiForwarderCreated expvar.Int |
|
|
|
|
multiForwarderDeleted expvar.Int |
|
|
|
|
removePktForwardOther expvar.Int |
|
|
|
|
avgQueueDuration *uint64 // In milliseconds; accessed atomically
|
|
|
|
|
|
|
|
|
|
mu sync.Mutex |
|
|
|
|
closed bool |
|
|
|
|
@ -182,6 +185,7 @@ func NewServer(privateKey key.Private, logf logger.Logf) *Server { |
|
|
|
|
memSys0: ms.Sys, |
|
|
|
|
watchers: map[*sclient]bool{}, |
|
|
|
|
sentTo: map[key.Public]map[key.Public]int64{}, |
|
|
|
|
avgQueueDuration: new(uint64), |
|
|
|
|
} |
|
|
|
|
s.initMetacert() |
|
|
|
|
s.packetsRecvDisco = s.packetsRecvByKind.Get("disco") |
|
|
|
|
@ -611,8 +615,9 @@ func (c *sclient) handleFrameForwardPacket(ft frameType, fl uint32) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return c.sendPkt(dst, pkt{ |
|
|
|
|
bs: contents, |
|
|
|
|
src: srcKey, |
|
|
|
|
bs: contents, |
|
|
|
|
enqueuedAt: time.Now(), |
|
|
|
|
src: srcKey, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -665,8 +670,9 @@ func (c *sclient) handleFrameSendPacket(ft frameType, fl uint32) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
p := pkt{ |
|
|
|
|
bs: contents, |
|
|
|
|
src: c.key, |
|
|
|
|
bs: contents, |
|
|
|
|
enqueuedAt: time.Now(), |
|
|
|
|
src: c.key, |
|
|
|
|
} |
|
|
|
|
return c.sendPkt(dst, p) |
|
|
|
|
} |
|
|
|
|
@ -696,7 +702,7 @@ func (c *sclient) sendPkt(dst *sclient, p pkt) error { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
select { |
|
|
|
|
case <-dst.sendQueue: |
|
|
|
|
case pkt := <-dst.sendQueue: |
|
|
|
|
s.packetsDropped.Add(1) |
|
|
|
|
s.packetsDroppedQueueHead.Add(1) |
|
|
|
|
if verboseDropKeys[dstKey] { |
|
|
|
|
@ -705,6 +711,7 @@ func (c *sclient) sendPkt(dst *sclient, p pkt) error { |
|
|
|
|
msg := fmt.Sprintf("tail drop %s -> %s", p.src.ShortString(), dstKey.ShortString()) |
|
|
|
|
c.s.limitedLogf(msg) |
|
|
|
|
} |
|
|
|
|
c.recordQueueTime(pkt.enqueuedAt) |
|
|
|
|
if debug { |
|
|
|
|
c.logf("dropping packet from client %x queue head", dstKey) |
|
|
|
|
} |
|
|
|
|
@ -927,11 +934,13 @@ type pkt struct { |
|
|
|
|
// src is the who's the sender of the packet.
|
|
|
|
|
src key.Public |
|
|
|
|
|
|
|
|
|
// enqueuedAt is when a packet was put onto a queue before it was sent,
|
|
|
|
|
// and is used for reporting metrics on the duration of packets in the queue.
|
|
|
|
|
enqueuedAt time.Time |
|
|
|
|
|
|
|
|
|
// bs is the data packet bytes.
|
|
|
|
|
// The memory is owned by pkt.
|
|
|
|
|
bs []byte |
|
|
|
|
|
|
|
|
|
// TODO(danderson): enqueue time, to measure queue latency?
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *sclient) setPreferred(v bool) { |
|
|
|
|
@ -959,6 +968,25 @@ func (c *sclient) setPreferred(v bool) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// expMovingAverage returns the new moving average given the previous average,
|
|
|
|
|
// a new value, and an alpha decay factor.
|
|
|
|
|
// https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
|
|
|
|
|
func expMovingAverage(prev, newValue, alpha float64) float64 { |
|
|
|
|
return alpha*newValue + (1-alpha)*prev |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// recordQueueTime updates the average queue duration metric after a packet has been sent.
|
|
|
|
|
func (c *sclient) recordQueueTime(enqueuedAt time.Time) { |
|
|
|
|
elapsed := float64(time.Since(enqueuedAt).Milliseconds()) |
|
|
|
|
for { |
|
|
|
|
old := atomic.LoadUint64(c.s.avgQueueDuration) |
|
|
|
|
newAvg := expMovingAverage(math.Float64frombits(old), elapsed, 0.1) |
|
|
|
|
if atomic.CompareAndSwapUint64(c.s.avgQueueDuration, old, math.Float64bits(newAvg)) { |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *sclient) sendLoop(ctx context.Context) error { |
|
|
|
|
defer func() { |
|
|
|
|
// If the sender shuts down unilaterally due to an error, close so
|
|
|
|
|
@ -1002,6 +1030,7 @@ func (c *sclient) sendLoop(ctx context.Context) error { |
|
|
|
|
continue |
|
|
|
|
case msg := <-c.sendQueue: |
|
|
|
|
werr = c.sendPacket(msg.src, msg.bs) |
|
|
|
|
c.recordQueueTime(msg.enqueuedAt) |
|
|
|
|
continue |
|
|
|
|
case <-keepAliveTick.C: |
|
|
|
|
werr = c.sendKeepAlive() |
|
|
|
|
@ -1025,6 +1054,7 @@ func (c *sclient) sendLoop(ctx context.Context) error { |
|
|
|
|
continue |
|
|
|
|
case msg := <-c.sendQueue: |
|
|
|
|
werr = c.sendPacket(msg.src, msg.bs) |
|
|
|
|
c.recordQueueTime(msg.enqueuedAt) |
|
|
|
|
case <-keepAliveTick.C: |
|
|
|
|
werr = c.sendKeepAlive() |
|
|
|
|
} |
|
|
|
|
@ -1290,6 +1320,9 @@ func (s *Server) ExpVar() expvar.Var { |
|
|
|
|
m.Set("multiforwarder_created", &s.multiForwarderCreated) |
|
|
|
|
m.Set("multiforwarder_deleted", &s.multiForwarderDeleted) |
|
|
|
|
m.Set("packet_forwarder_delete_other_value", &s.removePktForwardOther) |
|
|
|
|
m.Set("average_queue_duration_ms", expvar.Func(func() interface{} { |
|
|
|
|
return math.Float64frombits(atomic.LoadUint64(s.avgQueueDuration)) |
|
|
|
|
})) |
|
|
|
|
var expvarVersion expvar.String |
|
|
|
|
expvarVersion.Set(version.Long) |
|
|
|
|
m.Set("version", &expvarVersion) |
|
|
|
|
|