OpenFlow PacketOut消息机制
前言
由于最近实验的进行,遇到一个比较棘手的问题,就是利用控制器主动发送packet消息的问题,期间遇到一些问题,后来在RYU群中得到群友左木的帮助成功解决,记录一下这些问题,由于是昨天的问题,就没有把错误截图给截下来了(不想在重做一遍了)。
实验工具
- RYU
- mininet
- wireshark
问题描述与解决
class ryu.ofproto.ofproto_v1_3_parser.OFPPacketOut(datapath, buffer_id=None, in_port=None, actions=None, data=None, actions_len=None)
Packet-Out message
The controller uses this message to send a packet out throught the switch.
Attribute | Description |
---|---|
buffer_id | ID assigned by datapath (OFP_NO_BUFFER if none) |
in_port | Packet's input port or OFPP_CONTROLLER |
actions | list of OpenFlow action class |
data | Packet data of a binary type value or an instances of packet.Packet. |
Example:
def send_packet_out(self, datapath, buffer_id, in_port):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD, 0)]
req = ofp_parser.OFPPacketOut(datapath, buffer_id,
in_port, actions)
datapath.send_msg(req)
于是我照猫画虎的来下来如下代码:
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
actions = [ofp_parser.OFPActionOutput(port=1)]
req = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=ofp.OFP_NO_BUFFER, in_port=1,
actions=actions)
datapath.send_msg(req)
这样下来运行也没有错误,可是就是无法在端口一抓到包,心生疑惑又在控制器的那一端抓了一次,结果抓到了这个包。后来在群友耐心指导下,原来是没加data下去,所以在端口一无法抓到包。
于是我就构造了一个arp报文重新发了一次,改了一下代码
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
e = ethernet.ethernet(dst='00:00:00:00:ff:ff',
src='08:60:6e:7f:74:e7',
ethertype=ether.ETH_TYPE_ARP)
a = arp.arp(hwtype=1, proto=0x0800, hlen=6, plen=4, opcode=2,
src_mac='08:60:6e:7f:74:e7', src_ip='192.0.2.1',
dst_mac='00:00:00:00:00:00', dst_ip='192.0.2.2')
p = packet.Packet()
p.add_protocol(e)
p.add_protocol(a)
p.serialize()
actions = [ofp_parser.OFPActionOutput(1)]
req = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=ofp.OFP_NO_BUFFER, in_port=1,
actions=actions, data=p)
datapath.send_msg(req)
这回确实是抓到了,可是又心生疑惑,我明明有一条流表,为什么这个包不会先匹配一下流表吗?于是又向群友求助,原来是:
Action 是一个行动列表定义交换机如何处理数据包的字段。可包括包修改,组处理和一
个输出端口。 一个 OFPT_PACKET_OUT 行动清单消息也可以指定 OFPP_TABLE 保留端口
作为输出行动来处理 OpenFlow 流水线中的数据包,从第一个流表开始(见 4.5) 。如果
OFPP_TABLE 被指定,in_port 作为查找时流表的入端口。
于是我又改了一下代码,把动作改成output到OFPP_TABLE去
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
e = ethernet.ethernet(dst='00:00:00:00:ff:ff',
src='08:60:6e:7f:74:e7',
ethertype=ether.ETH_TYPE_ARP)
a = arp.arp(hwtype=1, proto=0x0800, hlen=6, plen=4, opcode=2,
src_mac='08:60:6e:7f:74:e7', src_ip='192.0.2.1',
dst_mac='00:00:00:00:00:00', dst_ip='192.0.2.2')
p = packet.Packet()
p.add_protocol(e)
p.add_protocol(a)
p.serialize()
actions = [ofp_parser.OFPActionOutput(port=ofp.OFPP_TABLE)]
req = ofp_parser.OFPPacketOut(datapath=datapath, buffer_id=ofp.OFP_NO_BUFFER, in_port=1,
actions=actions, data=p)
datapath.send_msg(req)
这下确实是大功告成了。
途中也遇到了一个疑惑,buffer_id的作用,相信的可以看这篇Openflow细节理解之—Buffer_id篇
总结
如果是OpenFlow消息交互的问题,还是得回归OpenFlow白皮书。