【mininet 0x01】mininet环境搭建
【mininet 0x02】如何使用mn工具来 *** 作mininet
【mininet 0x03】如何使用Python API来 *** 作mininet
【mininet 0x04】使用ryu作为mininet的controller完成HUB功能
【mininet 0x05】使用ryu作为mininet的controller完成L2Switch功能
文章目录
- mininet 系列文章链接归类:
- 前言
- 一、安装ryu
- 二、 实现一个简单的Switch
- 关键代码
- 三、实际效果
- 总结
- 参考
前言
这一节我们将接触controller,使用开源的框架ryu,制作一个简单的二层带学习MAC-Port的Switch功能。
一、安装ryu
我的环境是python2.7
,如果环境相同的读者可以按照下面的链接进行安装:
【RYU】python2.7环境安装RYU的方法及遇到的坑
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet, ether_types
from ryu.lib.packet import ethernet
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(self, *args, **kwargs)
# {dpid : {mac: port]}
self.mac_to_port = {}
@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()
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
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
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)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg # ev = PacketIn'data structure msg = openflow message
data = None
dp = msg.datapath # dp=switch'id
ofp = dp.ofproto
ofp_parser = dp.ofproto_parser
in_port = msg.match['in_port']
self.logger.info("switch is %s,buffer_id is %s,in_port is %s.", dp.id, msg.buffer_id, in_port)
pkg = packet.Packet(msg.data)
eth = pkg.get_protocols(ethernet.ethernet)[0]
print eth
src_MAC = eth.src
dst_MAC = eth.dst
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
# ignore lldp packet
self.logger.info("filter out LLDP msg.")
return
dpid = format(dp.id, "d").zfill(16)
self.mac_to_port.setdefault(dpid, {})
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src_MAC] = in_port
# find dst MAC in mac_to_port dict,
# send the pkg to the port, if we find out the dst port in mac_to_port by dst MAC.
# send to all port in the switch, if we can not find the dst port in mac_to_port by dst MAC.
if dst_MAC in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst_MAC]
actions = [ofp_parser.OFPActionOutput(out_port)]
match = ofp_parser.OFPMatch(in_port=in_port, eth_dst=dst_MAC, eth_src=src_MAC)
if msg.buffer_id != ofp.OFP_NO_BUFFER:
self.add_flow(datapath=dp, priority=100, match=match, actions=actions, buffer_id=msg.buffer_id)
return
else:
self.add_flow(datapath=dp, priority=100, match=match, actions=actions)
else:
out_port = ofp.OFPP_FLOOD
actions = [ofp_parser.OFPActionOutput(out_port)]
if msg.buffer_id == ofp.OFP_NO_BUFFER:
data = msg.data
out = ofp_parser.OFPPacketOut(
datapath=dp, buffer_id=msg.buffer_id, in_port=in_port,
actions=actions, data=data)
dp.send_msg(out)
self.logger.info("send success!")
- ev.msg:每一个事件类ev中都有msg成员,用于携带触发事件的数据包。
- msg.datapath:已经格式化的msg其实就是一个packet_in报文,msg.datapath直接可以获得packet_in报文的datapath结构。datapath用于描述一个交换网桥。也是和控制器通信的实体单元。datapath.send_msg()函数用于发送数据到指定datapath。通过datapath.id可获得dpid数据,在后续的教程中会有使用。
- datapath.ofproto对象是一个OpenFlow协议数据结构的对象,成员包含OpenFlow协议的数据结构,如动作类型OFPP_FLOOD。
- datapath.ofp_parser则是一个按照OpenFlow解析的数据结构。
- actions是一个列表,用于存放action list,可在其中添加动作。
- 通过ofp_parser类,可以构造构造packet_out数据结构。括弧中填写对应字段的赋值即可。
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src_MAC] = in_port
对于来的所有包,源MAC 进行一个学习,记录到mac_to_port字典中,
mac_to_port的结构为:{dpid : {mac: port]}
# find dst MAC in mac_to_port dict,
# send the pkg to the port, if we find out the dst port in mac_to_port by dst MAC.
# send to all port in the switch, if we can not find the dst port in mac_to_port by dst MAC.
if dst_MAC in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst_MAC]
actions = [ofp_parser.OFPActionOutput(out_port)]
match = ofp_parser.OFPMatch(in_port=in_port, eth_dst=dst_MAC, eth_src=src_MAC)
if msg.buffer_id != ofp.OFP_NO_BUFFER:
self.add_flow(datapath=dp, priority=100, match=match, actions=actions, buffer_id=msg.buffer_id)
return
else:
self.add_flow(datapath=dp, priority=100, match=match, actions=actions)
else:
out_port = ofp.OFPP_FLOOD
actions = [ofp_parser.OFPActionOutput(out_port)]
对于目的MAC在mac_to_port列表中的包,我们直接进行单播就好了,
对于目的MAC接口未知的情况,我们选择进行FLOOD处理,发往switch上所有的接口。
1、用命令 mn --topo linear,2 --mac --switch ovsk --controller remote
创建如下拓扑:
能够看到互ping已经通了
ryu的日志:
流表状态:
2、再创建如下拓扑:
能够看到互ping已经通了
ryu日志:
ovs流表内容:
使用ryu作为mininet的controller,完成了switch功能。
参考http://www.muzixing.com/pages/2014/09/20/ryuru-men-jiao-cheng.html
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)