| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- 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
- }
|