mirror of
https://github.com/slackhq/nebula.git
synced 2025-04-28 14:42:22 +00:00
39 lines
1.2 KiB
Go
39 lines
1.2 KiB
Go
package routing
|
|
|
|
import (
|
|
"net/netip"
|
|
|
|
"github.com/slackhq/nebula/firewall"
|
|
)
|
|
|
|
// Hashes the packet source and destination port and always returns a positive integer
|
|
// Based on 'Prospecting for Hash Functions'
|
|
// - https://nullprogram.com/blog/2018/07/31/
|
|
// - https://github.com/skeeto/hash-prospector
|
|
// [16 21f0aaad 15 d35a2d97 15] = 0.10760229515479501
|
|
func hashPacket(p *firewall.Packet) int {
|
|
x := (uint32(p.LocalPort) << 16) | uint32(p.RemotePort)
|
|
x ^= x >> 16
|
|
x *= 0x21f0aaad
|
|
x ^= x >> 15
|
|
x *= 0xd35a2d97
|
|
x ^= x >> 15
|
|
|
|
return int(x) & 0x7FFFFFFF
|
|
}
|
|
|
|
// For this function to work correctly it requires that the buckets for the gateways have been calculated
|
|
// If the contract is violated balancing will not work properly and the second return value will return false
|
|
func BalancePacket(fwPacket *firewall.Packet, gateways []Gateway) (netip.Addr, bool) {
|
|
hash := hashPacket(fwPacket)
|
|
|
|
for i := range gateways {
|
|
if hash <= gateways[i].BucketUpperBound() {
|
|
return gateways[i].Addr(), true
|
|
}
|
|
}
|
|
|
|
// If you land here then the buckets for the gateways are not properly calculated
|
|
// Fallback to random routing and let the caller know
|
|
return gateways[hash%len(gateways)].Addr(), false
|
|
}
|