bits.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package nebula
  2. import (
  3. "github.com/rcrowley/go-metrics"
  4. "github.com/sirupsen/logrus"
  5. )
  6. type Bits struct {
  7. length uint64
  8. current uint64
  9. bits []bool
  10. lostCounter metrics.Counter
  11. dupeCounter metrics.Counter
  12. outOfWindowCounter metrics.Counter
  13. }
  14. func NewBits(bits uint64) *Bits {
  15. b := &Bits{
  16. length: bits,
  17. bits: make([]bool, bits, bits),
  18. current: 0,
  19. lostCounter: metrics.GetOrRegisterCounter("network.packets.lost", nil),
  20. dupeCounter: metrics.GetOrRegisterCounter("network.packets.duplicate", nil),
  21. outOfWindowCounter: metrics.GetOrRegisterCounter("network.packets.out_of_window", nil),
  22. }
  23. // There is no counter value 0, mark it to avoid counting a lost packet later.
  24. b.bits[0] = true
  25. b.current = 0
  26. return b
  27. }
  28. func (b *Bits) Check(l *logrus.Logger, i uint64) bool {
  29. // If i is the next number, return true.
  30. if i > b.current {
  31. return true
  32. }
  33. // If i is within the window, check if it's been set already.
  34. if i > b.current-b.length || i < b.length && b.current < b.length {
  35. return !b.bits[i%b.length]
  36. }
  37. // Not within the window
  38. if l.Level >= logrus.DebugLevel {
  39. l.Debugf("rejected a packet (top) %d %d\n", b.current, i)
  40. }
  41. return false
  42. }
  43. func (b *Bits) Update(l *logrus.Logger, i uint64) bool {
  44. // If i is the next number, return true and update current.
  45. if i == b.current+1 {
  46. // Check if the oldest bit was lost since we are shifting the window by 1 and occupying it with this counter
  47. // The very first window can only be tracked as lost once we are on the 2nd window or greater
  48. if b.bits[i%b.length] == false && i > b.length {
  49. b.lostCounter.Inc(1)
  50. }
  51. b.bits[i%b.length] = true
  52. b.current = i
  53. return true
  54. }
  55. // If i is a jump, adjust the window, record lost, update current, and return true
  56. if i > b.current {
  57. lost := int64(0)
  58. // Zero out the bits between the current and the new counter value, limited by the window size,
  59. // since the window is shifting
  60. for n := b.current + 1; n <= min(i, b.current+b.length); n++ {
  61. if b.bits[n%b.length] == false && n > b.length {
  62. lost++
  63. }
  64. b.bits[n%b.length] = false
  65. }
  66. // Only record any skipped packets as a result of the window moving further than the window length
  67. // Any loss within the new window will be accounted for in future calls
  68. lost += max(0, int64(i-b.current-b.length))
  69. b.lostCounter.Inc(lost)
  70. b.bits[i%b.length] = true
  71. b.current = i
  72. return true
  73. }
  74. // If i is within the current window but below the current counter,
  75. // Check to see if it's a duplicate
  76. if i > b.current-b.length || i < b.length && b.current < b.length {
  77. if b.current == i || b.bits[i%b.length] == true {
  78. if l.Level >= logrus.DebugLevel {
  79. l.WithField("receiveWindow", m{"accepted": false, "currentCounter": b.current, "incomingCounter": i, "reason": "duplicate"}).
  80. Debug("Receive window")
  81. }
  82. b.dupeCounter.Inc(1)
  83. return false
  84. }
  85. b.bits[i%b.length] = true
  86. return true
  87. }
  88. // In all other cases, fail and don't change current.
  89. b.outOfWindowCounter.Inc(1)
  90. if l.Level >= logrus.DebugLevel {
  91. l.WithField("accepted", false).
  92. WithField("currentCounter", b.current).
  93. WithField("incomingCounter", i).
  94. WithField("reason", "nonsense").
  95. Debug("Receive window")
  96. }
  97. return false
  98. }