Example #1
0
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
Example #2
0
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)