FlowCover算法在Python中的实现

时间:2019-04-19 22:09:28

标签: python sdn mininet

我正在尝试在我的Ryu脚本(在get_topology方法中)实现SDN FlowCover算法。任何人都可以帮助实现那些可以在Mininet中运行的Python吗?

您可以在此处查看算法:https://arxiv.org/pdf/1710.05697

这是我的Ryu脚本:

from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.lib.packet import arp,ipv4
from ryu.lib import hub
from ryu.lib import mac
import copy,itertools
from ryu.topology import event, switches
from ryu.topology.api import get_switch, get_link
import networkx as nx

time_to_collect=10
class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.net=nx.DiGraph()
        self.all_pair_shortest_path={}


    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        match = parser.OFPMatch()
        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,ofproto.OFPCML_NO_BUFFER)]
        self.add_flow(datapath, 0, match, actions)

    def add_flow(self, dp, p, match, actions, idle_timeout=0, hard_timeout=0,table=0):
        ofproto = dp.ofproto
        parser = dp.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                             actions)]

        mod = parser.OFPFlowMod(datapath=dp, priority=p,
                                idle_timeout=idle_timeout,
                                hard_timeout=hard_timeout,
                                match=match, instructions=inst,table_id=table)
        dp.send_msg(mod)

    def get_shortestPath(self,edges,src,dst):
        path=nx.shortest_path(self.net,src,dst)
        edges_used = self.pairwise(path)
        edges_remain = set(edges) - set(edges_used)
        edges_remain = list(edges_remain)
        newgraph = nx.DiGraph()
        newgraph.add_edges_from(edges_remain)
        path2=nx.shortest_path(newgraph,src,dst)# compute second shortest path
        return path,path2

    def pairwise(self,l):#compute pairwise by given a path list
        result = []
        for i in range(len(l)):
            start = l[i]
            end = l[i+1]
            result.append((start,end))
            if end == l[-1]:
                break
        return result

    def getall_pair_shortest_path(self):
        self.all_pair_shortest_path={}
        edges=self.net.edges()
        edges=set(edges)
        edges=list(edges)
        nodes=self.net.nodes
        nodes=set(nodes)
        nodes=list(nodes)
        pairs=set(itertools.product(nodes, nodes))
        for pair in pairs:
            src,dst=pair
            try:
                if src!=dst:
                    path,path2=self.get_shortestPath(edges,src,dst)
                    self.all_pair_shortest_path[pair]=[path,path2]
            except:
               pass

    events = [event.EventSwitchEnter,
              event.EventSwitchLeave, event.EventPortAdd,
              event.EventLinkAdd]

    @set_ev_cls(events)
    def get_topology(self, ev):
        self.net=nx.DiGraph()
        links = copy.copy(get_link(self, None))
        edges_list=[]  # extra list item for constructing nx graph
        if len(links)>0:
            for link in links:
                src = link.src
                dst = link.dst
                edges_list.append((src.dpid,dst.dpid,{'port':src.port_no}))

            self.net.add_edges_from(edges_list)  
            self.getall_pair_shortest_path()


    def send_group_mod(self,datapath,group_id,watch_port1,out_port1,watch_port2,out_port2):
        ofp = datapath.ofproto
        ofp_parser = datapath.ofproto_parser
        actions1 = [ofp_parser.OFPActionOutput(out_port1)]
        actions2 = [ofp_parser.OFPActionOutput(out_port2)]
        weight = 0
        buckets = [ofp_parser.OFPBucket(weight,watch_port1,ofp.OFPG_ANY,actions1),ofp_parser.OFPBucket(weight,watch_port2,ofp.OFPG_ANY,actions2)]
        req = ofp_parser.OFPGroupMod(datapath,ofp.OFPGC_ADD,ofp.OFPGT_FF,group_id,buckets)
        datapath.send_msg(req)


    def build_flow(self, msg,priority, flow_info, src_port, out_port1,out_port2):
        datapath=msg.datapath
        parser = datapath.ofproto_parser
        actions = []
        if out_port2:# if no dst_port2 is supplied meaning that its not group entry
            group_id = int(flow_info[2].split('.')[3])-1
            self.send_group_mod(datapath,group_id,out_port1,out_port1,out_port2,out_port2)
            actions.append(parser.OFPActionGroup(group_id))
        else:
            actions.append(parser.OFPActionOutput(out_port1))

        match = parser.OFPMatch(
            in_port=src_port, eth_type=flow_info[0],
            ipv4_src=flow_info[1], ipv4_dst=flow_info[2])
        self.add_flow(datapath, priority, match, actions,
                      idle_timeout=100, 
                      hard_timeout=100,table=0)
        out = datapath.ofproto_parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, data=msg.data, in_port=src_port, actions=actions)
        datapath.send_msg(out)

    def shortest_forwarding(self, msg, eth_type, ip_src, ip_dst):
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        in_port = msg.match['in_port']
        flow_info = (eth_type, ip_src, ip_dst, in_port)
        back_info = (flow_info[0], flow_info[2], flow_info[1])

        src_sw=int(ip_src.split('.')[3])
        dst_sw=int(ip_dst.split('.')[3])
        curr_sw=datapath.id

        if curr_sw!=dst_sw:
            path,backup_path=self.all_pair_shortest_path[(curr_sw,dst_sw)]
            print path,backup_path
            next_sw_in_path=path[path.index(curr_sw)+1]
            next_sw_in_backuppath=backup_path[backup_path.index(curr_sw)+1]
            out_port1=self.net[curr_sw][next_sw_in_path]['port']
            out_port2=self.net[curr_sw][next_sw_in_backuppath]['port']
            self.build_flow(msg,1, flow_info, in_port, out_port1, out_port2)

        else:
            out_port=1
            self.build_flow(msg,1, flow_info, in_port, out_port,False)

        return

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        """
        """
        msg = ev.msg
        datapath = msg.datapath
        in_port = msg.match['in_port']
        pkt = packet.Packet(msg.data)
        ip_pkt = pkt.get_protocol(ipv4.ipv4)


        if isinstance(ip_pkt, ipv4.ipv4):
            if ip_pkt.src == '0.0.0.0':
                return 
            if len(pkt.get_protocols(ethernet.ethernet)):
                eth_type = pkt.get_protocols(ethernet.ethernet)[0].ethertype
                self.shortest_forwarding(msg, eth_type, ip_pkt.src, ip_pkt.dst)


    def _build_packet_out(self, datapath, buffer_id, src_port, dst_port, data):
        actions = []
        if dst_port:
            actions.append(datapath.ofproto_parser.OFPActionOutput(dst_port))

        msg_data = None
        if buffer_id == datapath.ofproto.OFP_NO_BUFFER:
            if data is None:
                return None
            msg_data = data
        out = datapath.ofproto_parser.OFPPacketOut(datapath=datapath, buffer_id=buffer_id,data=msg_data, in_port=src_port, actions=actions)
        return out

    def send_packet_out(self, datapath, buffer_id, src_port, dst_port, data):
        out = self._build_packet_out(datapath, buffer_id,src_port, dst_port, data)
        if out:
            datapath.send_msg(out)

预期输出:

需要监控交换机:[6,5,21,7,17,19,14,15,22,3,12,24,10,1,11]


总共15个开关 FlowCover计算时间:10.6439590454

0 个答案:

没有答案