def map_flows2stateful(overlay, start_instance, arc, out_flows): # remove any existing mappings of flows to edges along the arc for e in start_instance.edges_out.values(): if e.arc == arc: e.flows = [] # add currently outgoing flows to edges back to stateful instances (create edges if necessary) for f in out_flows: dest_inst = f.passed_stateful[arc.dest] if dest_inst in start_instance.edges_out.keys(): new_edge = False edge = start_instance.edges_out[dest_inst] else: new_edge = True edge = Edge(arc, start_instance, dest_inst) edge.paths.append(shortest_paths[(start_instance.location, dest_inst.location)][0]) overlay.edges.append(edge) f.dr[edge] = out_flows[f] edge.flows.append(f) # print("\tMapped flow {} (dr {}) to edge {} (new: {}) back to same stateful instance".format(f, out_flows[f], # edge, new_edge)) logger.info( "\tMapped flow {} (dr {}) to edge {} (new: {}) back to same stateful instance" .format(f, out_flows[f], edge, new_edge))
def read_prev_embedding(file, templates, nodes, links): # create shortest paths shortest_paths = sp.all_pairs_shortest_paths(nodes, links) # create empty overlays for all templates prev_embedding = {} # dict: template -> overlay for t in templates: prev_embedding[t] = Overlay(t, [], []) with open(file, "r") as f: yaml_file = yaml.load(f, yaml.SafeLoader) # read and create VNF instances of previous embedding for vnf in yaml_file["placement"]["vnfs"]: # find component that matches the VNF name (in any of the templates) for t in templates: # use first matching component (assuming it's only in one template) if vnf["name"] in [c.name for c in t.components]: component = list(filter(lambda x: x.name == vnf["name"], t.components))[0] # add new instance to overlay of corresponding template (source components need src_flows being set) if component.source: prev_embedding[t].instances.append(Instance(component, vnf["node"], src_flows=[])) else: prev_embedding[t].instances.append(Instance(component, vnf["node"])) break # TODO: read and create flows. otherwise, adding edges really doesn't make a difference in the heuristic # read and create edges of previous embedding for edge in yaml_file["placement"]["vlinks"]: instances = [i for ol in prev_embedding.values() for i in ol.instances] # try to get source and dest instance from list of instances try: source = list(filter(lambda x: x.component.name == edge["src_vnf"] and x.location == edge["src_node"], instances))[0] dest = list(filter(lambda x: x.component.name == edge["dest_vnf"] and x.location == edge["dest_node"], instances))[0] # if the vnfs don't exist in prev_embedding (eg, through incorrect input), ignore the edge except IndexError: # print("No matching VNFs in prev_embedding for edge from {} to {}. # Ignoring the edge.".format(source, dest)) continue # skip and continue with next edge # get arc from templates by matching against source and dest components for t in templates: if source.component in t.components and dest.component in t.components: # assume t has an arc source->dest if both components are in t arc = list(filter(lambda x: x.source == source.component and x.dest == dest.component, t.arcs))[0] # add new edge to overlay of corresponding template edge = Edge(arc, source, dest) prev_embedding[t].edges.append(edge) edge.paths.append(shortest_paths[(source.location, dest.location)][0]) return prev_embedding
def map_flow2edge(overlay, start_instance, arc, flow, flow_dr, tabu): # determine if the instances of the destination component are fixed => if so, cannot place new instances fixed = False for i in overlay.instances: if i.component == arc.dest and i.fixed: fixed = True break best_node = find_best_node(overlay, start_instance.location, arc, flow_dr, fixed, tabu) if best_node is None: logger.error(f"No suitable node found. Cannot compute placement.") return False # if the instance at best node already exists (e.g., from forward dir), just connect to it, else create anew # look for existing instance instance_exists = False for i in overlay.instances: if i.component == arc.dest and i.location == best_node: instance_exists = True dest_instance = i break # create new instance if none exists in the overlay if not instance_exists: dest_instance = Instance(arc.dest, best_node) overlay.instances.append(dest_instance) # print("\tAdded new instance {} at best node {} (may exist in other overlays)".format(dest_instance, # best_node)) logger.info( "\tAdded new instance {} at best node {} (may exist in other overlays)" .format(dest_instance, best_node)) # check if edge to dest_instance already exists edge_exists = False if instance_exists: if dest_instance in start_instance.edges_out.keys(): edge_exists = True edge = start_instance.edges_out[dest_instance] # if it doesn't exist, create a new edge and assign a path (shortest path) if not edge_exists: edge = Edge(arc, start_instance, dest_instance) overlay.edges.append(edge) edge.paths.append(shortest_paths[(start_instance.location, dest_instance.location)][0]) # map flow to edge flow.dr[edge] = flow_dr edge.flows.append(flow) # print("\tMapped flow {} (dr {}) to edge {} (new: {})".format(flow, flow_dr, edge, not edge_exists)) logger.info("\tMapped flow {} (dr {}) to edge {} (new: {})".format( flow, flow_dr, edge, not edge_exists)) return True
def __deepcopy__(self, memodict={}): new_overlay = Overlay(self.template, [], []) # empty overlay instance_dict = { } # dict of old to new instances; for easy access when adding the edges flow_dict = {} # same for old to new flows # add new instances with same attributes (component, etc) but without edges_in/out for i in self.instances: # copy src_flows new_src_flows = None if i.src_flows: new_src_flows = [] for f in i.src_flows: new_flow = Flow(f.id, f.src_dr) flow_dict[f] = new_flow new_src_flows.append(new_flow) # copy instances new_instance = Instance(i.component, i.location, new_src_flows, i.fixed) new_overlay.instances.append(new_instance) instance_dict[i] = new_instance # add new edges in topological order => sets edges_in/out etc automatically for e in self.topological_order(True): # source/dest from new_overlay's instances using the instance_dict new_source = instance_dict[e.source] new_dest = instance_dict[e.dest] # create new edge with references to the new instances and manually set the remaining attributes new_edge = Edge(e.arc, new_source, new_dest) new_edge.direction = e.direction new_edge.paths = copy.deepcopy( e.paths, memodict) # deepcopy for copying list of lists # copy and update flows for f in e.flows: new_flow = flow_dict[f] new_edge.flows.append(new_flow) new_flow.dr[new_edge] = f.dr[e] if new_edge.source.component.stateful: new_flow.passed_stateful[ new_edge.source.component] = new_edge.source elif new_edge.dest.component.stateful: new_flow.passed_stateful[ new_edge.dest.component] = new_edge.dest new_overlay.edges.append(new_edge) return new_overlay