2019 SDN上机第5次作业

别等时光非礼了梦想. 提交于 2019-11-26 03:24:47

1.浏览RYU官网学习RYU控制器的安装和RYU开发入门教程,提交你对于教程代码的理解

1.描述官方教程实现了一个什么样的交换机功能?

让交换机在各个端口发送它接收到的数据包

2. 控制器设定交换机支持什么版本的OpenFlow?

OpenFlow v1.0

3. 控制器设定了交换机如何处理数据包?

这里把官方给出的代码放上来(不然不知道在解释啥),备注中解释到处理函数定义为止的部分,部分需要单独列出的在下面用文字解释

from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0

class L2Switch(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION] #这里设置想要向交换机协商的OpenFlow版本号
   #这玩意设置完后,控制器会自动交换Hello包,协商版本号,接着协商完成之后,它再自动执行交换Features包,进行握手
    def __init__(self, *args, **kwargs):
        super(L2Switch, self).__init__(*args, **kwargs)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) #握手完成后,使用set_ev_cls函数处理Features响应包
    def packet_in_handler(self, ev): #这里调用处理函数,并解析返回包的字段
        msg = ev.msg 
        dp = msg.datapath
        ofp = dp.ofproto
        ofp_parser = dp.ofproto_parser

        actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
        out = ofp_parser.OFPPacketOut(
            datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
            actions=actions)
        dp.send_msg(out)

set_ev_cls:这其实是个修饰器,它功能就是告诉Ryu啥时候调用它要修饰的那个函数,它里面的俩实参啥意思我们看下面

ofp_event.EventOFPPacketIn:这个实参表示要调用的那个函数是用来处理什么事件的,换句话说,就是根据要处理的事件来决定调用什么函数

MAIN_DISPATCHER:这个实参则表示交换机的状态,它的意思是只有在协商完成之后,下面要用的那个处理函数才能被调用,我们现在看到的“MAIN_DISPATCHER”这玩意代表状态正常OK,即控制器收到回复,可以下发配置消息

ev.msg:这是packet_in数据结构的对象

msg.datapath :这玩意是交换机的对象,datapath其实就是OVS中虚拟交换机的代称

ofp = dp.ofproto和ofp_parser = dp.ofproto_parser:这俩玩意也是对象,代表交换机和Ryu在协商中订立的OpenFlow协议

OFPActionOutput :这是个类,当要发送packet_out信息时,用它来选择要往哪个交换机端口发送

OFPPacketOut :这也是个类,用来建立OFPPacketOut信息

send_msg:这是个方法(应该是),一般在有OpenFlow信息类对象的情况下调用它,它的作用就是让Ryu建立在线数据格式结构并发送给交换机

2.根据官方教程和提供的示例代码(SimpleSwitch.py),将具有自学习功能的交换机代码(SelfLearning.py)补充完整

二层交换机,编写过程中依赖了百度,我太菜了我应该在车底

#coding=utf-8
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
from ryu.lib.mac import haddr_to_bin
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
 
class L2Switch(app_manager.RyuApp):
 
    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]  #定下使用的OpenFlow版本
 
    def __init__(self, *args, **kwargs):
        super(L2Switch, self).__init__(*args, **kwargs)
        self.mac_to_port = {}
 
    def add_flow(self, datapath, in_port, dst, actions):
        ofproto = datapath.ofproto
 
        match = datapath.ofproto_parser.OFPMatch(
            in_port = in_port, dl_dst = haddr_to_bin(dst))
 
        mod = datapath.ofproto_parser.OFPFlowMod(
            datapath = datapath, match = match, cookie = 0,
            command = ofproto.OFPFC_ADD, idle_timeout = 10,hard_timeout = 30,
            priority = ofproto.OFP_DEFAULT_PRIORITY,
            flags =ofproto.OFPFF_SEND_FLOW_REM, actions = actions)
 
        datapath.send_msg(mod)
 
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) #展示交换机状态,通知何时调用函数
    def packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
 
        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocol(ethernet.ethernet)
 
        dst = eth.dst
        src = eth.src
 
        dpid = datapath.id    #获取dpid
        self.mac_to_port.setdefault(dpid, {})
 
        self.logger.info("packet in %s %s %s %s", dpid, src, dst , msg.in_port)  #获得局域网地址,防止下次出现溢出现象
        
 
        self.mac_to_port[dpid][src] = msg.in_port
 
 
        out_port = ofproto.OFPP_FLOOD
 

        if dst in self.mac_to_port[dpid]:  #查询输出端口
            out_port = self.mac_to_port[dpid][dst]
 
        ofp_parser = datapath.ofproto_parser
 
        actions = [ofp_parser.OFPActionOutput(out_port)]
 
        if out_port != ofproto.OFPP_FLOOD:
            self.logger.info("add flow s:DPID:%s Match:[ MAC_SRC:%s MAC_DST:%s IN_PORT:%s ], Action:[OUT_PUT:%s] ",dpid, src, dst, msg.in_port, out_port) #显示datapath id,目标的MAC地址,源的MAC地址,进入端口,输出端口等信息
            self.add_flow(datapath, msg.in_port, dst, actions)
 
 
        packet_out = ofp_parser.OFPPacketOut(datapath = datapath, buffer_id = msg.buffer_id,in_port = msg.in_port, actions = actions)  #持续发送packet_out消息以抓包
        datapath.send_msg(packet_out)

    @set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER) #这里则是展示端口状态
    def _port_status_handler(self, ev):
        msg = ev.msg
        reason = msg.reason
        port_no = msg.desc.port_no
 
        ofproto = msg.datapath.ofproto
 
        if reason == ofproto.OFPPR_ADD:
            self.logger.info("port added %s", port_no)
        elif reason == ofproto.OFPPR_DELETE:
            self.logger.info("port deleted %s", port_no)
        elif reason == ofproto.OFPPR_MODIFY:
            self.logger.info("port modified %s", port_no)
        else:
            self.logger.info("Illeagal port state %s %s", port_no, reason)

3.在mininet创建一个最简拓扑,并连接RYU控制器

拓扑图如下:

Python代码如下:

from mininet.topo import Topo

class Mytopo(Topo):

    def __init__(self):

        Topo.__init__(self)

        sw=self.addSwitch('s1')

        count=1

        for i in range(2):

                host = self.addHost('h{}'.format(count))

                self.addLink(host,sw,1,count)

                count = count + 1

topos = {'mytopo': (lambda:Mytopo())}

创建成功

进入ryu安装文件夹,创建selflearning.py文件,输入

ryu-manager selflearning.py

执行它以连接ryu控制器

4.验证自学习交换机的功能,提交分析过程和验证结果

咱们连接到了RYU这个外部控制器才能ping测试连通性,不然主机之间是不互通的,既然这里已经连接到了,那么输入h1 ping h2,测试主机之间的连通性

在连通期间另开终端,输入sudo ovs-ofctl dump-flows s1,下发流表

开启RYU控制器的终端会显示如下信息,可以看到目标的MAC地址,源的MAC地址,进入端口,输出端口等数据

5.写下你的实验体会

主要繁琐在安装RYU的过程,代码方面读懂教程问题就不大,学海无涯,而我太菜,需加倍努力

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!