github.com/slackhq/nebula@v1.9.0/bits.go (about) 1 package nebula 2 3 import ( 4 "github.com/rcrowley/go-metrics" 5 "github.com/sirupsen/logrus" 6 ) 7 8 type Bits struct { 9 length uint64 10 current uint64 11 bits []bool 12 firstSeen bool 13 lostCounter metrics.Counter 14 dupeCounter metrics.Counter 15 outOfWindowCounter metrics.Counter 16 } 17 18 func NewBits(bits uint64) *Bits { 19 return &Bits{ 20 length: bits, 21 bits: make([]bool, bits, bits), 22 current: 0, 23 lostCounter: metrics.GetOrRegisterCounter("network.packets.lost", nil), 24 dupeCounter: metrics.GetOrRegisterCounter("network.packets.duplicate", nil), 25 outOfWindowCounter: metrics.GetOrRegisterCounter("network.packets.out_of_window", nil), 26 } 27 } 28 29 func (b *Bits) Check(l logrus.FieldLogger, i uint64) bool { 30 // If i is the next number, return true. 31 if i > b.current || (i == 0 && b.firstSeen == false && b.current < b.length) { 32 return true 33 } 34 35 // If i is within the window, check if it's been set already. The first window will fail this check 36 if i > b.current-b.length { 37 return !b.bits[i%b.length] 38 } 39 40 // If i is within the first window 41 if i < b.length { 42 return !b.bits[i%b.length] 43 } 44 45 // Not within the window 46 l.Debugf("rejected a packet (top) %d %d\n", b.current, i) 47 return false 48 } 49 50 func (b *Bits) Update(l *logrus.Logger, i uint64) bool { 51 // If i is the next number, return true and update current. 52 if i == b.current+1 { 53 // Report missed packets, we can only understand what was missed after the first window has been gone through 54 if i > b.length && b.bits[i%b.length] == false { 55 b.lostCounter.Inc(1) 56 } 57 b.bits[i%b.length] = true 58 b.current = i 59 return true 60 } 61 62 // If i packet is greater than current but less than the maximum length of our bitmap, 63 // flip everything in between to false and move ahead. 64 if i > b.current && i < b.current+b.length { 65 // In between current and i need to be zero'd to allow those packets to come in later 66 for n := b.current + 1; n < i; n++ { 67 b.bits[n%b.length] = false 68 } 69 70 b.bits[i%b.length] = true 71 b.current = i 72 //l.Debugf("missed %d packets between %d and %d\n", i-b.current, i, b.current) 73 return true 74 } 75 76 // If i is greater than the delta between current and the total length of our bitmap, 77 // just flip everything in the map and move ahead. 78 if i >= b.current+b.length { 79 // The current window loss will be accounted for later, only record the jump as loss up until then 80 lost := maxInt64(0, int64(i-b.current-b.length)) 81 //TODO: explain this 82 if b.current == 0 { 83 lost++ 84 } 85 86 for n := range b.bits { 87 // Don't want to count the first window as a loss 88 //TODO: this is likely wrong, we are wanting to track only the bit slots that we aren't going to track anymore and this is marking everything as missed 89 //if b.bits[n] == false { 90 // lost++ 91 //} 92 b.bits[n] = false 93 } 94 95 b.lostCounter.Inc(lost) 96 97 if l.Level >= logrus.DebugLevel { 98 l.WithField("receiveWindow", m{"accepted": true, "currentCounter": b.current, "incomingCounter": i, "reason": "window shifting"}). 99 Debug("Receive window") 100 } 101 b.bits[i%b.length] = true 102 b.current = i 103 return true 104 } 105 106 // Allow for the 0 packet to come in within the first window 107 if i == 0 && b.firstSeen == false && b.current < b.length { 108 b.firstSeen = true 109 b.bits[i%b.length] = true 110 return true 111 } 112 113 // If i is within the window of current minus length (the total pat window size), 114 // allow it and flip to true but to NOT change current. We also have to account for the first window 115 if ((b.current >= b.length && i > b.current-b.length) || (b.current < b.length && i < b.length)) && i <= b.current { 116 if b.current == i { 117 if l.Level >= logrus.DebugLevel { 118 l.WithField("receiveWindow", m{"accepted": false, "currentCounter": b.current, "incomingCounter": i, "reason": "duplicate"}). 119 Debug("Receive window") 120 } 121 b.dupeCounter.Inc(1) 122 return false 123 } 124 125 if b.bits[i%b.length] == true { 126 if l.Level >= logrus.DebugLevel { 127 l.WithField("receiveWindow", m{"accepted": false, "currentCounter": b.current, "incomingCounter": i, "reason": "old duplicate"}). 128 Debug("Receive window") 129 } 130 b.dupeCounter.Inc(1) 131 return false 132 } 133 134 b.bits[i%b.length] = true 135 return true 136 137 } 138 139 // In all other cases, fail and don't change current. 140 b.outOfWindowCounter.Inc(1) 141 if l.Level >= logrus.DebugLevel { 142 l.WithField("accepted", false). 143 WithField("currentCounter", b.current). 144 WithField("incomingCounter", i). 145 WithField("reason", "nonsense"). 146 Debug("Receive window") 147 } 148 return false 149 } 150 151 func maxInt64(a, b int64) int64 { 152 if a > b { 153 return a 154 } 155 156 return b 157 }