mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-22 08:24:25 +01:00
113 lines
3.3 KiB
Go
113 lines
3.3 KiB
Go
package nebula
|
|
|
|
import (
|
|
"github.com/rcrowley/go-metrics"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Bits struct {
|
|
length uint64
|
|
current uint64
|
|
bits []bool
|
|
lostCounter metrics.Counter
|
|
dupeCounter metrics.Counter
|
|
outOfWindowCounter metrics.Counter
|
|
}
|
|
|
|
func NewBits(bits uint64) *Bits {
|
|
b := &Bits{
|
|
length: bits,
|
|
bits: make([]bool, bits, bits),
|
|
current: 0,
|
|
lostCounter: metrics.GetOrRegisterCounter("network.packets.lost", nil),
|
|
dupeCounter: metrics.GetOrRegisterCounter("network.packets.duplicate", nil),
|
|
outOfWindowCounter: metrics.GetOrRegisterCounter("network.packets.out_of_window", nil),
|
|
}
|
|
|
|
// There is no counter value 0, mark it to avoid counting a lost packet later.
|
|
b.bits[0] = true
|
|
b.current = 0
|
|
return b
|
|
}
|
|
|
|
func (b *Bits) Check(l *logrus.Logger, i uint64) bool {
|
|
// If i is the next number, return true.
|
|
if i > b.current {
|
|
return true
|
|
}
|
|
|
|
// If i is within the window, check if it's been set already.
|
|
if i > b.current-b.length || i < b.length && b.current < b.length {
|
|
return !b.bits[i%b.length]
|
|
}
|
|
|
|
// Not within the window
|
|
if l.Level >= logrus.DebugLevel {
|
|
l.Debugf("rejected a packet (top) %d %d\n", b.current, i)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (b *Bits) Update(l *logrus.Logger, i uint64) bool {
|
|
// If i is the next number, return true and update current.
|
|
if i == b.current+1 {
|
|
// Check if the oldest bit was lost since we are shifting the window by 1 and occupying it with this counter
|
|
// The very first window can only be tracked as lost once we are on the 2nd window or greater
|
|
if b.bits[i%b.length] == false && i > b.length {
|
|
b.lostCounter.Inc(1)
|
|
}
|
|
b.bits[i%b.length] = true
|
|
b.current = i
|
|
return true
|
|
}
|
|
|
|
// If i is a jump, adjust the window, record lost, update current, and return true
|
|
if i > b.current {
|
|
lost := int64(0)
|
|
// Zero out the bits between the current and the new counter value, limited by the window size,
|
|
// since the window is shifting
|
|
for n := b.current + 1; n <= min(i, b.current+b.length); n++ {
|
|
if b.bits[n%b.length] == false && n > b.length {
|
|
lost++
|
|
}
|
|
b.bits[n%b.length] = false
|
|
}
|
|
|
|
// Only record any skipped packets as a result of the window moving further than the window length
|
|
// Any loss within the new window will be accounted for in future calls
|
|
lost += max(0, int64(i-b.current-b.length))
|
|
b.lostCounter.Inc(lost)
|
|
|
|
b.bits[i%b.length] = true
|
|
b.current = i
|
|
return true
|
|
}
|
|
|
|
// If i is within the current window but below the current counter,
|
|
// Check to see if it's a duplicate
|
|
if i > b.current-b.length || i < b.length && b.current < b.length {
|
|
if b.current == i || b.bits[i%b.length] == true {
|
|
if l.Level >= logrus.DebugLevel {
|
|
l.WithField("receiveWindow", m{"accepted": false, "currentCounter": b.current, "incomingCounter": i, "reason": "duplicate"}).
|
|
Debug("Receive window")
|
|
}
|
|
b.dupeCounter.Inc(1)
|
|
return false
|
|
}
|
|
|
|
b.bits[i%b.length] = true
|
|
return true
|
|
}
|
|
|
|
// In all other cases, fail and don't change current.
|
|
b.outOfWindowCounter.Inc(1)
|
|
if l.Level >= logrus.DebugLevel {
|
|
l.WithField("accepted", false).
|
|
WithField("currentCounter", b.current).
|
|
WithField("incomingCounter", i).
|
|
WithField("reason", "nonsense").
|
|
Debug("Receive window")
|
|
}
|
|
return false
|
|
}
|