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 = ShortestPath(self.igp_graph) # process input forwarding DAGs, one at the time for dest, dag in requirement_dags.iteritems(): log.info('Solving DAG for dest %s', dest) self.dest, self.dag = dest, dag log.debug('Checking dest in dag') ssu.add_dest_to_graph(dest, dag) log.debug('Checking dest in igp graph') ssu.add_dest_to_graph(dest, topo, edges_src=dag.predecessors, spt=self.igp_paths, metric=self.new_edge_metric) ssu.complete_dag(dag, topo, dest, self.igp_paths, skip=self.reqs.keys()) # Add temporarily the destination to the igp graph and/or req dags if not ssu.solvable(dag, topo): log.warning('Skipping requirement for dest: %s', dest) continue for node in dag: nhs = self.nhs_for(node, dest, dag) if not nhs: continue for req_nh in nhs: log.debug('Placing a fake node for %s->%s', node, req_nh) for i in xrange(get_edge_multiplicity(dag, node, req_nh)): self.fake_ospf_lsas.append( ssu.LSA(node=node, nh=req_nh, cost=(-1 - i), dest=dest)) # Check whether we need to include one more fake node to handle # the case where we create a new route from scratch. for p in dag.predecessors_iter(dest): if not is_fake(topo, p, dest): continue log.debug( '%s is a terminal node towards %s but had no prior ' 'route to it! Adding a synthetic route', p, dest) self.fake_ospf_lsas.append( ssu.GlobalLie(dest, self.new_edge_metric, p)) 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: IGPGraph :type requirements: { dest: IGPGraph } :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 = ShortestPath(graph) lsa = [] for dest, dag in requirements.iteritems(): self.dest, self.dag = dest, dag self.ecmp.clear() log.info('Evaluating requirement %s', dest) log.info('Ensuring the consistency of the DAG') self.check_dest() ssu.complete_dag(self.dag, self.g, self.dest, self._p, skip=self.reqs.keys()) 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._p.default_path(n, self.dest)]) if not ssu.solvable(self.dag, self.g): 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.debug('Fake node bounds: %s', [n for _, n in self.nodes() if n.has_any_fake_node()]) log.info('Reducing the augmented topology') self.merge_fake_nodes() self.remove_redundant_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
def solve(self, graph, requirements): """Compute the augmented topology for a given graph and a set of requirements. :type graph: IGPGraph :type requirements: { dest: IGPGraph } :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 = ShortestPath(graph) lsa = [] for dest, dag in requirements.iteritems(): self.dest, self.dag = dest, dag self.ecmp.clear() log.info('Evaluating requirement %s', dest) log.info('Ensuring the consistency of the DAG') self.check_dest() ssu.complete_dag(self.dag, self.g, self.dest, self._p, skip=self.reqs.keys()) 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._p.default_path(n, self.dest)]) if not ssu.solvable(self.dag, self.g): 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.debug('Fake node bounds: %s', [n for _, n in self.nodes() if n.has_any_fake_node()]) log.info('Reducing the augmented topology') self.merge_fake_nodes() self.remove_redundant_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
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 = ShortestPath(self.igp_graph) # process input forwarding DAGs, one at the time for dest, dag in requirement_dags.iteritems(): log.info('Solving DAG for dest %s', dest) self.dest, self.dag = dest, dag log.debug('Checking dest in dag') ssu.add_dest_to_graph(dest, dag) log.debug('Checking dest in igp graph') ssu.add_dest_to_graph(dest, topo, edges_src=dag.predecessors, spt=self.igp_paths, metric=self.new_edge_metric) ssu.complete_dag(dag, topo, dest, self.igp_paths, skip=self.reqs.keys()) # Add temporarily the destination to the igp graph and/or req dags if not ssu.solvable(dag, topo): log.warning('Skipping requirement for dest: %s', dest) continue for node in dag: nhs = self.nhs_for(node, dest, dag) if not nhs: continue for req_nh in nhs: log.debug('Placing a fake node for %s->%s', node, req_nh) for i in xrange(get_edge_multiplicity(dag, node, req_nh)): self.fake_ospf_lsas.append(ssu.LSA(node=node, nh=req_nh, cost=(-1 - i), dest=dest)) # Check whether we need to include one more fake node to handle # the case where we create a new route from scratch. for p in dag.predecessors_iter(dest): if not is_fake(topo, p, dest): continue log.debug('%s is a terminal node towards %s but had no prior ' 'route to it! Adding a synthetic route', p, dest) self.fake_ospf_lsas.append( ssu.GlobalLie(dest, self.new_edge_metric, p)) return self.fake_ospf_lsas
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 = ShortestPath(self.igp_graph) log.debug('Original SPT: %s', self.igp_paths) # process input forwarding DAGs, one at the time for dest, dag in requirement_dags.iteritems(): log.debug('Solving DAG for dest %s', dest) self.dest, self.dag = dest, dag log.debug('Checking dest in dag') ssu.add_dest_to_graph(dest, dag) log.debug('Checking dest in igp graph') ssu.add_dest_to_graph(dest, topo, edges_src=dag.predecessors, spt=self.igp_paths, metric=self.new_edge_metric) ssu.complete_dag(dag, topo, dest, self.igp_paths, skip=self.reqs.keys()) # Add temporarily the destination to the igp graph and/or req dags if not ssu.solvable(dag, topo): log.warning('Skipping requirement for dest: %s', dest) 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): log.debug('%s does not require a fake node (%s - %s)', node, nhs, original_nhs) continue for req_nh in nhs: log.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, 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 = ShortestPath(self.igp_graph) log.debug('Original SPT: %s', self.igp_paths) # process input forwarding DAGs, one at the time for dest, dag in requirement_dags.iteritems(): log.debug('Solving DAG for dest %s', dest) self.dest, self.dag = dest, dag log.debug('Checking dest in dag') ssu.add_dest_to_graph(dest, dag) log.debug('Checking dest in igp graph') ssu.add_dest_to_graph(dest, topo, edges_src=dag.predecessors, spt=self.igp_paths, metric=self.new_edge_metric) ssu.complete_dag(dag, topo, dest, self.igp_paths, skip=self.reqs.keys()) # Add temporarily the destination to the igp graph and/or req dags if not ssu.solvable(dag, topo): log.warning('Skipping requirement for dest: %s', dest) 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): log.debug('%s does not require a fake node (%s - %s)', node, nhs, original_nhs) continue for req_nh in nhs: log.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