コード例 #1
0
class Substrate:

    def __init__(self, path, filename):
        self.net = extract_network(path, filename)
        self.agent = None
        self.mapped_info = {}
        self.evaluation = Evaluation(self.net)
        self.no_solution = False

    def set_topology(self, graph):
        self.net = graph

    def handle(self, queue, algorithm, arg=0):

        # self.linkenv = LinkEnv(self.net)

        for req in queue:

            # the id of current request
            req_id = req.graph['id']

            if req.graph['type'] == 0:
                """a request which is newly arrived"""

                print("\nTry to map request%s: " % req_id)
                if self.mapping(req, algorithm, arg):
                    print("Success!")

            if req.graph['type'] == 1:
                """a request which is ready to leave"""

                if req_id in self.mapped_info.keys():
                    print("\nRelease the resources which are occupied by request%s" % req_id)
                    self.change_resource(req, 'release')

    def mapping(self, vnr, algorithm, arg):
        """two phrases:node mapping and link mapping"""

        self.evaluation.total_arrived += 1

        # mapping virtual nodes
        node_map = self.node_mapping(vnr, algorithm, arg)

        if len(node_map) == vnr.number_of_nodes():
            # mapping virtual links
            print("link mapping...")
            link_map = self.link_mapping(vnr, node_map, algorithm, arg)
            if len(link_map) == vnr.number_of_edges():
                self.mapped_info.update({vnr.graph['id']: (node_map, link_map)})
                self.change_resource(vnr, 'allocate')
                print("Success!")
                return True
            else:
                print("Failed to map all links!")
                return False
        else:
            print("Failed to map all nodes!")
            return False

    def node_mapping(self, vnr, algorithm, arg):
        """求解节点映射问题"""

        print("node mapping...")

        node_map = {}
        # 如果刚开始映射,那么需要对所选用的算法进行配置
        if algorithm != 'RLNL':
            if self.agent is None:
                self.agent = configure(self, algorithm, arg)
            node_map = self.agent.run(self, vnr)

        else:
            nodeenv = NodeEnv(self.net)
            nodeenv.set_vnr(vnr)
            nodep = nodepolicy(nodeenv.action_space.n, nodeenv.observation_space.shape)
            nodeobservation = nodeenv.reset()
            for vn_id in range(vnr.number_of_nodes()):
                sn_id = nodep.choose_max_action(nodeobservation, nodeenv.sub,
                                                vnr.nodes[vn_id]['cpu'],
                                                vnr.number_of_nodes())
                if sn_id == -1:
                    break
                else:
                    # 执行一次action,获取返回的四个数据
                    nodeobservation, _, done, info = nodeenv.step(sn_id)
                    node_map.update({vn_id: sn_id})

        # 使用指定的算法进行节点映射并得到节点映射集合

        # 返回节点映射集合
        return node_map

    def link_mapping(self, vnr, node_map, algorithm, arg):
        """求解链路映射问题"""

        link_map = {}

        if algorithm == 'grc':
            sub_copy1 = copy.deepcopy(self.net)
            for vLink in vnr.edges:
                vn_from, vn_to = vLink[0], vLink[1]
                resource = vnr[vn_from][vn_to]['bw']
                # 剪枝操作,先暂时将那些不满足当前待映射虚拟链路资源需求的底层链路删除
                sub_tmp = copy.deepcopy(sub_copy1)
                sub_edges = []
                for sLink in sub_tmp.edges:
                    sub_edges.append(sLink)
                for edge in sub_edges:
                    sn_from, sn_to = edge[0], edge[1]
                    if sub_tmp[sn_from][sn_to]['bw_remain'] <= resource:
                        sub_tmp.remove_edge(sn_from, sn_to)

                # 在剪枝后的底层网络上寻找一条可映射的最短路径
                sn_from, sn_to = node_map[vn_from], node_map[vn_to]
                if nx.has_path(sub_tmp, source=sn_from, target=sn_to):
                    path = k_shortest_path(sub_tmp, sn_from, sn_to, 1)[0]
                    link_map.update({vLink: path})

                    # 这里的资源分配是暂时的
                    start = path[0]
                    for end in path[1:]:
                        bw_tmp = sub_copy1[start][end]['bw_remain'] - resource
                        sub_copy1[start][end]['bw_remain'] = round(bw_tmp, 6)
                        start = end
                else:
                    break

            # 返回链路映射集合

            return link_map

        if algorithm == 'RLNL':
            if self.agent is None:
                self.agent = configure(self, algorithm, arg)
            # link_map = self.agent.run(self, vnr, node_map, self.linkenv)

            # linkenv = LinkEnv(self.net)
            # linkenv.set_vnr(vnr)
            # linkp = linkpolicy(linkenv.action_space.n, linkenv.observation_space.shape)
            # linkob = linkenv.reset()
            # for link in vnr.edges:
            #     linkenv.set_link(link)
            #     vn_from = link[0]
            #     vn_to = link[1]
            #     sn_from = node_map[vn_from]
            #     sn_to = node_map[vn_to]
            #     bw = vnr[vn_from][vn_to]['bw']
            #     if nx.has_path(linkenv.sub, sn_from, sn_to):
            #         linkaction = linkp.choose_max_action(linkob, linkenv.sub, bw, linkenv.linkpath, sn_from, sn_to)
            #         if linkaction == -1:
            #             break
            #         else:
            #             linkob, linkreward, linkdone, linkinfo = linkenv.step(linkaction)
            #             path = list(linkenv.linkpath[linkaction].values())[0]
            #             link_map.update({link: path})

        else:
            for vLink in vnr.edges:
                vn_from = vLink[0]
                vn_to = vLink[1]
                sn_from = node_map[vn_from]
                sn_to = node_map[vn_to]
                if nx.has_path(self.net, source=sn_from, target=sn_to):
                    for path in nx.all_shortest_paths(self.net, sn_from, sn_to):
                        if self.get_path_capacity(path) >= vnr[vn_from][vn_to]['bw']:
                            link_map.update({vLink: path})
                            break
                        else:
                            continue


        # 返回链路映射集合
        return link_map

    def change_resource(self, req, instruction):
        """分配或释放节点和链路资源"""

        # 读取该虚拟网络请求的映射信息
        req_id = req.graph['id']
        node_map = self.mapped_info[req_id][0]
        link_map = self.mapped_info[req_id][1]

        factor = -1
        if instruction == 'release':
            factor = 1

        # 分配或释放节点资源
        for v_id, s_id in node_map.items():
            self.net.nodes[s_id]['cpu_remain'] += factor * req.nodes[v_id]['cpu']

        # 分配或释放链路资源
        for vl, path in link_map.items():
            link_resource = req[vl[0]][vl[1]]['bw']
            start = path[0]
            for end in path[1:]:
                self.net[start][end]['bw_remain'] += factor * link_resource
                start = end

        if instruction == 'allocate':
            # 增加实验结果
            self.evaluation.add(req, link_map)

        if instruction == 'release':
            # 移除相应的映射信息
            self.mapped_info.pop(req_id)

    def get_path_capacity(self, path):
        """找到一条路径中带宽资源最小的链路并返回其带宽资源值"""

        bandwidth = 1000
        head = path[0]
        for tail in path[1:]:
            if self.net[head][tail]['bw_remain'] <= bandwidth:
                bandwidth = self.net[head][tail]['bw_remain']
            head = tail
        return bandwidth