bits.go 4.6 KB

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