zoukankan      html  css  js  c++  java
  • shortest_forwording.py

    from ryu.base import app_manager
    from ryu.ofproto import ofproto_v1_3
    from ryu.controller import ofp_event
    from ryu.controller.handler import set_ev_cls
    from ryu.controller.handler import CONFIG_DISPATCHER,MAIN_DISPATCHER
    from ryu.lib.packet import packet
    from ryu.lib.packet import ethernet
    from ryu.topology import event
    from ryu.topology.api import get_switch, get_link
    import networkx as nx

    #原理:
    # 1)拓扑信息发现:周期发送LLDP报文,发现链路信息,使用networkx来存储拓扑信息。
    # 2)根据链路信息计算最佳转发路径:使用networkx实现最短路径计算
    # 3)根据最短路径,安装流表项,实现批量下发流表项方法

    class ShortestForwarding(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]


    def __init__(self,*args,**kwargs):
    super(ShortestForwarding, self).__init__(*args,**kwargs)
    self.network = nx.DiGraph()#声明一个有向图
    self.topology_api_app = self#用自己的拓扑
    self.paths = {}

    #handle switch features info
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self,ev):
    datapath = ev.msg.datapath
    ofproto = datapath.ofproto
    ofp_parser = datapath.ofproto_parser

    #install a table-miss flow entry for each datapath
    match = ofp_parser.OFPMatch()
    #看这action动作的参数,就知道是下面的send_msg(mod)是提交到控制器的请求了
    actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
    ofproto.OFPCML_NO_BUFFER)]

    self.add_flow(datapath,0,match,actions)

    #流表都是在交换机中安装的
    def add_flow(self,datapath,priority,match,actions):
    ofproto = datapath.ofproto
    ofp_parser = datapath.ofproto_parser
    #inst,mod都是在已经获取到的match,action的基础下得到的,所以是可以通过参数的方式传递进来
    #contruct a flow_mod msg and send it to datapath
    inst = [ofp_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
    actions)]
    mod = ofp_parser.OFPFlowMod(datapath=datapath,priority=priority,
    match=match,instructions=inst)

    #发送信息给控制器
    datapath.send_msg(mod)

    #get topology and store it into network object.
    #两种状态都可能会出现,所以就是[]
    @set_ev_cls(event.EventSwitchEnter,[CONFIG_DISPATCHER,MAIN_DISPATCHER])
    def get_topology(self,ev):

    #get nodes
    switch_list = get_switch(self.topology_api_app,None)
    switches = [switch.dp.id for switch in switch_list]#datapath是以键值对的形式储存
    self.network.add_nodes_from(switches)

    #get links
    links_list = get_link(self.topology_api_app,None)
    links = [(link.src.dpid,link.dst.dpid,{'port':link.src.port_no}) for link in links_list]
    self.network.add_edges_from(links)

    #get reverse links
    links = [(link.dst.dpid,link.src.dpid,{'port':link.dst.port_no}) for link in links_list]
    self.network.add_edges_from(links)

    #get out_port by using networkx's Dijkstra algorithm.
    def get_out_port(self,datapath,src,dst,in_port):
    dpid = datapath.id
    #add links between host and access switch
    if src not in self.network:
    self.network.add_node(src)
    self.network.add_edge(dpid,src,{'port':in_port})
    self.network.add_edge(src,dpid)#主机到交换机的链路一般是没用的,一般是网卡的名字。
    self.paths.setdefault(src,{})

    if dst in self.network:
    if dst not in self.paths[src]:
    path = nx.shortest_path(self.network,src,dst)
    self.paths[src][dst] = path

    path = self.paths[src][dst]#要记得这是个二维数组
    #因为我们要找的是out_port,要找的是出口。
    next_hop = path[path.index(dpid) + 1]
    #['port']是[next_hop]里面存在的一个属性
    out_port = self.network[dpid][next_hop]['port']
    print("path:",path)
    else:
    out_port = datapath.ofproto.OFPP_FLOOD
    return out_port

    #handle packet in msg
    @set_ev_cls(ofp_event.EventOFPPacketIn,MAIN.DISPATCHER)
    def packet_in_handler(self,ev):
    #解析事件信息
    msg = ev.msg
    datapath = msg.datapath
    ofproto = datapath.ofproto
    ofp_parser = datapath.ofproto_parser

    #还要对网络数据包进行解析
    pkt = packet.Packet(msg.data)
    eth = pkt.get_protocol(ethernet.ethernet)
    in_port = msg.match["in_port"]

    #get out_port
    out_port = self.get_out_port(datapath,eth.src,eth.dst,in_port)#也是需要通过入端口找到出端口的
    actions = [ofp_parser.OFPActionOutput[out_port]]

    #install flow entries
    if out_port != ofproto.OFPP_FLOOD:
    #因为我们是要找指定端口,匹配参数自然少不了端口匹配。
    match = ofp_parser.OFPMatch(in_port=in_port,eth_dst=eth_dst)
    #下发流表指导后续操作
    self.add_flow(datapath,1,match,actions)

    #控制器会下发packet_out包到交换机的指定端口:是因为上面下发了流表,才指导的了下面的后续操作吧
    out = ofp_parser.OFPPacketOut(
    datapath=datapath,buffer_id=msg.buffer_id,in_port=in_port,actions=actions)
    datapath.send_msg(out)

  • 相关阅读:
    VMware的三种网络连接方式区别
    迁移至博客园
    Oracle常用语句集合
    Oracle表的几种连接方式
    Oracle逻辑结构(TableSpace→Segment→Extent→Block)
    从线性代数的角度理解线性时不变系统和信号响应
    从线性代数的角度理解傅里叶变换
    在WPF中调用文件夹浏览/选择对话框
    在WPF中调用打开文件对话框
    在WPF中调用另存为对话框
  • 原文地址:https://www.cnblogs.com/yangrongkuan/p/12009331.html
Copyright © 2011-2022 走看看