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