1. 代码解析
ryu/app/example_switch_13.py:
from ryu.base importapp_managerfrom ryu.controller importofp_eventfrom ryu.controller.handler importCONFIG_DISPATCHER, MAIN_DISPATCHERfrom ryu.controller.handler importset_ev_clsfrom ryu.ofproto importofproto_v1_3from ryu.lib.packet importpacketfrom ryu.lib.packet importethernetclassExampleSwitch13(app_manager.RyuApp):
OFP_VERSIONS=[ofproto_v1_3.OFP_VERSION]def __init__(self, *args, **kwargs):
super(ExampleSwitch13, self).__init__(*args, **kwargs)#initialize mac address table.
self.mac_to_port ={}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)defswitch_features_handler(self, ev):
datapath=ev.msg.datapath
ofproto=datapath.ofproto
parser=datapath.ofproto_parser#install the table-miss flow entry.
match =parser.OFPMatch()#OFPCML_NO_BUFFER: 不缓冲,将发送整个数据包
actions =[parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)defadd_flow(self, datapath, priority, match, actions):
ofproto=datapath.ofproto
parser=datapath.ofproto_parser#construct flow_mod message and send it.
inst =[parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
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
datapath=msg.datapath
ofproto=datapath.ofproto
parser=datapath.ofproto_parser#get Datapath ID to identify OpenFlow switches.
dpid =datapath.id
self.mac_to_port.setdefault(dpid, {})#analyse the received packets using the packet library.
pkt =packet.Packet(msg.data)
eth_pkt=pkt.get_protocol(ethernet.ethernet)
dst=eth_pkt.dst
src=eth_pkt.src#get the received port number from packet_in message.
in_port = msg.match['in_port']
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#if the destination mac address is already learned,
#decide which port to output the packet, otherwise FLOOD.
if dst inself.mac_to_port[dpid]:
out_port=self.mac_to_port[dpid][dst]else:
out_port=ofproto.OFPP_FLOOD#construct action list.
actions =[parser.OFPActionOutput(out_port)]#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)
self.add_flow(datapath,1, match, actions)#construct packet_out message and send it.
out = parser.OFPPacketOut(datapath=datapath,
buffer_id=ofproto.OFP_NO_BUFFER,
in_port=in_port, actions=actions,
data=msg.data)
datapath.send_msg(out)
Ryu 应用需要继承 ryu.base.app_manager.RyuApp;
OFP_VERSIONS指定支持的OpenFlow版本;
Ryu 会自己完成交换机和控制器间的握手等初始化过程;
每当 Ryu 接收到一个OpenFlow消息时,便会生成对应的事件;使用 ryu.controller.handler.set_ev_cls装饰器可以指定事件处理器:
第一个参数指定事件类型;
第二个参数指定交换机状态;
状态
解释
HANDSHAKE_DISPATCHER
Exchange of HELLO message
CONFIG_DISPATCHER
Waiting to receive SwitchFeatures message
MAIN_DISPATCHER
Normal status
DEAD_DISPATCHER
Disconnection of connection
ryu.controller.controller.Datapath类表示和控制器相连的交换机;主要属性如下,
==================================== ======================================Attribute Description==================================== ======================================id64-bit OpenFlow Datapath ID.
Only availableforryu.controller.handler.MAIN_DISPATCHER
phase.
ofproto A module which exports OpenFlow
definitions, mainly constants appearedin the specification, forthe
negotiated OpenFlow version. For
example, ryu.ofproto.ofproto_v1_0forOpenFlow1.0.
ofproto_parser A module which exports OpenFlow wire
message encoderand decoder forthe
negotiated OpenFlow version.
For example,
ryu.ofproto.ofproto_v1_0_parserfor OpenFlow 1.0.
ofproto_parser.OFPxxxx(datapath,...) A callable to prepare an OpenFlow
messageforthe given switch. It can
be sent with Datapath.send_msg later.
xxxxisa name of the message. For
example OFPFlowModfor flow-mod
message. Arguemnts depend on the
message.
set_xid(self, msg) Generate an OpenFlow XIDandput itinmsg.xid.
send_msg(self, msg) Queue an OpenFlow message to send to
the corresponding switch. If msg.xidis None, set_xid isautomatically
called on the message before queueing.
send_barrier Queue an OpenFlow barrier message to
send to the switch.==================================== ======================================
ryu.ofproto.ofproto_v1_3_parser.OFPMatch类表示流匹配结构体;
================ =============== ==================================Argument Value Description================ =============== ==================================in_port Integer 32bit Switch input port
in_phy_port Integer 32bit Switch physical input port
metadata Integer 64bit Metadata passed between tables
eth_dst MAC address Ethernet destination address
eth_src MAC address Ethernet source address
eth_type Integer 16bit Ethernet frame type
vlan_vid Integer 16bit VLAN id
vlan_pcp Integer 8bit VLAN priority
ip_dscp Integer 8bit IP DSCP (6 bits inToS field)
ip_ecn Integer 8bit IP ECN (2 bits inToS field)
ip_proto Integer 8bit IP protocol
ipv4_src IPv4 address IPv4 source address
ipv4_dst IPv4 address IPv4 destination address
tcp_src Integer 16bit TCP source port
tcp_dst Integer 16bit TCP destination port
udp_src Integer 16bit UDP source port
udp_dst Integer 16bit UDP destination port
sctp_src Integer 16bit SCTP source port
sctp_dst Integer 16bit SCTP destination port
icmpv4_type Integer 8bit ICMP type
icmpv4_code Integer 8bit ICMP code
arp_op Integer 16bit ARP opcode
arp_spa IPv4 address ARP source IPv4 address
arp_tpa IPv4 address ARP target IPv4 address
arp_sha MAC address ARP source hardware address
arp_tha MAC address ARP target hardware address
ipv6_src IPv6 address IPv6 source address
ipv6_dst IPv6 address IPv6 destination address
ipv6_flabel Integer 32bit IPv6 Flow Label
icmpv6_type Integer 8bit ICMPv6 type
icmpv6_code Integer 8bit ICMPv6 code
ipv6_nd_target IPv6 address Target addressforND
ipv6_nd_sll MAC address Source link-layer forND
ipv6_nd_tll MAC address Target link-layer forND
mpls_label Integer 32bit MPLS label
mpls_tc Integer 8bit MPLS TC
mpls_bos Integer 8bit MPLS BoS bit
pbb_isid Integer 24bit PBB I-SID
tunnel_id Integer 64bit Logical Port Metadata
ipv6_exthdr Integer 16bit IPv6 Extension Header pseudo-field
pbb_uca Integer 8bit PBB UCA header field
(EXT-256Old version of ONF Extension)
tcp_flags Integer 16bit TCP flags
(EXT-109ONF Extension)
actset_output Integer 32bit Output portfromaction set metadata
(EXT-233ONF Extension)================ =============== ==================================
ryu.ofproto.ofproto_v1_3_parser.OFPFlowMod类表示Flow Mod消息,即修改流项;支持以下参数:
================ ======================================================Attribute Description================ ======================================================cookie Opaque controller-issued identifier
cookie_mask Mask used to restrict the cookie bits that must match
when the commandis OPFFC_MODIFY* orOFPFC_DELETE*table_id ID of the table to put the flowincommand One of the following values.|OFPFC_ADD|OFPFC_MODIFY|OFPFC_MODIFY_STRICT|OFPFC_DELETE|OFPFC_DELETE_STRICT
idle_timeout Idle time before discarding (seconds)
hard_timeout Max time before discarding (seconds)
priority Priority level of flow entry
buffer_id Buffered packet to apply to (orOFP_NO_BUFFER)
out_port For OFPFC_DELETE*commands, require matching
entries to include this as an output port
out_group For OFPFC_DELETE*commands, require matching
entries to include this as an output group
flags Bitmap of the following flags.|OFPFF_SEND_FLOW_REM|OFPFF_CHECK_OVERLAP|OFPFF_RESET_COUNTS|OFPFF_NO_PKT_COUNTS|OFPFF_NO_BYT_COUNTS
match Instance of OFPMatch
instructions list of OFPInstruction*instance================ ======================================================
ryu.ofproto.ofproto_v1_3_parser.OFPPacketIn类表示Packet-In消息,即交换机发向控制器;包含以下属性:
============= =========================================================Attribute Description============= =========================================================buffer_id ID assigned by datapath
total_len Full length of frame
reason Reason packetisbeing sent.|OFPR_NO_MATCH|OFPR_ACTION|OFPR_INVALID_TTL
table_id ID of the table that was looked up
cookie Cookie of the flow entry that was looked up
match Instance of OFPMatch
data Ethernet frame============= =========================================================
ryu.ofproto.ofproto_v1_3_parser.OFPPacketOut类表示Packet-Out消息,即控制器发向交换机;包含以下属性:
================ ======================================================Attribute Description================ ======================================================buffer_id ID assigned by datapath (OFP_NO_BUFFERifnone)
in_port Packet's input port or OFPP_CONTROLLER
actions list of OpenFlow action classdata Packet data of a binary type valueoran instances of packet.Packet.================ ======================================================
ryu.ofproto.ofproto_v1_3_parser.OFPActionOutput类表示输出动作;支持以下参数:
================ ======================================================Attribute Description================ ======================================================port Output port
max_len Max length to send to controller================ ======================================================
ryu.ofproto.ofproto_v1_3_parser.OFPInstructionActions表示写/应用/清空 actions 的指令:
================ ======================================================Attribute Description================ ======================================================type One of following values.|OFPIT_WRITE_ACTIONS|OFPIT_APPLY_ACTIONS|OFPIT_CLEAR_ACTIONS
actions list of OpenFlow action class================ ======================================================
支持的指令如下:
OFPIT_GOTO_TABLE = 1 #Setup the next table in the lookup pipeline.
OFPIT_WRITE_METADATA = 2 #Setup the metadata field for use later in
#pipeline.
OFPIT_WRITE_ACTIONS = 3 #Write the action(s) onto the datapath
#action set
OFPIT_APPLY_ACTIONS = 4 #Applies the action(s) immediately
OFPIT_CLEAR_ACTIONS = 5 #Clears all actions from the datapath action
#set
OFPIT_METER = 6 #Apply meter (rate limiter)
OFPIT_EXPERIMENTER = 0xFFFF #Experimenter instruction
2. 运行
# --topo sigle,3: 单个交换机,3个主机
#--mac: 自动设置主机的MAC地址
#--switch ovsk: 使用 ovs
#--controller remote: 使用外部OpenFlow控制器
#-x: 启动xterm
$sudo mn --topo single,3 --mac --switch ovsk --controller remote -x
此时会启动5个xterm:h1~h3, switch, controller.
设置OpenFlow版本:switch: s1
# ovs-vsctl set Bridge s1 protocols=OpenFlow13
启动控制器:controller: c0
# ryu-manager --verbose ryu/app/example_switch_13.py
查看Table-miss流项:switch: s1
# ovs-ofctl -O OpenFlow13 dump-flows s1
ping:
mininet> h1 ping -c1 h2
再次查看流项:switch: s1
# ovs-ofctl -O OpenFlow13 dump-flows s1
参考资料
https://osrg.github.io/ryu-book/en/Ryubook.pdf