3
0

balance.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. package routing
  2. import (
  3. "net/netip"
  4. "github.com/slackhq/nebula/firewall"
  5. )
  6. // Hashes the packet source and destination port and always returns a positive integer
  7. // Based on 'Prospecting for Hash Functions'
  8. // - https://nullprogram.com/blog/2018/07/31/
  9. // - https://github.com/skeeto/hash-prospector
  10. // [16 21f0aaad 15 d35a2d97 15] = 0.10760229515479501
  11. func hashPacket(p *firewall.Packet) int {
  12. x := (uint32(p.LocalPort) << 16) | uint32(p.RemotePort)
  13. x ^= x >> 16
  14. x *= 0x21f0aaad
  15. x ^= x >> 15
  16. x *= 0xd35a2d97
  17. x ^= x >> 15
  18. return int(x) & 0x7FFFFFFF
  19. }
  20. // For this function to work correctly it requires that the buckets for the gateways have been calculated
  21. // If the contract is violated balancing will not work properly and the second return value will return false
  22. func BalancePacket(fwPacket *firewall.Packet, gateways []Gateway) (netip.Addr, bool) {
  23. hash := hashPacket(fwPacket)
  24. for i := range gateways {
  25. if hash <= gateways[i].BucketUpperBound() {
  26. return gateways[i].Addr(), true
  27. }
  28. }
  29. // If you land here then the buckets for the gateways are not properly calculated
  30. // Fallback to random routing and let the caller know
  31. return gateways[hash%len(gateways)].Addr(), false
  32. }