def read_prev_placement(networkx, templates): # create empty overlays for all templates prev_embedding = {} # dict: template -> overlay for t in templates: prev_embedding[t] = Overlay(t, [], []) # only read and recreate placement (not edges or flows) for v in networkx.nodes.data(): node_id = v[0] node_attr = v[1] for vnf in node_attr['available_sf']: # 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); here, "vnf" is the vnf's name component = get_component(t, vnf) if component is not None: # 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, node_id, src_flows=[])) else: prev_embedding[t].instances.append( Instance(component, node_id)) break return prev_embedding
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 solve(arg_nodes, arg_links, templates, prev_overlays, sources, fixed, arg_shortest_paths, tabu=set()): # print("Previous overlays:") # for ol in prev_overlays.values(): # ol.print() # tabu_string = "" # for i in tabu: # tabu_string += "({},{}) ".format(i[0], i[1]) # print("Tabu list: {}".format(tabu_string)) # write global variables global nodes, links, shortest_paths, overlays nodes = arg_nodes links = arg_links shortest_paths = arg_shortest_paths # keep previous overlays of templates that still exist overlays = {t: ol for t, ol in prev_overlays.items() if t in templates} # create empty overlays for new templates for t in templates: if t not in overlays.keys(): overlays[t] = Overlay(t, [], []) # print("Created empty overlay for new template {}".format(t)) logger.info("Created empty overlay for new template {}".format(t)) # remove all instances of fixed components => curr fixed instances added again later; prev fixed instances removed fixed_components = {f.component for f in fixed} fixed_instances = { i for ol in overlays.values() for i in ol.instances if i.component in fixed_components } # print("Remove any existing fixed instances:", *fixed_instances, sep=" ") for i in fixed_instances: remove_instance(i) # embed templates sequentially in given order for t in templates: # print("\n-Embedding template: {}-".format(t)) logger.info("-Embedding template: {}-".format(t)) own_sources = [src for src in sources if src.component in t.components] update_sources(overlays[t], own_sources) # add fixed instances that match template t's components for f in fixed: if f.component in t.components: fixed_instance = Instance(f.component, f.location, fixed=True) if fixed_instance not in overlays[t].instances: overlays[t].instances.append(fixed_instance) # print("Added fixed instance of {} at {}".format(f.component, f.location)) logger.info("Added fixed instance of {} at {}".format( f.component, f.location)) # iterate over all instances in topological order; start in forward direction then switch to backward i = 0 direction = "forward" while i < len(overlays[t].topological_order()): instance = overlays[t].topological_order()[i] # #print("Topological order:", *overlays[t].topological_order(), sep=" ") # remove unused instances (except fixed instances) if not instance.fixed: if not instance.used(direction, overlays[t]): # print("Removed unused instance {} from overlay of {}".format(instance, t)) logger.info( "Removed unused instance {} from overlay of {}".format( instance, t)) remove_instance(instance, overlays[t]) continue # switch direction at the first instance of an end component (bc outgoing not ingoing direction considered) if instance.component.end: direction = "backward" # get outgoing flows (and their dr) for each output out_flows = instance.out_flows(direction) for k in range(len(out_flows)): arc = out_arc(t, instance.component, k, direction) # when a component is adapted for reuse, it has separate outputs for the arcs of different templates if arc is None: # for output k, this template has no arc => skip to next output # print("{}'s outgoing arc at output {} in {} direction belongs to a different template. # The output is skipped".format(instance, k, direction)) logger.debug( "{}'s outgoing arc at output {} in {} direction belongs to a different template. " "The output is skipped".format(instance, k, direction)) continue update_flow_mapping(overlays[t], instance, arc, out_flows[k], tabu) # print("Updated the flow mapping along arc {} at {}\n".format(arc, instance)) logger.info( "Updated the flow mapping along arc {} at {}\n".format( arc, instance)) i += 1 # print() if overlays[t].empty(): del overlays[t] # print("Deleted empty overlay of {}".format(t)) logger.info("Deleted empty overlay of {}".format(t)) # else: # overlays[t].print() # print("Topological order:", *overlays[t].topological_order(), sep=" ") # print() return overlays