bits.go 4.5 KB

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