1
0

gateway.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package routing
  2. import (
  3. "fmt"
  4. "net/netip"
  5. "strings"
  6. )
  7. const (
  8. // Sentinel value
  9. BucketNotCalculated = -1
  10. )
  11. type Gateways []Gateway
  12. func (g Gateways) String() string {
  13. var str strings.Builder
  14. for i, gw := range g {
  15. str.WriteString(gw.String())
  16. if i < len(g)-1 {
  17. str.WriteString(", ")
  18. }
  19. }
  20. return str.String()
  21. }
  22. type Gateway struct {
  23. addr netip.Addr
  24. weight int
  25. bucketUpperBound int
  26. }
  27. func NewGateway(addr netip.Addr, weight int) Gateway {
  28. return Gateway{addr: addr, weight: weight, bucketUpperBound: BucketNotCalculated}
  29. }
  30. func (g *Gateway) BucketUpperBound() int {
  31. return g.bucketUpperBound
  32. }
  33. func (g *Gateway) Addr() netip.Addr {
  34. return g.addr
  35. }
  36. func (g *Gateway) String() string {
  37. return fmt.Sprintf("{addr: %s, weight: %d}", g.addr, g.weight)
  38. }
  39. // Divide and round to nearest integer
  40. func divideAndRound(v uint64, d uint64) uint64 {
  41. var tmp uint64 = v + d/2
  42. return tmp / d
  43. }
  44. // Implements Hash-Threshold mapping, equivalent to the implementation in the linux kernel.
  45. // After this function returns each gateway will have a
  46. // positive bucketUpperBound with a maximum value of 2147483647 (INT_MAX)
  47. func CalculateBucketsForGateways(gateways []Gateway) {
  48. var totalWeight int = 0
  49. for i := range gateways {
  50. totalWeight += gateways[i].weight
  51. }
  52. var loopWeight int = 0
  53. for i := range gateways {
  54. loopWeight += gateways[i].weight
  55. gateways[i].bucketUpperBound = int(divideAndRound(uint64(loopWeight)<<31, uint64(totalWeight))) - 1
  56. }
  57. }