def sidr_reject_by_peer(SDXes, sdxi): """ Reject policy by checking peers """ policy = SDXes[sdxi]['policy'] reject_cnt = 0 tp_reject_cnt = 0 peer_policy = [SDXes[p]['policy'] for p in SDXes[sdxi]['peers']] merge_peer_policy = PyTricia() for p_policy in peer_policy: for p in p_policy.keys(): if p not in merge_peer_policy.keys(): merge_peer_policy[p] = {} merge_peer_policy[p].update(p_policy[p]) rejected_prefixes = set(policy.keys()).intersection( merge_peer_policy.keys()) fp_rejected_policy = PyTricia() for prefix in rejected_prefixes: deflect_port = {p for p in policy[prefix].keys()} peer_deflect_port = {p for p in merge_peer_policy[prefix].keys()} reject_cnt += len(deflect_port) tp_reject_cnt += len(deflect_port.intersection(peer_deflect_port)) fp_rejected_policy[prefix] = { p: 1 for p in deflect_port if p not in peer_deflect_port } return reject_cnt, tp_reject_cnt, fp_rejected_policy
class Topology(NullTopology): def __init__(self, graph, nodes, links, traffic_modulators): self.logger = get_logger('fslib.config') self.__graph = graph self.nodes = nodes self.links = links self.traffic_modulators = traffic_modulators self.routing = {} self.ipdestlpm = None self.owdhash = {} self.__configure_routing() for a,b,d in self.graph.edges(data=True): if 'reliability' in d: self.__configure_edge_reliability(a,b,d['reliability'],d) @property def graph(self): return self.__graph def remove_node(self, name): self.__graph.remove_node(name) for n in self.graph: self.routing[n] = single_source_dijkstra_path(self.graph, n) def __configure_edge_reliability(self, a, b, relistr, edict): relidict = fsutil.mkdict(relistr) ttf = ttr = None for k,v in relidict.iteritems(): if k == 'failureafter': ttf = eval(v) if isinstance(ttf, (int, float)): ttf = modulation_generator([ttf]) elif k == 'downfor': ttr = eval(v) if isinstance(ttr, (int, float)): ttr = modulation_generator([ttr]) elif k == 'mttf': ttf = eval(v) elif k == 'mttr': ttr = eval(v) if ttf or ttr: assert(ttf and ttr) xttf = next(ttf) fscore().after(xttf, 'link-failure-'+a+'-'+b, self.__linkdown, a, b, edict, ttf, ttr) def __configure_routing(self): for n in self.graph: self.routing[n] = single_source_dijkstra_path(self.graph, n) self.ipdestlpm = PyTricia() for n,d in self.graph.nodes_iter(data=True): dlist = d.get('ipdests','').split() for destipstr in dlist: ipnet = ipaddr.IPNetwork(destipstr) xnode = {} self.ipdestlpm[str(ipnet)] = xnode if 'dests' in xnode: xnode['dests'].append(n) else: xnode['net'] = ipnet xnode['dests'] = [ n ] # install static forwarding table entries to each node # FIXME: there's a problematic bit of code here that triggers # pytricia-related (iterator) core dump for nodename,nodeobj in self.nodes.iteritems(): if isinstance(nodeobj, Router): for prefix in self.ipdestlpm.keys(): lpmnode = self.ipdestlpm.get(prefix) if nodename not in lpmnode['dests']: routes = self.routing[nodename] for d in lpmnode['dests']: try: path = routes[d] except KeyError: self.logger.warn("No route from {} to {}".format(nodename, d)) continue nexthop = path[1] nodeobj.addForwardingEntry(prefix, nexthop) self.owdhash = {} for a in self.graph: for b in self.graph: key = a + ':' + b rlist = [ a ] while rlist[-1] != b: nh = self.nexthop(rlist[-1], b) if not nh: self.logger.debug('No route from %s to %s (in owd; ignoring)' % (a,b)) return None rlist.append(nh) owd = 0.0 for i in xrange(len(rlist)-1): owd += self.delay(rlist[i],rlist[i+1]) self.owdhash[key] = owd def node(self, nname): '''get the node object corresponding to a name ''' return self.nodes[nname] def start(self): for tm in self.traffic_modulators: tm.start() for nname,n in self.nodes.iteritems(): n.start() def stop(self): for nname,n in self.nodes.iteritems(): n.stop() def __linkdown(self, a, b, edict, ttf, ttr): '''kill a link & recompute routing ''' self.logger.info('Link failed %s - %s' % (a,b)) self.graph.remove_edge(a,b) self.__configure_routing() uptime = None try: uptime = next(ttr) except: self.logger.info('Link %s-%s permanently taken down (no recovery time remains in generator)' % (a, b)) return else: fscore().after(uptime, 'link-recovery-'+a+'-'+b, self.__linkup, a, b, edict, ttf, ttr) def __linkup(self, a, b, edict, ttf, ttr): '''revive a link & recompute routing ''' self.logger.info('Link recovered %s - %s' % (a,b)) self.graph.add_edge(a,b,weight=edict.get('weight',1),delay=edict.get('delay',0),capacity=edict.get('capacity',1000000)) self.__configure_routing() downtime = None try: downtime = next(ttf) except: self.logger.info('Link %s-%s permanently going into service (no failure time remains in generator)' % (a, b)) return else: fscore().after(downtime, 'link-failure-'+a+'-'+b, self.__linkdown, a, b, edict, ttf, ttr) def owd(self, a, b): '''get the raw one-way delay between a and b ''' key = a + ':' + b rv = None if key in self.owdhash: rv = self.owdhash[key] return rv def delay(self, a, b): '''get the link delay between a and b ''' d = self.graph.edge[a][b] if d is not None: return d.values()[0]['delay'] return None def capacity(self, a, b): '''get the bandwidth between a and b ''' d = self.graph.edge[a][b] if d is not None: return d.values()[0]['capacity'] return None def nexthop(self, node, dest): ''' return the next hop node for a given destination. node: current node dest: dest node name returns: next hop node name ''' try: nlist = self.routing[node][dest] except: return None if len(nlist) == 1: return nlist[0] return nlist[1] def destnode(self, node, dest): ''' return the destination node corresponding to a dest ip. node: current node dest: ipdest returns: destination node name ''' # radix trie lpm lookup for destination IP prefix xnode = self.ipdestlpm.get(dest, None) if xnode: dlist = xnode['dests'] best = None if len(dlist) > 1: # in the case that there are multiple egress nodes # for the same IP destination, choose the closest egress best = None bestw = 10e6 for d in dlist: w = single_source_dijkstra_path_length(self.graph, node, d) if w < bestw: bestw = w best = d else: best = dlist[0] return best else: raise InvalidRoutingConfiguration('No route for ' + dest)