diff --git a/crew/connect.go b/crew/connect.go index c7f3c77..b40abb4 100644 --- a/crew/connect.go +++ b/crew/connect.go @@ -224,7 +224,7 @@ func expand(fromTerminal terminal.OpTerminal, from, to *navigator.Pin) (expansio // connection. type TunnelContext struct { Path []*TunnelContextHop - PathCost int + PathCost float32 RoutingAlg string } diff --git a/navigator/findnearest.go b/navigator/findnearest.go index 444d2cc..c6b84af 100644 --- a/navigator/findnearest.go +++ b/navigator/findnearest.go @@ -77,8 +77,8 @@ func (nb *nearbyPins) clean() { } // nearbyPin represents a Pin and the proximity to a certain location. -func (nb *nearbyPin) DstCost() int { - return 100 - nb.proximity // TODO: weigh with other costs +func (nb *nearbyPin) DstCost() float32 { + return 100 - float32(nb.proximity) // TODO: weigh with other costs } // FindNearestHubs searches for the nearest Hubs to the given IP address. The returned Hubs must not be modified in any way. diff --git a/navigator/findroutes.go b/navigator/findroutes.go index debe109..7634a04 100644 --- a/navigator/findroutes.go +++ b/navigator/findroutes.go @@ -114,7 +114,7 @@ func (m *Map) findRoutes(dsts *nearbyPins, opts *Options, maxRoutes int) (*Route } // Add Pin to the current path and remove when done. - route.addHop(lane.Pin, int(lane.Latency/100000)) + route.addHop(lane.Pin, lane.Cost+lane.Pin.Cost) defer route.removeHop() // Check if the route would even make it into the list. diff --git a/navigator/pin.go b/navigator/pin.go index 434d8d9..208d573 100644 --- a/navigator/pin.go +++ b/navigator/pin.go @@ -22,9 +22,14 @@ type Pin struct { LocationV6 *geoip.Location // Hub Status - State PinState + State PinState + // HopDistance signifies the needed hops to reach this Hub. + // HopDistance is measured from the view of a client. + // A Hub itself will have itself at distance 1. HopDistance int - Load int // estimated in microseconds this port adds to latency + // Cost is the routing cost of this Hub. + Cost float32 + // ConnectedTo holds validated lanes. ConnectedTo map[string]*Lane // Key is Hub ID. // FailingUntil specifies until when this Hub should be regarded as failing. @@ -67,6 +72,9 @@ type Lane struct { // It is specified in nanoseconds. Latency time.Duration + // Cost is the routing cost of this lane. + Cost float32 + // active is a helper flag in order help remove abandoned Lanes. active bool } diff --git a/navigator/route.go b/navigator/route.go index 5671638..cf43e77 100644 --- a/navigator/route.go +++ b/navigator/route.go @@ -8,8 +8,8 @@ import ( type Routes struct { All []*Route - maxCost int // automatic - maxRoutes int // manual setting + maxCost float32 // automatic + maxRoutes int // manual setting } // Len is the number of elements in the collection. @@ -61,14 +61,14 @@ func (r *Routes) clean() { type Route struct { // DstCost is the calculated cost between the Destination Hub and the destination IP. - DstCost int + DstCost float32 // Path is a list of Transit Hubs and the Destination Hub, including the Cost // for each Hop. Path []*Hop // TotalCost is the sum of all costs of this Route. - TotalCost int + TotalCost float32 // Algorithm is the ID of the algorithm used to calculate the route. Algorithm string @@ -81,11 +81,11 @@ type Hop struct { HubID string // Cost is the cost for both Lane to this Hub and the Hub itself. - Cost int + Cost float32 } // addHop adds a hop to the route. -func (r *Route) addHop(pin *Pin, cost int) { +func (r *Route) addHop(pin *Pin, cost float32) { r.Path = append(r.Path, &Hop{ pin: pin, Cost: cost, @@ -95,7 +95,7 @@ func (r *Route) addHop(pin *Pin, cost int) { // completeRoute completes the route by adding the destination cost of the // connection between the last hop and the destination IP. -func (r *Route) completeRoute(dstCost int) { +func (r *Route) completeRoute(dstCost float32) { r.DstCost = dstCost r.recalculateTotalCost() } @@ -117,7 +117,7 @@ func (r *Route) recalculateTotalCost() { for _, hop := range r.Path { if hop.pin.HasActiveTerminal() { // If we have an active connection, only take 90% of the cost. - r.TotalCost += (hop.Cost * 9) / 10 + r.TotalCost += hop.Cost * 0.9 } else { r.TotalCost += hop.Cost } diff --git a/navigator/routing-profiles.go b/navigator/routing-profiles.go index 1350b66..591ad8a 100644 --- a/navigator/routing-profiles.go +++ b/navigator/routing-profiles.go @@ -25,7 +25,7 @@ type RoutingProfile struct { // cost of the currently best route. This is an optimization option and // should not interfere with finding the best route, but might reduce the // amount of routes found. - MaxExtraCost int + MaxExtraCost float32 } const ( diff --git a/navigator/update.go b/navigator/update.go index 78f1691..ab7c012 100644 --- a/navigator/update.go +++ b/navigator/update.go @@ -166,8 +166,17 @@ func (m *Map) updateHub(h *hub.Hub, lockMap, lockHub bool) { // Update Trust and Advisory Statuses. m.updateIntelStatuses(pin) - // Update Hub load. - pin.Load = pin.Hub.Status.Load + // Update Hub cost. + switch { + case pin.Hub.Status.Load >= 100: + pin.Cost = 10000 + case pin.Hub.Status.Load >= 95: + pin.Cost = 1000 + case pin.Hub.Status.Load >= 80: + pin.Cost = 200 + default: + pin.Cost = 50 + } // Mark all existing Lanes as inactive. for _, lane := range pin.ConnectedTo { @@ -220,6 +229,17 @@ func (m *Map) updateHub(h *hub.Hub, lockMap, lockHub bool) { m.PushPinChanges() } +const ( + minUnconfirmedLatency = 10 * time.Millisecond + maxUnconfirmedCapacity = 100000000 // 100Mbit/s + + cap1Mbit = 1000000 + cap10Mbit = 10000000 + cap100Mbit = 100000000 + cap1Gbit = 1000000000 + cap10Gbit = 10000000000 +) + // updateHubLane updates a lane between two Hubs on the Map. // pin must already be locked, lane belongs to pin. // peer will be locked by this function. @@ -246,29 +266,61 @@ func (m *Map) updateHubLane(pin *Pin, lane *hub.Lane, peer *Pin) { return } - // Calculate matching Capacity and Latency values between both Hubs. - combinedCapacity := lane.Capacity - if peerLane.Capacity < combinedCapacity { - // For Capacity, use the lesser value of both. - combinedCapacity = peerLane.Capacity - } + // Calculate combined latency, use the greater value. combinedLatency := lane.Latency if peerLane.Latency > combinedLatency { - // For Latency, use the greater value of both. combinedLatency = peerLane.Latency } + // Enforce minimum value if at least one side has no data. + if (lane.Latency == 0 || peerLane.Latency == 0) && combinedLatency < minUnconfirmedLatency { + combinedLatency = minUnconfirmedLatency + } + + // Calculate combined capacity, use the lesser existing value. + combinedCapacity := lane.Capacity + if combinedCapacity == 0 || (peerLane.Capacity > 0 && peerLane.Capacity < combinedCapacity) { + combinedCapacity = peerLane.Capacity + } + // Enforce maximum value if at least one side has no data. + if (lane.Capacity == 0 || peerLane.Capacity == 0) && combinedCapacity > maxUnconfirmedCapacity { + combinedCapacity = maxUnconfirmedCapacity + } + + // Calculate cost: + var laneCost float32 + // - One point for every ms in latency (linear) + laneCost += float32(combinedLatency) / float32(time.Millisecond) + switch { + case combinedCapacity < cap1Mbit: + // - Between 1000 and 10000 points for ranges below 1Mbit/s + laneCost += 1000 + 9000*((cap1Mbit-float32(combinedCapacity))/cap1Mbit) + case combinedCapacity < cap10Mbit: + // - Between 200 and 1000 points for ranges below 10Mbit/s + laneCost += 200 + 800*((cap10Mbit-float32(combinedCapacity))/cap10Mbit) + case combinedCapacity < cap100Mbit: + // - Between 20 and 200 points for ranges below 100Mbit/s + laneCost += 20 + 180*((cap100Mbit-float32(combinedCapacity))/cap100Mbit) + case combinedCapacity < cap1Gbit: + // - Between 5 and 20 points for ranges below 1Gbit/s + laneCost += 5 + 15*((cap1Gbit-float32(combinedCapacity))/cap1Gbit) + case combinedCapacity < cap10Gbit: + // - Between 0 and 5 points for ranges below 10Gbit/s + laneCost += 5 * ((cap10Gbit - float32(combinedCapacity)) / cap10Gbit) + } // Add Lane to both Pins and override old values in the process. pin.ConnectedTo[peer.Hub.ID] = &Lane{ Pin: peer, Capacity: combinedCapacity, Latency: combinedLatency, + Cost: laneCost, active: true, } peer.ConnectedTo[pin.Hub.ID] = &Lane{ Pin: pin, Capacity: combinedCapacity, Latency: combinedLatency, + Cost: laneCost, active: true, } peer.pushChanges.Set()