首页 > 其他分享 >实验6:开源控制器实践——RYU

实验6:开源控制器实践——RYU

时间:2022-10-29 10:22:23浏览次数:38  
标签:控制器 parser datapath packet msg 开源 ofproto RYU port

实验6:开源控制器实践——RYU

一、实验目的

能够独立部署RYU控制器;
能够理解RYU控制器实现软件定义的集线器原理;
能够理解RYU控制器实现软件定义的交换机原理。

二、实验环境

(一)基本要求

下载虚拟机软件Oracle VisualBox或VMware;
在虚拟机中安装Ubuntu 20.04 Desktop amd64,并完整安装Mininet;

三、实验要求

1.搭建下图所示SDN拓扑,协议使用Open Flow 1.0,并连接Ryu控制器。

  • 在对应文件夹下执行ryu-manager gui_topology.py --observe-links启动控制器

使用命令sudo mn --topo=single,3 --mac --controller=remote,ip=127.0.0.1,port=6633 --switch ovsk,protocols=OpenFlow10搭建上述拓扑

2.通过Ryu的图形界面查看网络拓扑

3.阅读Ryu文档的The First Application一节,运行并使用 tcpdump 验证L2Switch,分析和POX的Hub模块有何不同。

  • 创建L2Switch.py文件,并保存在目录/home/用户名/学号/lab6/中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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]       def __init__(self*args, **kwargs):         super(L2Switch, self).__init__(*args, **kwargs)       @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)     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)]           data = None         if msg.buffer_id == ofp.OFP_NO_BUFFER:              data = msg.data           out = ofp_parser.OFPPacketOut(             datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,             actions=actions, data = data)         dp.send_msg(out)
  • 执行命令ryu-manager L2Switch.py

重新创建拓扑

  • 利用mininet的xterm开启h1,h2,h3的命令行终端,并在h2和h3使用开启抓包(抓取eth0端口)

    • h1 ping h2

  • h1 ping h3

由图可见,h1 ping h2时h3也能收到数据包,h1 ping h3时h2也能收到数据包,说明L2Switch模块的功能同hub模块:为每一个交换机建立通配的洪泛规则,让交换机拥有集线器的功能

  • 分析和POX的Hub模块有何不同

    1.查看下发流表dpctl dump-flows

    2.运行ryuryu-manager L2Switch.py

    3.运行pox(Hub模块)./pox.py log.level --DEBUG forwarding.hub

    无法查看L2Switch下发的流表

而hub模块下发的流表可以查看

编程修改L2Switch.py,另存为L2xxxxxxxxx.py,使之和POX的Hub模块的变得一致(xxxxxxxxx为学号)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 from ryu.base import app_manager from ryu.ofproto import ofproto_v1_3 from ryu.controller import ofp_event from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER from ryu.controller.handler import set_ev_cls       class hub(app_manager.RyuApp):     OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]        def __init__(self*args, **kwargs):         super(hub, self).__init__(*args, **kwargs)        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)     def switch_feathers_handler(self, ev):         datapath = ev.msg.datapath         ofproto = datapath.ofproto         ofp_parser = datapath.ofproto_parser            # install flow table-miss flow entry         match = ofp_parser.OFPMatch()         actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]         # 1\OUTPUT PORT, 2\BUFF IN SWITCH?         self.add_flow(datapath, 0, match, actions)        def add_flow(self, datapath, priority, match, actions):         # 1\ datapath for the switch, 2\priority for flow entry, 3\match field, 4\action for packet         ofproto = datapath.ofproto         ofp_parser = datapath.ofproto_parser         # install flow         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)        @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         in_port = msg.match['in_port']  # get in port of the packet            # add a flow entry for the packet         match = ofp_parser.OFPMatch()         actions = [ofp_parser.OFPActionOutput(ofproto.OFPP_FLOOD)]         self.add_flow(datapath, 1, match, actions)            # to output the current packet. for install rules only output later packets         out = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions)         # buffer id: locate the buffered packet         datapath.send_msg(out)

(二)进阶要求

阅读Ryu关于simple_switch.py和simple_switch_1x.py的实现,以simple_switch_13.py为例,完成其代码的注释工作,并回答下列问题:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 # Copyright (C) 2011 Nippon Telegraph and Telephone Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # #    http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License.   # 引入包 from ryu.base import app_manager from ryu.controller import ofp_event from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_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     class SimpleSwitch13(app_manager.RyuApp):     # 指定OpenFlow版本为1.3     OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]       def __init__(self*args, **kwargs):         super(SimpleSwitch13, self).__init__(*args, **kwargs)         self.mac_to_port = {} # 一个保存(交换机id, mac地址)到转发端口的字典       # 处理EventOFPSwitchFeatures事件     @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           # install table-miss flow entry         #         # We specify NO BUFFER to max_len of the output action due to         # OVS bug. At this moment, if we specify a lesser number, e.g.,         # 128, OVS will send Packet-In with invalid buffer_id and         # truncated packet data. In that case, we cannot output packets         # correctly.  The bug has been fixed in OVS v2.1.0.         match = parser.OFPMatch()#match:流表项匹配,OFPMatch():不匹配任何信息         actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,                                         ofproto.OFPCML_NO_BUFFER)]         self.add_flow(datapath, 0, match, actions)#添加流表项       # 添加流表     def add_flow(self, datapath, priority, match, actions, buffer_id=None):         # 获取交换机信息         ofproto = datapath.ofproto         parser = datapath.ofproto_parser           # 包装action         inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,                                            actions)]         # 判断是否有buffer_id,生成相应的mod对象         if buffer_id:             mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,                                     priority=priority, match=match,                                     instructions=inst)         else:             mod = parser.OFPFlowMod(datapath=datapath, priority=priority,                                     match=match, instructions=inst)         # 发送mod         datapath.send_msg(mod)       # 触发packet in事件时,调用_packet_in_handler函数     @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)     def _packet_in_handler(self, ev):         # If you hit this you might want to increase         # the "miss_send_length" of your switch         if ev.msg.msg_len < ev.msg.total_len:             self.logger.debug("packet truncated: only %s of %s bytes",                             ev.msg.msg_len, ev.msg.total_len)         # 获取Packet_In报文中的各种信息:包信息,交换机信息,协议等等         msg = ev.msg         datapath = msg.datapath         ofproto = datapath.ofproto         parser = datapath.ofproto_parser         in_port = msg.match['in_port']           pkt = packet.Packet(msg.data)         eth = pkt.get_protocols(ethernet.ethernet)[0]           # 忽略LLDP类型         if eth.ethertype == ether_types.ETH_TYPE_LLDP:             # ignore lldp packet             return           # 获取源端口,目的端口         dst = eth.dst         src = eth.src           dpid = format(datapath.id"d").zfill(16)         self.mac_to_port.setdefault(dpid, {})           self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)           # 学习包的源地址,和交换机上的入端口绑定         # learn a mac address to avoid FLOOD next time.         self.mac_to_port[dpid][src] = in_port           # 在字典中查找目的mac地址是否有对应的出端口         if dst in self.mac_to_port[dpid]:             out_port = self.mac_to_port[dpid][dst]         # 没有就进行洪泛         else:             out_port = ofproto.OFPP_FLOOD           actions = [parser.OFPActionOutput(out_port)]           # 下发流表处理后续包,不再触发 packet in 事件         # install a flow to avoid packet_in next time         if out_port != ofproto.OFPP_FLOOD:             match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)             # verify if we have a valid buffer_id, if yes avoid to send both             # flow_mod & packet_out             if msg.buffer_id != ofproto.OFP_NO_BUFFER:                 self.add_flow(datapath, 1, match, actions, msg.buffer_id)                 return             else:                 self.add_flow(datapath, 1, match, actions)         data = None         if msg.buffer_id == ofproto.OFP_NO_BUFFER:             data = msg.data         # 发送Packet_out数据包         out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,                                   in_port=in_port, actions=actions, data=data)         # 发送流表         datapath.send_msg(out)

  

a) 代码当中的mac_to_port的作用是什么?
答:保存mac地址到交换机端口的映射
b) simple_switch和simple_switch_13在dpid的输出上有何不同?
答:simple_switch直接输出dpid,simple_switch_13会在不满16位的dpid前补0直到满16位
c) 相比simple_switch,simple_switch_13增加的switch_feature_handler实现了什么功能?
答:switch_features_handler函数是新增缺失流表项到流表中,当封包没有匹配到流表时,就触发packet_in
d) simple_switch_13是如何实现流规则下发的?
答:在接收到packetin事件后,首先获取包学习,交换机信息,以太网信息,协议信息等。如果以太网类型是LLDP类型,则不予处理。如果不是,则获取源端口目的端口,以及交换机id,先学习源地址对应的交换机的入端口,再查看是否已经学习目的mac地址,如果没有则进行洪泛转发。如果学习过该mac地址,则查看是否有buffer_id,如果有的话,则在添加流动作时加上buffer_id,向交换机发送流表。
e) switch_features_handler和_packet_in_handler两个事件在发送流规则的优先级上有何不同?
答:switch_features_handler下发流表的优先级高于_packet_in_handler。

(三)实验报告

通过这次实验能够了解RYU控制器,理解RYU控制器实现软件定义的集线器原理,理解RYU控制器实现软件定义的交换机原理经过查阅技术博客、文档等资料才解决。

ryu与pox转发的流表的区别:pox是直接向交换机发送流表项的,而ryu要经过处理packet_in事件后,才向交换机下发流表;

RYU工作原理:RYU的L2Switch模块和POX的Hub模块都采用洪泛转发,但不同之处在于:可以在pox的Hub模块运行时查看流表,而无法在ryu的L2Switch模块运行时查看到流表

标签:控制器,parser,datapath,packet,msg,开源,ofproto,RYU,port
From: https://www.cnblogs.com/jiangshanBlog/p/16838159.html

相关文章

  • 实验6:开源控制器实践——RYU
    1、搭建下图所示SDN拓扑,协议使用OpenFlow1.0,并连接Ryu控制器,通过Ryu的图形界面查看网络拓扑。sudomn--topo=single,3--mac--controller=remote,ip=127.0.0.1,port=6......
  • 实验6:开源控制器实践——RYU
    一、实验目的1.能够独立部署RYU控制器;2.能够理解RYU控制器实现软件定义的集线器原理。3.能够理解RYU控制器实现软件定义的交换机原理。二、实验环境Ubuntu20.04Desk......
  • 实验6:开源控制器实践——RYU
    实验6:开源控制器实践——RYU一、实验目的能够独立部署RYU控制器;能够理解RYU控制器实现软件定义的集线器原理;能够理解RYU控制器实现软件定义的交换机原理。二、实验环境......
  • 实验6:开源控制器实践——RYU
    (一)基本要求1.搭建所示SDN拓扑,协议使用OpenFlow1.0,并连接Ryu控制器,通过Ryu的图形界面查看网络拓扑。构建拓扑sudomn--topo=single,3--mac--controller=remote,ip......
  • 实验6:开源控制器实践——RYU
    实验6:开源控制器实践——RYU一、实验目的能够独立部署RYU控制器;能够理解RYU控制器实现软件定义的集线器原理;能够理解RYU控制器实现软件定义的交换机原理。二、实验环......
  • 实验6:开源控制器实践——RYU
    实验6:开源控制器实践——RYU一、实验目的1、能够独立部署RYU控制器2、弄够理解RYU控制器实现软件定义的集线器原理3、能够理解RYU控制器实现软件定义的交换机原理二、......
  • 实验5:开源控制器实践——POX
    实验5:开源控制器实践——POX一、实验目的1、能够理解POX控制器的工作原理;2、通过验证POX的forwarding.hub和forwarding.l2_learning模块,初步掌握POX控制器的使用方法;......
  • 实验6:开源控制器实践——RYU
    1.搭建下图所示SDN拓扑,协议使用OpenFlow1.0,并连接Ryu控制器,通过Ryu的图形界面查看网络拓扑。  输入命令生成拓扑sudomn--topo=single,3--mac--controller=re......
  • SDN 开源控制器实践——RYU
    实验6:开源控制器实践——RYU一、实验目的1.能够独立部署RYU控制器;2.能够理解RYU控制器实现软件定义的集线器原理;3.能够理解RYU控制器实现软件定义的交换机原理。二、......
  • 实验6:开源控制器实践——RYU
    1.基础要求:不同:Ryu中L2Switch下发的流表无法查看,POX中Hub模块可查看L2_212006164代码fromryu.baseimportapp_managerfromryu.controllerimportofp_eventfrom......