It often happens that we have several links between many points. And we want to use them all while taking into account latency and channel width. A trivial example is IP telephony or gaming.

Due to the peculiarity of speed cutting in ISP (almost all of them work on the same technology), the higher the speed, the better the channel. But this is not always the case - this feature must be taken into account.

In the context of routing (for example, in BGP), the greater the local-preference, the greater the weight of the route. Routing protocols do not (not always) have the ability to take latency into account. But it is possible to take into account local-preference. And we can use it to take into account latency.

How to calculate local-preference?

First you need to calculate the RTT between two points. Then we round up to 10 ms. Example: RTT 14 ms - rounded to 20 ms. This is necessary so that there is not too much difference in the link weight between 10 and 13 ms. This should compensate for some problems with the accuracy of RTT measurements and the peculiarities of the Internet structure.

Link weight (Scaling Factor), depending on its speed.

  • 1 - 100M
  • 2 - 500M
  • 3 - 1G
  • 4 - 2.5G
  • 5 - 5G
  • 6 - 10G
  • 7 - 25G
  • 8 - 40G
  • 9 - 40G+

We will count from 10 seconds. If the letency link takes more than 10 seconds, then we probably need to rethink everything, whether we are even needed on the desired planet (even less than 5 seconds to the moon).

Next we calculate the weight of the link:

Local Preference = (10000 / RTT) * Scaling Factor

Example code:

import math

def get_scale_factor(speed:int) -> int:
    if speed <= 100:
        return 1
    elif speed <= 500:
        return 2
    elif speed <= 1000:
        return 3
    elif speed <= 2500:
        return 4
    elif speed <= 5000:
        return 5
    elif speed <= 10000:
        return 6
    elif speed <= 25000:
        return 7
    elif speed <= 40000:
        return 8
    else:
        return 9


def get_local_preference(rtt:int, scale:int = 1) -> int:
    rounded_rtt = math.ceil(rtt / 10) * 10
    preference =  (10000 / rounded_rtt) * scale
    return math.ceil(preference)

Calculation example:

links = [
    {'name': 'isp1-to-server', 'rtt': 11, 'speed': 100},
    {'name': 'isp2-to-server', 'rtt': 17, 'speed': 500},
    {'name': 'isp3-to-server', 'rtt': 23, 'speed': 250},
    {'name': 'isp4-to-server', 'rtt': 34, 'speed': 100}
]

for link in links:
    scale = get_scale_factor(link['speed'])
    print(link['name'], "->", get_local_preference(link['rtt'], scale))
isp1-to-server -> 500
isp2-to-server -> 1000
isp3-to-server -> 667
isp4-to-server -> 250