A3CLB的实现

主函数

main.py

# 导入必要的库
import random

from mininet.link import TCLink
from mininet.net import Mininet
from mininet.node import CPULimitedHost
from mininet.node import RemoteController
from mininet.util import dumpNodeConnections
import F5
import state
import torch
import torch.nn as nn
import torch.optim as optim
import torch.multiprocessing as mp
import gym

# 定义环境和模型
class Environment:
    def __init__(self, topology):
        self.topology = topology
        self.controller = RemoteController()
        self.net = Mininet(topo=self.topology, controller=self.controller, host=CPULimitedHost, link=TCLink)
        self.net.start()
        self.mapping_relation = {}
        for link in self.net.links:
            self.mapping_relation[link.intf1.name] = link.intf2.name

        self.current_state = 0.0

        # for switch in net.switches:
        #     # 获取交换机的名称
        #     switch_name = switch.name
        #
        #     # 获取交换机与之相连的链路的接口名称
        #     for intf in switch.intfList():
        #         intf_name = intf.namenet
        #
        #         # 获取链路的带宽利用率
        #         bandwidth_utilization = get_bandwidth_utilization(switch_name, intf_name)
        #         link_bw.append(bandwidth_utilization)
        #         print(f"交换机 {switch_name} 的链路 {intf_name} 的带宽利用率为:{bandwidth_utilization}")
        #     state.append(link_bw)
        # print(state)
        # 创建A3C算法Agent


    def reset(self):
        # 初始化环境状态
        # 初始化与智能体相连的链路的带宽利用率
        # link_bandwidth_utilization = [random.uniform(0, 1) for _ in range(4)]
        # (负载均衡程度)表示状态
        self.current_state = state.init(self.net)
        return self.current_state

    def reward(self,state):
        # 以交换机上各条链路的带宽利用率的方差的倒数作为奖励值
        # 以字典保存奖励值
        switch_reward = {}
        for switch_name,switch_state in state.items():
            sum_bw = sum(switch_state.values())  # 求交换机上各条链路的带宽利用率的和
            ave_bw = sum_bw / len(switch_state)  # 求带宽利用率的平均值
            sum = 0
            for bw in state.values():
                sum += (bw - ave_bw) ** 2
            variance_bw = sum / len(switch_state)  # 求带宽利用率的方差
            recirocal = 1 / (variance_bw + 1)  # 求方差的倒数
            switch_reward[switch_name] = recirocal
        return switch_reward
    def step(self, action):
        # 执行动作并返回新的状态、奖励和是否完成的标志
        new_state = self.reset()
        reward = self.reward(new_state)
        done = 1
        return new_state, reward, done


class Model:
    def __init__(self, state_dim, action_dim):
        super(A3CNet, self).__init__()
        # 定义网络结构,例如使用多层全连接层
        self.fc1 = nn.Linear(state_dim, 64)  # 输入层到隐藏层的全连接层,输入维度为state_dim,隐藏层维度为64
        self.fc2 = nn.Linear(64, action_dim)  # 隐藏层到输出层的全连接层,隐藏层维度为64,输出维度为action_dim

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用ReLU激活函数处理输入层到隐藏层的输出
        x = self.fc2(x)  # 输出隐藏层到输出层的结果,不使用激活函数
        return x

# 定义A3C算法的Actor和Critic模型

# 定义A3C算法的Agent


def create_flow_entry(in_port, out_port):
    # 生成一个简单的流表项字典
    flow_entry = {
        "match": {
            "in_port": in_port
        },
        "actions": [
            {
                "type": "OUTPUT",
                "port": out_port
            }
        ]
    }
    return flow_entry


class Agent:
    def __init__(self, state_shape, action_shape):
        self.state_shape = state_shape
        self.action_shape = action_shape
        self.actor = Model(state_shape, action_shape)
        self.critic = Model(state_shape, 1)

    def choose_action(self, state):
        # 基于当前状态选择动作
        # 选择带宽利用率最低的链路

        for switch, switch_bw in state.items():
            min_utilization = float('inf')  # 初始化为无穷大
            chosen_link = None

            for interface,utilization in switch_bw.items():     # 遍历交换机的状态
                if utilization < min_utilization:  # 获取最小利用率
                    min_utilization = utilization
                    chosen_link = (switch, interface)

            # 下发流表项,将流量转发到选择的链路
            if chosen_link:
                switch, interface = chosen_link
                # 下发流表项,将流量从某个输入端口(interface)转发到某个输出端口(out_port)
                out_port = env.mapping_relation[interface]
                flow_entry = create_flow_entry(in_port=interface, out_port=out_port)
                env.controller.install_flow_entry(flow_entry)

        # return action

    def train(self, state, action, reward, next_state, done):
        # 训练Actor和Critic模型
        ...


# 定义训练过程
def train_a3c(env, agent, num_episodes):
    for episode in range(num_episodes):
        state = env.reset()  # 初始化环境状态,获得当前状态
        done = False  # 完成标志
        total_reward = 0  # 奖励总值

        while not done:
            # 选择动作并执行
            action = agent.choose_action(state,env.controller)
            next_state, reward, done = env.step(action)
            total_reward += reward

            # 训练智能体Agent
            agent.train(state, action, reward, next_state, done)

            state = next_state

        # 输出每个episode的总奖励
        print(f"Episode {episode}, Total Reward: {total_reward}")


# 主函数
if __name__ == "__main__":
    # 创建四叉胖树拓扑结构网络,并初始化环境
    topology = F5.MyTopo()
    # net = Mininet(topo=topology, host=CPULimitedHost, link=TCLink)
    # topology = F5.MyTopo()  # 创建四叉胖树拓扑结构网络
    env = Environment(topology) # 初始化网络环境


    state_shape = 2  # 确定状态空间的形状,与交换机相连的链路数量相对应
    action_shape = 2  # 确定动作空间的形状
    agent = Agent(state_shape, action_shape)

    # 训练Agent
    num_episodes = 10  # 确定训练的轮次
    train_a3c(env, agent, num_episodes)
    # print(env.mapping_relation)

状态文件

state.py

import re
import subprocess
import time

from cv2 import setLogLevel
from mininet.net import Mininet
from mininet.link import Link, TCLink
from mininet.node import CPULimitedHost

import F5


def get_bandwidth_utilization(net,switch, interface):
    # 假设这里使用iperf或其他方法来获取链路的带宽利用率
    # 返回链路的带宽利用率
    # 运行iperf客户端并与目标服务器建立连接
    server_cmd = f"iperf -s > iperf_server.txt 2>&1 &"
    server_IP = net[switch].IP()
    cmd = f"iperf -c {server_IP} -t 5"  # 设置测试时间为5秒
    # 启动iperf服务器
    subprocess.Popen(server_cmd, shell=True)
    time.sleep(1)
    output = subprocess.check_output(cmd, shell=True, text=True)

    # 解析iperf输出,获取传输速率(单位为Mbits/sec)
    m = re.search(r'\d+\.\d+\s+Gbits/sec', output)
    if m:
        transfer_rate = float(m.group().split()[0])
        link_bandwidth = 100.0  # 假设链路带宽为100 Mbps
        bandwidth_utilization = transfer_rate / link_bandwidth
        return bandwidth_utilization
    else:
        return None

    return bandwidth_utilization

def init(net):
    # setLogLevel('info')
    # topo = F5.MyTopo()
    # net = Mininet(topo=topo, host=CPULimitedHost, link=TCLink)
    net.start()
    state = {}  # 状态
    # 获取所有交换机的状态
    for switch in net.switches:
        # 获取交换机的名称
        switch_name = switch.name
        switch_state = {}  # 交换机对应的状态
        # 获取交换机与之相连的链路的接口名称
        for intf in switch.intfList():
            intf_name = intf.name

            # 获取链路的带宽利用率
            bandwidth_utilization = get_bandwidth_utilization(net,switch_name, intf_name)
            switch_state[intf_name] = bandwidth_utilization
            # link_bw.append(bandwidth_utilization)
            # print(f"交换机 {switch_name} 的链路 {intf_name} 的带宽利用率为:{bandwidth_utilization}")
        state[switch_name] = switch_state


    print(state)
    return state
    # net.stop()

拓扑结构

F5.py

from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import RemoteController
from mininet.link import TCLink
from mininet.util import dumpNodeConnections


class MyTopo(Topo):

    def __init__(self):
        super(MyTopo, self).__init__()
        # Marking the number of switch for per level
        k = 4
        pod = k
        L1 = (pod // 2) ** 2
        L2 = pod * pod // 2
        L3 = L2

        # Starting create the switch
        c = []  # core switch
        a = []  # aggregate switch
        e = []  # edge switch

        # notice: switch label is a special data structure
        for i in range(L1):
            c_sw = self.addSwitch('c{}'.format(i + 1))  # label from 1 to n,not start with 0
            c.append(c_sw)

        for i in range(L2):
            a_sw = self.addSwitch('a{}'.format(L1 + i + 1))
            a.append(a_sw)

        for i in range(L3):
            e_sw = self.addSwitch('e{}'.format(L1 + L2 + i + 1))
            e.append(e_sw)

        # 建立映射关系

        # Starting create the link between switchs
        # first the first level and second level link

        for i in range(L1):
            c_sw = c[i]
            start = i % (pod // 2)
            for j in range(pod):
                self.addLink(c_sw, a[start + j * (pod // 2)])


        # second the second level and third level link
        for i in range(L2):
            group = i // (pod // 2)
            for j in range(pod // 2):
                self.addLink(a[i], e[group * (pod // 2) + j])


        # Starting create the host and create link between switches and hosts
        for i in range(L3):
            for j in range(2):
                hs = self.addHost('h{}'.format(i * 2 + j + 1))
                self.addLink(e[i], hs)

topos = {"mytopo": (lambda: MyTopo())}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值