Commit eb7ec381 authored by Yohann D'Anello's avatar Yohann D'Anello

[monitoring] Implement cost multiplier

Signed-off-by: Yohann D'Anello's avatarYohann D'ANELLO <ynerant@crans.org>
parent 660f2d21
...@@ -2,8 +2,9 @@ import logging ...@@ -2,8 +2,9 @@ import logging
import random import random
import socket import socket
import subprocess import subprocess
import time
from re6st import utils from re6st import utils, ctl
RE6ST_PORT = 326 # Found in tunnel.PORT, but we want to avoid import loops RE6ST_PORT = 326 # Found in tunnel.PORT, but we want to avoid import loops
MONITORING_PORT = 327 # Port used for monitoring MONITORING_PORT = 327 # Port used for monitoring
...@@ -42,9 +43,9 @@ class MonitoringManager: ...@@ -42,9 +43,9 @@ class MonitoringManager:
Refresh routes that are used for link monitoring. Refresh routes that are used for link monitoring.
""" """
# Cleanup old routes # Cleanup old routes
for link in list(self.links.values()): # for link in list(self.links.values()):
if link.prefix not in self.tunnel_manager.ctl.neighbours: # if link.prefix not in self.tunnel_manager.ctl.neighbours:
link.delete() # link.delete()
# Babel is not initialized yet. # Babel is not initialized yet.
if not hasattr(self.tunnel_manager.ctl, 'neighbours'): if not hasattr(self.tunnel_manager.ctl, 'neighbours'):
...@@ -69,16 +70,24 @@ class MonitoringLink: ...@@ -69,16 +70,24 @@ class MonitoringLink:
manager = None manager = None
prefix = None prefix = None
address = None address = None
neighbour = None
last_sent_pings = None
last_received_pings = None
old_multiplier = None
def __init__(self, monitoring_manager, prefix): def __init__(self, monitoring_manager, prefix):
self.manager = monitoring_manager self.manager = monitoring_manager
self.prefix = prefix self.prefix = prefix
self.last_sent_pings = []
self.last_received_pings = []
@property @property
def tested_address(self): def tested_address(self):
return utils.ipFromBin(self.manager.tunnel_manager._network + self.prefix) return utils.ipFromBin(self.manager.tunnel_manager._network + self.prefix)
def update_link(self, neighbour): def update_link(self, neighbour):
self.neighbour = neighbour
nexthop = neighbour.address nexthop = neighbour.address
nexthop = utils.ipFromBin("".join(bin(ord(c))[2:].zfill(8) for c in nexthop)) nexthop = utils.ipFromBin("".join(bin(ord(c))[2:].zfill(8) for c in nexthop))
...@@ -111,8 +120,10 @@ class MonitoringLink: ...@@ -111,8 +120,10 @@ class MonitoringLink:
def monitor(self): def monitor(self):
msock = None msock = None
try: try:
print("Send ping from " + self.address + " for " + self.tested_address # print("Send ping from " + self.address + " for " + self.tested_address
+ " to " + self.manager.main_address + "...") # + " to " + self.manager.main_address + "...")
self.last_sent_pings.append(time.time()) # Store time even if there is an error.
msock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) msock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
msock.bind((self.address, MONITORING_PORT)) msock.bind((self.address, MONITORING_PORT))
msg = b'\x08' msg = b'\x08'
...@@ -122,7 +133,8 @@ class MonitoringLink: ...@@ -122,7 +133,8 @@ class MonitoringLink:
msock.sendto(data, (self.manager.main_address, RE6ST_PORT)) msock.sendto(data, (self.manager.main_address, RE6ST_PORT))
except Exception, e: except Exception, e:
logging.error("Error while monitoring " + self.tested_address + ": " + str(e)) logging.error("Error while monitoring " + self.tested_address + ": " + str(e))
self.manager.tunnel_manager.newVersion() # Maybe babel dump is not up to date # Maybe babel dump is not up to date
self.manager.tunnel_manager.selectTimeout(time.time() + 1, self.manager.tunnel_manager.newVersion)
finally: finally:
if msock: if msock:
try: try:
...@@ -130,18 +142,54 @@ class MonitoringLink: ...@@ -130,18 +142,54 @@ class MonitoringLink:
finally: finally:
pass pass
now = time.time()
self.last_sent_pings = [t for t in self.last_sent_pings if now - t < 31]
self.last_received_pings = [t for t in self.last_received_pings if now - t < 31]
if len(self.last_sent_pings) - len(self.last_received_pings) > 4:
# 4 pings over 6 failed, consider the link as bad
print(self.tested_address + " is a bad neighbour")
if self.old_multiplier is None:
self.old_multiplier = self.neighbour.cost_multiplier
self.manager.tunnel_manager.ctl.send(
ctl.SetCostMultiplier(self.neighbour.address, self.neighbour.ifindex, 4096)
)
self.manager.tunnel_manager.selectTimeout(now + 1, self.manager.tunnel_manager.newVersion)
def ping(self): def ping(self):
"""
We received a ping. We store it, and we reset the cost multiplier
since the link seems to be working.
"""
self.manager.main_peer._i -= 1 # Don't increment seqno with this packet self.manager.main_peer._i -= 1 # Don't increment seqno with this packet
print("Monitoring!") # print("Monitoring!")
print(self.address) # print(self.address)
self.last_received_pings.append(time.time())
self.last_sent_pings = [t for t in self.last_sent_pings if time.time() - t < 16] # The link may work
# Reset cost multiplier to its old state
if self.old_multiplier is not None:
print(self.tested_address + " became a good neighbour")
self.manager.tunnel_manager.ctl.send(
ctl.SetCostMultiplier(self.neighbour.address, self.neighbour.ifindex, self.old_multiplier)
)
self.old_multiplier = None
self.manager.tunnel_manager.selectTimeout(time.time() + 1, self.manager.tunnel_manager.newVersion)
def delete(self): def delete(self):
self.last_sent_pings = []
self.last_received_pings = []
if self.old_multiplier is not None:
self.manager.tunnel_manager.ctl.send(
ctl.SetCostMultiplier(self.neighbour.address, self.neighbour.ifindex, self.old_multiplier)
)
self.old_multiplier = None
subprocess.check_call(('ip', '-6', 'address', 'del', self.address, 'dev', self.manager.main_interface)) subprocess.check_call(('ip', '-6', 'address', 'del', self.address, 'dev', self.manager.main_interface))
subprocess.check_call(('ip', '-6', 'route', 'del', self.manager.main_address, subprocess.check_call(('ip', '-6', 'route', 'del', self.manager.main_address,
'from', self.address, 'table', '34071')) 'from', self.address, 'table', '34071'))
if self.prefix in self.manager.links: if self.prefix in self.manager.links:
del self.manager.links[self.prefix] del self.manager.links[self.prefix]
def __del__(self):
self.delete()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment