Commit 8f254e2d authored by Pedro Oliveira's avatar Pedro Oliveira

use IPDB also to obtain metric and RPF interface

parent 3ac652db
...@@ -355,7 +355,7 @@ class Kernel: ...@@ -355,7 +355,7 @@ class Kernel:
if ip_src not in self.routing: if ip_src not in self.routing:
self.routing[ip_src] = {} self.routing[ip_src] = {}
iif = self.vif_dic.get(UnicastRouting.check_rpf(ip_src)) iif = UnicastRouting.check_rpf(ip_src)
self.set_flood_multicast_route(ip_src, ip_dst, iif) self.set_flood_multicast_route(ip_src, ip_dst, iif)
self.routing[ip_src][ip_dst] = kernel_entry self.routing[ip_src][ip_dst] = kernel_entry
return kernel_entry return kernel_entry
......
import socket import socket
import ipaddress import ipaddress
from threading import RLock
from pyroute2 import IPDB, IPRoute from pyroute2 import IPDB, IPRoute
import Main import Main
from utils import if_indextoname
def get_route(ip_dst: str): def get_route(ip_dst: str):
...@@ -17,10 +18,12 @@ def check_rpf(ip_dst): ...@@ -17,10 +18,12 @@ def check_rpf(ip_dst):
return UnicastRouting.check_rpf(ip_dst) return UnicastRouting.check_rpf(ip_dst)
def get_unicast_info(ip_dst):
return UnicastRouting.get_unicast_info(ip_dst)
class UnicastRouting(object): class UnicastRouting(object):
ipr = None
ipdb = None ipdb = None
lock = RLock()
def __init__(self): def __init__(self):
UnicastRouting.ipr = IPRoute() UnicastRouting.ipr = IPRoute()
...@@ -28,13 +31,25 @@ class UnicastRouting(object): ...@@ -28,13 +31,25 @@ class UnicastRouting(object):
self._ipdb = UnicastRouting.ipdb self._ipdb = UnicastRouting.ipdb
self._ipdb.register_callback(UnicastRouting.unicast_changes, mode="post") self._ipdb.register_callback(UnicastRouting.unicast_changes, mode="post")
# get metrics (routing preference and cost) to IP ip_dst
@staticmethod @staticmethod
def get_route(ip_dst: str): def get_metric(ip_dst: str):
(metric_administrative_distance, metric_cost, _, _, mask) = UnicastRouting.get_unicast_info(ip_dst)
return (metric_administrative_distance, metric_cost, mask)
# get output interface IP, used to send data to IP ip_dst
# (root interface IP to ip_dst)
@staticmethod
def check_rpf(ip_dst):
# vif index of rpf interface
return UnicastRouting.get_unicast_info(ip_dst)[3]
@staticmethod
def get_route(ip_dst: str):
ip_bytes = socket.inet_aton(ip_dst) ip_bytes = socket.inet_aton(ip_dst)
ip_int = int.from_bytes(ip_bytes, byteorder='big') ip_int = int.from_bytes(ip_bytes, byteorder='big')
info = None info = None
with UnicastRouting.lock:
ipdb = UnicastRouting.ipdb # type:IPDB ipdb = UnicastRouting.ipdb # type:IPDB
for mask_len in range(32, 0, -1): for mask_len in range(32, 0, -1):
...@@ -42,46 +57,59 @@ class UnicastRouting(object): ...@@ -42,46 +57,59 @@ class UnicastRouting(object):
ip_dst = socket.inet_ntoa(ip_bytes) + "/" + str(mask_len) ip_dst = socket.inet_ntoa(ip_bytes) + "/" + str(mask_len)
print(ip_dst) print(ip_dst)
if ip_dst in ipdb.routes: if ip_dst in ipdb.routes:
print(info)
if ipdb.routes[ip_dst]['ipdb_scope'] != 'gc':
info = ipdb.routes[ip_dst] info = ipdb.routes[ip_dst]
break break
else: else:
continue continue
if not info: if not info:
print("0.0.0.0/0") print("0.0.0.0/0")
if "default" in ipdb.routes:
info = ipdb.routes["default"] info = ipdb.routes["default"]
print(info) print(info)
return info return info
# get metrics (routing preference and cost) to IP ip_dst
@staticmethod @staticmethod
def get_metric(ip_dst: str): def get_unicast_info(ip_dst):
unicast_routing_entry = UnicastRouting.get_route(ip_dst) metric_administrative_distance = 0xFFFFFFFF
entry_protocol = unicast_routing_entry["proto"] metric_cost = 0xFFFFFFFF
entry_cost = unicast_routing_entry["priority"] rpf_node = ip_dst
mask = unicast_routing_entry["dst_len"] oif = None
if entry_cost is None: mask = 0
entry_cost = 0 unicast_route = UnicastRouting.get_route(ip_dst)
return (entry_protocol, entry_cost, mask) if unicast_route is not None:
oif = unicast_route.get("oif")
next_hop = unicast_route["gateway"]
multipaths = unicast_route["multipath"]
# prefsrc = unicast_route.get("prefsrc")
# rpf_node = ip_dst if (next_hop is None and prefsrc is not None) else next_hop
rpf_node = next_hop if next_hop is not None else ip_dst
highest_ip = ipaddress.ip_address("0.0.0.0")
for m in multipaths:
if m["gateway"] is None:
oif = m.get('oif')
rpf_node = ip_dst
break
elif ipaddress.ip_address(m["gateway"]) > highest_ip:
highest_ip = ipaddress.ip_address(m["gateway"])
oif = m.get('oif')
rpf_node = m["gateway"]
# get output interface IP, used to send data to IP ip_dst metric_administrative_distance = unicast_route["proto"]
# (root interface IP to ip_dst) metric_cost = unicast_route["priority"]
@staticmethod metric_cost = metric_cost if metric_cost is not None else 0
def check_rpf(ip_dst): mask = unicast_route["dst_len"]
# obter index da interface
# rpf_interface_index = ipr.get_routes(family=socket.AF_INET, dst=ip)[0]['attrs'][2][1]
# interface_name = if_indextoname(rpf_interface_index)
# return interface_name
# obter ip da interface de saida interface_name = None if oif is None else if_indextoname(int(oif))
rpf_interface_source = UnicastRouting.ipr.get_routes(family=socket.AF_INET, dst=ip_dst)[0]['attrs'][3][1] rpf_if = Main.kernel.vif_name_to_index_dic.get(interface_name)
return rpf_interface_source return (metric_administrative_distance, metric_cost, rpf_node, rpf_if, mask)
@staticmethod @staticmethod
def unicast_changes(ipdb, msg, action): def unicast_changes(ipdb, msg, action):
print("unicast change?") print("unicast change?")
print(action) print(action)
UnicastRouting.lock.acquire()
UnicastRouting.ipdb = ipdb
if action == "RTM_NEWROUTE" or action == "RTM_DELROUTE": if action == "RTM_NEWROUTE" or action == "RTM_DELROUTE":
print(ipdb.routes) print(ipdb.routes)
mask_len = msg["dst_len"] mask_len = msg["dst_len"]
...@@ -100,12 +128,9 @@ class UnicastRouting(object): ...@@ -100,12 +128,9 @@ class UnicastRouting(object):
print(network_address + "/" + str(mask_len)) print(network_address + "/" + str(mask_len))
subnet = ipaddress.ip_network(network_address + "/" + str(mask_len)) subnet = ipaddress.ip_network(network_address + "/" + str(mask_len))
print(str(subnet)) print(str(subnet))
UnicastRouting.lock.release()
Main.kernel.notify_unicast_changes(subnet) Main.kernel.notify_unicast_changes(subnet)
elif action == "RTM_NEWADDR" or action == "RTM_DELADDR":
UnicastRouting.lock.release()
# TODO ALTERACOES NA INTERFACE
''' '''
elif action == "RTM_NEWADDR" or action == "RTM_DELADDR":
print(action) print(action)
print(msg) print(msg)
interface_name = None interface_name = None
...@@ -115,15 +140,37 @@ class UnicastRouting(object): ...@@ -115,15 +140,37 @@ class UnicastRouting(object):
if key == "IFA_LABEL": if key == "IFA_LABEL":
interface_name = value interface_name = value
break break
Main.kernel.notify_interface_change(interface_name)
'''
else:
UnicastRouting.lock.release() UnicastRouting.lock.release()
try:
Main.kernel.notify_interface_changes(interface_name)
except:
import traceback
traceback.print_exc()
pass
bnet = ipaddress.ip_network("0.0.0.0/0")
Main.kernel.notify_unicast_changes(subnet)
elif action == "RTM_NEWLINK" or action == "RTM_DELLINK":
attrs = msg["attrs"]
if_name = None
operation = None
for (key, value) in attrs:
print((key, value))
if key == "IFLA_IFNAME":
if_name = value
elif key == "IFLA_OPERSTATE":
operation = value
if if_name is not None and operation is not None:
break
if if_name is not None:
print(if_name + ": " + operation)
UnicastRouting.lock.release()
if operation == 'DOWN':
Main.kernel.remove_interface(if_name, igmp=True, pim=True)
subnet = ipaddress.ip_network("0.0.0.0/0")
Main.kernel.notify_unicast_changes(subnet)
'''
def stop(self): def stop(self):
if UnicastRouting.ipr:
UnicastRouting.ipr.close()
if UnicastRouting.ipdb: if UnicastRouting.ipdb:
UnicastRouting.ipdb = None UnicastRouting.ipdb = None
if self._ipdb: if self._ipdb:
......
...@@ -19,26 +19,12 @@ class KernelEntry: ...@@ -19,26 +19,12 @@ class KernelEntry:
self.source_ip = source_ip self.source_ip = source_ip
self.group_ip = group_ip self.group_ip = group_ip
# CHECK UNICAST ROUTING INFORMATION################################################### # OBTAIN UNICAST ROUTING INFORMATION###################################################
# CHOSE RPC INTERFACE (metric_administrative_distance, metric_cost, rpf_node, root_if, mask) = \
# GET RPC TO SOURCE UnicastRouting.get_unicast_info(source_ip)
unicast_route = UnicastRouting.get_route(source_ip) if root_if is None:
next_hop = unicast_route["gateway"] raise Exception
multipaths = unicast_route["multipath"] self.rpf_node = rpf_node
self.rpf_node = next_hop if next_hop is not None else source_ip
import ipaddress
highest_ip = ipaddress.ip_address("0.0.0.0")
for m in multipaths:
if m["gateway"] is None:
self.rpf_node = source_ip
break
elif ipaddress.ip_address(m["gateway"]) > highest_ip:
highest_ip = ipaddress.ip_address(m["gateway"])
self.rpf_node = m["gateway"]
print("RPF_NODE:", UnicastRouting.get_route(source_ip))
print(self.rpf_node == source_ip)
# (S,G) starts IG state # (S,G) starts IG state
self._was_olist_null = False self._was_olist_null = False
...@@ -49,7 +35,7 @@ class KernelEntry: ...@@ -49,7 +35,7 @@ class KernelEntry:
self.CHANGE_STATE_LOCK = RLock() self.CHANGE_STATE_LOCK = RLock()
# decide inbound interface based on rpf check # decide inbound interface based on rpf check
self.inbound_interface_index = Main.kernel.vif_dic[self.check_rpf()] self.inbound_interface_index = root_if
self.interface_state = {} # type: Dict[int, TreeInterface] self.interface_state = {} # type: Dict[int, TreeInterface]
with self.CHANGE_STATE_LOCK: with self.CHANGE_STATE_LOCK:
...@@ -69,9 +55,6 @@ class KernelEntry: ...@@ -69,9 +55,6 @@ class KernelEntry:
self.timestamp_of_last_state_refresh_message_received = 0 self.timestamp_of_last_state_refresh_message_received = 0
print('Tree created') print('Tree created')
#self._lock = threading.RLock()
def get_inbound_interface_index(self): def get_inbound_interface_index(self):
return self.inbound_interface_index return self.inbound_interface_index
...@@ -81,10 +64,6 @@ class KernelEntry: ...@@ -81,10 +64,6 @@ class KernelEntry:
outbound_indexes[index] = state.is_forwarding() outbound_indexes[index] = state.is_forwarding()
return outbound_indexes return outbound_indexes
def check_rpf(self):
return UnicastRouting.check_rpf(self.source_ip)
################################################ ################################################
# Receive (S,G) data packets or control packets # Receive (S,G) data packets or control packets
################################################ ################################################
...@@ -168,41 +147,10 @@ class KernelEntry: ...@@ -168,41 +147,10 @@ class KernelEntry:
def network_update(self): def network_update(self):
# TODO TALVEZ OUTRO LOCK PARA BLOQUEAR ENTRADA DE PACOTES # TODO TALVEZ OUTRO LOCK PARA BLOQUEAR ENTRADA DE PACOTES
with self.CHANGE_STATE_LOCK: with self.CHANGE_STATE_LOCK:
'''
next_hop = UnicastRouting.get_route(self.source_ip)["gateway"]
multipaths = UnicastRouting.get_route(self.source_ip)["multipath"]
rpf_node = next_hop
print("MUL", multipaths)
# self.rpf_node = multipaths[0]["gateway"]
for m in multipaths:
if m["gateway"] is None:
rpf_node = self.source_ip
break
else:
rpf_node = m["gateway"]
'''
unicast_route = UnicastRouting.get_route(self.source_ip)
next_hop = unicast_route["gateway"]
multipaths = unicast_route["multipath"]
rpf_node = next_hop if next_hop is not None else self.source_ip
import ipaddress
highest_ip = ipaddress.ip_address("0.0.0.0")
for m in multipaths:
if m["gateway"] is None:
rpf_node = self.source_ip
break
elif ipaddress.ip_address(m["gateway"]) > highest_ip:
highest_ip = ipaddress.ip_address(m["gateway"])
rpf_node = m["gateway"]
print("RPF_NODE:", UnicastRouting.get_route(self.source_ip))
(metric_administrative_distance, metric_cost, rpf_node, new_inbound_interface_index, _) = \
UnicastRouting.get_unicast_info(self.source_ip)
print(self.rpf_node == self.source_ip)
new_inbound_interface_index = Main.kernel.vif_dic.get(self.check_rpf(), None)
if new_inbound_interface_index is None: if new_inbound_interface_index is None:
self.delete() self.delete()
return return
...@@ -210,24 +158,30 @@ class KernelEntry: ...@@ -210,24 +158,30 @@ class KernelEntry:
self.rpf_node = rpf_node self.rpf_node = rpf_node
# get old interfaces # get old interfaces
old_upstream_interface = self.interface_state[self.inbound_interface_index] old_upstream_interface = self.interface_state.get(self.inbound_interface_index, None)
old_downstream_interface = self.interface_state[new_inbound_interface_index] old_downstream_interface = self.interface_state.get(new_inbound_interface_index, None)
# change type of interfaces # change type of interfaces
if self.inbound_interface_index is not None:
new_downstream_interface = TreeInterfaceDownstream(self, self.inbound_interface_index) new_downstream_interface = TreeInterfaceDownstream(self, self.inbound_interface_index)
self.interface_state[self.inbound_interface_index] = new_downstream_interface self.interface_state[self.inbound_interface_index] = new_downstream_interface
new_upstream_interface = None
if new_inbound_interface_index is not None:
new_upstream_interface = TreeInterfaceUpstream(self, new_inbound_interface_index) new_upstream_interface = TreeInterfaceUpstream(self, new_inbound_interface_index)
self.interface_state[new_inbound_interface_index] = new_upstream_interface self.interface_state[new_inbound_interface_index] = new_upstream_interface
self.inbound_interface_index = new_inbound_interface_index self.inbound_interface_index = new_inbound_interface_index
# remove old interfaces # remove old interfaces
if old_upstream_interface is not None:
old_upstream_interface.delete(change_type_interface=True) old_upstream_interface.delete(change_type_interface=True)
if old_downstream_interface is not None:
old_downstream_interface.delete(change_type_interface=True) old_downstream_interface.delete(change_type_interface=True)
# atualizar tabela de encaminhamento multicast # atualizar tabela de encaminhamento multicast
#self._was_olist_null = False #self._was_olist_null = False
self.change() self.change()
self.evaluate_olist_change() self.evaluate_olist_change()
if new_upstream_interface is not None:
new_upstream_interface.change_on_unicast_routing(interface_change=True) new_upstream_interface.change_on_unicast_routing(interface_change=True)
elif self.rpf_node != rpf_node: elif self.rpf_node != rpf_node:
self.rpf_node = rpf_node self.rpf_node = rpf_node
...@@ -294,7 +248,7 @@ class KernelEntry: ...@@ -294,7 +248,7 @@ class KernelEntry:
#check if removed interface is root interface #check if removed interface is root interface
if self.inbound_interface_index == index: if self.inbound_interface_index == index:
self.delete() self.delete()
else: elif index in self.interface_state:
self.interface_state.pop(index).delete() self.interface_state.pop(index).delete()
self.change() self.change()
self.evaluate_olist_change() self.evaluate_olist_change()
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