def solve(self, topo, requirement_dags): # a list of tuples with info on the node to be attracted, # the forwarding address, the cost to be set in the fake LSA, # and the respective destinations self.fake_ospf_lsas = [] self.reqs = requirement_dags self.igp_graph = topo self.igp_paths = ssu.all_shortest_paths(self.igp_graph) # process input forwarding DAGs, one at the time for dest, dag in requirement_dags.iteritems(): logger.debug('Solving DAG for dest %s', dest) self.dest, self.dag = dest, dag self.add_dest_to_graphs(dest, dag) if dest not in topo: sinks = dag.predecessors(dest) for s in sinks: logger.info('Adding edge (%s, %s) in the graph', s, self.dest) topo.add_edge(s, dest, weight=self.new_edge_weight) for n in topo.nodes_iter(): if n == dest: # dest is a path in itself self.igp_paths[n] = ([[n]], 0) continue paths = [] cost = sys.maxint for s in sinks: if s not in self.igp_paths[n][0]: # no path to sink continue c = self.igp_paths[n][1][s] p = self.igp_paths[n][0][s] if c < cost: # new spt paths = list(ssu.extend_paths_list(p, dest)) cost = c if c == cost: # ecmp paths.extend(ssu.extend_paths_list(p, dest)) if paths: _t = self.igp_paths[n] _t[0][dest] = paths _t[1][dest] = cost self.complete_dag() # Add temporarily the destination to the igp graph and/or req dags if not self.solvable(dest, dag): continue for node in nx.topological_sort(dag, reverse=True)[1:]: nhs, original_nhs = self.nhs_for(node, dag, dest) if not self.require_fake_node(nhs, original_nhs): logger.debug('%s does not require a fake node (%s - %s)', node, nhs, original_nhs) continue for req_nh in nhs: logger.debug('Placing a fake node for nh %s', req_nh) self.fake_ospf_lsas.append(ssu.LSA(node=node, nh=req_nh, cost=-1, dest=dest)) return self.fake_ospf_lsas
def solve(self, graph, requirements): """Compute the augmented topology for a given graph and a set of requirements. :type graph: DiGraph :type requirements: { dest: DiGraph } :param requirements: the set of requirement DAG on a per dest. basis :return: list of fake LSAs""" self.reqs = requirements log.info('Preparing IGP graph') self.g = prepare_graph(graph, requirements) log.info('Computing SPT') self._p = ssu.all_shortest_paths(self.g) lsa = [] for dest, dag in requirements.iteritems(): self.ecmp.clear() log.info('Evaluating requirement %s', dest) self.dest = dest self.dag = dag log.info('Ensuring the consistency of the DAG') self.check_dest() self.complete_dag() log.info('Computing original and required next-hop sets') for n, node in self.nodes(): node.forced_nhs = set(self.dag.successors(n)) node.original_nhs = set([p[1] for p in self.path(n, self.dest)]) if not self.check_consistency(): log.warning('Consistency check failed, skipping %s', dest) continue log.info('Placing initial fake nodes') self.place_fake_nodes() log.info('Initializing fake nodes') self.initialize_fake_nodes() log.info('Propagating initial lower bounds') self.propagate_lb() log.info('Reducing the augmented topology') self.merge_fake_nodes() log.info('Generating LSAs') lsas = self.create_fake_lsa() log.info('Solved the DAG for destination %s with LSA set: %s', self.dest, lsas) lsa.extend(lsas) return lsa