diff --git a/birdvisu/__init__.py b/birdvisu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/birdvisu/maps.py b/birdvisu/maps.py new file mode 100644 index 0000000..269af11 --- /dev/null +++ b/birdvisu/maps.py @@ -0,0 +1,85 @@ +from birdvisu.ospffile import load +import re + +class Topology: + """Basically a graph""" + + def __init__(self): + self.routers = [] # Tuples like in ospffile for router section + self.networks = [] # Ditto, but the key is the address, not the ad-hoc string from bird + self.network_addrs = {} # Keeps mapping from network to address + self.links = [] # Tuples (router, network_addr, cost) + # FIXME: we are ugly, so everything are strings and I don't care as of now. + + def add_area(self, dirtuple): + # FIXME: Do not use BIRD's strings, create an abstraction above them. + _area, topo = dirtuple # Ignoring the area + for obj in topo: + directive, details = obj + if directive.startswith('router'): + self.routers.append(obj) + elif directive.startswith('network'): + net_addr = None + for d, _ in details: + if d.startswith('address'): + net_addr = d + break + assert net_addr is not None + fixed_network = (net_addr, details + [directive]) + self.networks.append(fixed_network) + self.network_addrs[directive] = net_addr + + # Fix the topology: find other networks (stubnets, external, ...) and links: + for r, rd in self.routers: + for n, nd in rd: + if n.startswith(('network', 'stubnet', 'external')): + net_id = re.match(r'((network|stubnet|external) [^ ]+)', n).group(1) + if n.startswith(('stubnet', 'external')): + self.networks.append((net_id, [])) + # Add dummy mapping + self.network_addrs[net_id] = net_id + metric = int(re.search(r'metric ([0-9]+)', n).group(1)) + net_addr = self.network_addrs[net_id] + self.links.append((r, net_addr, metric)) + + @classmethod + def from_ospffile(cls, f): + # FIXME: We should create own classes from the OSPF file as soon as + # possible to avoid changing whole codebase when BIRD's format changes. + result = cls() + parsed = load(f) + for directive, details in parsed: + if directive.startswith('area'): + result.add_area((directive, details)) + return result + + +class TopologyDifference: + def __init__(self, actual, reference): + self.actual = actual + self.reference = reference + + def compare(self): + # FIXME: This also relies on BIRD's current format. + just_ident = lambda x: x[0] + act_routers = set(map(just_ident, self.actual.routers)) + ref_routers = set(map(just_ident, self.reference.routers)) + act_networks = set(map(just_ident, self.actual.networks)) + ref_networks = set(map(just_ident, self.reference.networks)) + act_links = set(self.actual.links) + ref_links = set(self.reference.links) + + # *_missing: in reference, not in actual network. + # *_extra: in actual network, not in reference. + # *_discrepancies: different settings (currently only metrics) + self.routers_missing = ref_routers - act_routers + self.routers_extra = act_routers - ref_routers + self.networks_missing = ref_networks - act_networks + self.networks_extra = act_networks - ref_networks + + # FIXME: be more clever. Discrepancy is not missing and extra… + self.links_missing = ref_links - act_links + self.links_extra = act_links - ref_links + self.links_discrepancies = act_links ^ ref_links + +