- 1 fromryu.baseimportapp_manager#继承ryu.base.app_manager
- 2 fromryu.controllerimportofp_event#继承ryu.controller.ofp_event
- 3 fromryu.controller.handlerimportCONFIG_DISPATCHER, MAIN_DISPATCHER#继承ryu.controller.handler.CONFIG_DISPATCHER, MAIN_DISPATCHER
- 4 fromryu.controller.handlerimportset_ev_cls#继承ryu.controller.handler.set_ev_cls
- 5 fromryu.ofprotoimportofproto_v1_3#继承ryu.ofproto.ofproto_v1_3
- 6 fromryu.lib.packetimportpacket#继承ryu.lib.packet.packet
- 7 fromryu.lib.packetimportethernet#继承ryu.lib.packet.ethernet
- 8 fromryu.lib.packetimportether_types#继承ryu.lib.packet.ether_types+63652020
- 9
- 10 class SimpleSwitch13(app_manager.RyuApp):
- 11OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]#用于指定OpenFlow的版本,这里指定OpenFlow的版本为1.3版
- 12 #定义版本以后,mac_to_port也已经被指定
- 13 #初始化环境变量
- 14 def __init__(self, *args, **kwargs):
- 15super(SimpleSwitch13, self).__init__(*args, **kwargs)
- 16self.mac_to_port = {}
- 17
- 18 #Event Handler是一个拥有事件物件(Event Object)作为参数
- 19 #并使用"ryu.controller.handler.set_ev_cls"来修饰decorator函数
- 20 #set_ev_cls用于指定事件类别得以接受讯息和交换机状态作为参数
- 21 #时间类别命名名称的规则为ryu.controller.ofp_event.EventOFP + <OpenFlow讯息名称>
- 22 #如Packet-in讯息的状态下的时间为EventOFPPacketIn
- 23
- 24 #部分名称的作用
- 25 #ryu.controller.handler.HANDSHAKE_DISPATCHER 交换HELLO信息
- 26 #ryu.controller.handler.CONFIG_DISPATCHER 接收SwitchFeatures讯息
- 27 #ryu.controller.handler.MAIN_DISPATCHER 一般状态
- 28 #ryu.controller.handler.DEAD_DISPATCHER 连线中断
- 29 @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
- 30 def switch_features_handler(self, ev):
- 31datapath = ev.msg.datapath#此讯息用于存储OpenFlow交换机的ryu.controller.controller.Datapath类别所对应的实体
- 32ofproto = datapath.ofproto
- 33parser = datapath.ofproto_parser
- 34
- 35 #ev.msg是用来存储对应事件的OpenFlow讯息类别实体。在这个例子中,则是ryu.ofproto.ofproto_v1_3_parser.OFPSwitchFeatures
- 36 #Datapath类别是用来处理OpenFlow交换机的重要讯息,例如执行与交换机的通信和触发接收讯息的事件
- 37
- 38match = parser.OFPMatch()#为了match所有封包,需要产生一个空的match
- 39actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
- 40 ofproto.OFPCML_NO_BUFFER)]
- 41 #为了将封包转送到Controller连接埠,OFPActionOutput类别的实例也会被产生
- 42 #指定OFPP_Controller为封包目的地
- 43 #设定OFPCML_NO_BUFFER为max_len以便接下来的封包传送
- 44 self.add_flow(datapath, 0, match, actions)
- 45 #设定Table-miss Flow Entry的优先权为0(最低优先权)
- 46 #然后执行add_flow()方法以发送Flow Mod讯息
- 47
- 48 #交换机本身不仅仅使用Switch features讯息,
- 49 #还使用事件处理以取得新增Table-miss Flow Entry的时间点
- 50 #Table-miss Flow Entry的优先权为0(最低优先权),而且此Entry可以match所有的封包
- 51 #这个Entry的Instruction通常指定为output action
- 52
- 53 #定义add_flow()函数,用于新增Flow Entry
- 54 defadd_flow(self, datapath, priority, match, actions, buffer_id=None):
- 55ofproto = datapath.ofproto
- 56parser = datapath.ofproto_parser
- 57
- 58inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
- 59 actions)]
- 60 #APPLY_ACTIONS是用来设定那些必须立即执行的action所使用的
- 61
- 62 if buffer_id:
- 63mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
- 64priority=priority, match=match,
- 65instructions=inst)
- 66 else:
- 67mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
- 68match=match, instructions=inst)
- 69 #OFPFlowMod类别中参数的预设值
- 70 #datapath:openflow交换机以及flow table的操作都是通过datapath类别的实体来进行。
- 71 #在一般的情况下,会由事件传递给事件管理的讯息中取得,如Packet-In
- 72 #cookie(0): controller所设定存储的资料,在Entry的更新或者删除时所需要使用的资料存放地
- 73 #并作为过滤器使用,而且不可以作为封包处理的参数
- 74 #cookie_mask():Entry的更新或删除时,若是该值为非零,则作为指定Entry的cookie使用
- 75 #table_id(0):使用Flow Entry的Table ID
- 76 #idle_timeout:flow entry 的有效期限,以秒为单位
- 77 #hard_timeout:flow entry的有效期限,但在超过时间限后不会重新归零计算
- 78 #priority:优先权,值越大,优先权限越高
- 79 #out_put(0):OFPFC_DELETE 和 OFPFC_DELETE_STRICT 命令用來指定输出位置的参数。
- 80 #命令为 OFPFC_ADD、 OFPFC_MODIFY、OFPFC_MODIFY_STRICT 时可以忽略。
- 81 #若要制定无效,指定输出为OFPP_ANY
- 82 #out_group(0):与上相同,作为一个输出位置,但是转到特定的group,若无效,使用OFPG_ANY
- 83
- 84
- 85 #通过FlowMod讯息将Flow Entry新增到Flow table中
- 86 datapath.send_msg(mod)
- 87 #使用OFPFlowMod所产生的实体通过datapath,send_msg()来发送讯息至交换机
- 88
- 89 #Packet-In事件接收处理位置目的地的封包
- 90 @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
- 91 #OFPPacketIn类别的常用属性
- 92 #match: ryu.ofproto.ofproto_v1_3_parser.OFPMatch类别的实体,用来存储接收封包的meta讯息
- 93 #data:接收封包本身的binary资料
- 94 #tatal_len:接收封包的资料长度
- 95 #buffer_id:接受封包的内容。
- 96 #若存在OpenFlow交换机上时所指定的ID,如果在没有buffer的状态下,则设定ryu.ofproto.ofproto_v1_3.OFP_NO_BUFFER
- 97
- 98 #更新MAC地址表
- 99 def _packet_in_handler(self, ev):
- 100 # If you hit this you might want to increase
- 101 # the "miss_send_length" of your switch
- 102 ifev.msg.msg_len < ev.msg.total_len:
- 103self.logger.debug("packet truncated: only %s of %s bytes",
- 104 ev.msg.msg_len, ev.msg.total_len)
- 105msg = ev.msg
- 106datapath = msg.datapath
- 107ofproto = datapath.ofproto
- 108parser = datapath.ofproto_parser
- 109in_port = msg.match['in_port']
- 110 #从OFPPacketIn类别的match得到接收埠(in_port)的讯息。
- 111 #目的MAC地址和来源MAC地址分别使用Ryu的封包函数库,从接收到封包的Ethernet header取得
- 112
- 113pkt = packet.Packet(msg.data)
- 114eth = pkt.get_protocols(ethernet.ethernet)[0]
- 115
- 116 ifeth.ethertype == ether_types.ETH_TYPE_LLDP:
- 117 return
- 118dst = eth.dst
- 119src = eth.src
- 120
- 121dpid = datapath.id
- 122 #是同datapath.id来确认MAC地址表和每个交换机之间的识别来应对连接到多个OpenFlow交换机
- 123 self.mac_to_port.setdefault(dpid, {})
- 124
- 125self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
- 126
- 127 # learn a mac address to avoid FLOOD next time.
- 128self.mac_to_port[dpid][src] = in_port
- 129 #借此得知目的MAC地址表和来源MAC地址,更新MAC地址表
- 130
- 131
- 132 ifdstin self.mac_to_port[dpid]:
- 133out_port = self.mac_to_port[dpid][dst]
- 134 else:
- 135out_port = ofproto.OFPP_FLOOD
- 136
- 137actions = [parser.OFPActionOutput(ofproto.OFPP_IN_PORT)]
- 138 #判断转送封包的连接埠
- 139 #若目的MAC地址存在于MAC地址表,则判断该连接埠的号码作为输出
- 140 #反之若不存在MAC地址表
- 141 #则ActionOutput类别的尸体并生成flooding(OFPP_FLOOD)给目的连接埠使用
- 142
- 143 #转送封包
- 144 #在MAC位置表中找寻目的MAC地址,若有则发送Packet-in讯息,并转送封包
- 145 # install a flow to avoid packet_in next time
- 146 ifout_port != ofproto.OFPP_FLOOD:
- 147match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
- 148 # verify if we have a valid buffer_id, if yes avoid to send both
- 149 # flow_mod & packet_out
- 150 ifmsg.buffer_id != ofproto.OFP_NO_BUFFER:
- 151self.add_flow(datapath, 1, match, actions, msg.buffer_id)
- 152 return
- 153 else:
- 154self.add_flow(datapath, 1, match, actions)
- 155data = None
- 156 ifmsg.buffer_id == ofproto.OFP_NO_BUFFER:
- 157data = msg.data
- 158
- 159out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
- 160in_port=in_port, actions=actions, data=data)
- 161 datapath.send_msg(out)
- 162
- 163 #buffer_id:指定openflow交换机上封包对应的缓冲区,若不需要,则指定为OFP_NO_BUFFER
- 164 #in_port:制定接收到的连接埠号,如果不想使用,就制定为OFPP_CONTROLLER
来源: http://www.cnblogs.com/sgatbl/p/6861771.html