OpenFlow消息中buffer_Id是什么?
Openflow中buffer_id分别在三类消息中定义,并且起到的作用均是不同的。
- Packetin消息:用于标记缓存在交换机中的数据报文id,如报文被action上送到控制器中maxlen字段或者table_miss消息限制长度,而通过bufferid将报文缓存在交换机中,以便被另外两种消息来调用;
- Packetout消息:用于控制器将原先buffer在交换机中的报文,通过Packetout个形式从交换机的某个物理口送出去;
- Flowmod消息:如果flowmod中带有bufferid,那么说明这个flowmod需要做两件事情,第一是正常下发一条flow,其次是把交换机中先前buffer的那个数据报文,Packetout到table来匹配一次下的这条flow;注意以上两个指令都是通过这个带有bufferid的消息执行的,不需要控制器另外下packet_out消息,这种设计思路是非常巧妙的。
为什么要引入buffer_Id?
- 优点没必要多说,Packet_in到控制器的报文决策之后,大部分报文必然还是要扔回交换机的,为何不在交换机上缓存起来,只送个tag上去呢?
Openflow针对buffer_id的设计思想
- 协议针对packetin/packetout中buffer_id的设计思想很简单,一个上去,一个下来,具体思路参考下面例子。
- 协议针对Flowmod中bufferid设计思想就非常巧妙了,前面我已经提过,如果flowmod中带有bufferid,那么说明这个flowmod需要做两件事情,第一是正常下发一条flow,其次是把交换机中先前buffer的那个数据报文,Packetout到table来匹配一次下的这条flow;我这里举个例子大家就明白为什么这么设计了:
举例
- 假设现在从交换机的某个口进来一个arp请求的报文,通过tablemiss直接Packetin(bufferid是0x100)上送到controller了,controller收到之后这个arp请求之后肯定会通过Packetout(bufferid填0x100)把这个报文给广播出去,这个过程数据报文不用真正整个都送到控制器,只要送上去指定长度部分,并通过bufferid来交互数据报文内容
- 现在又假设交换机上某个口挂的host响应了这个arp请求,并回复了arp reply,交换机收到依然果断Packetin(bufferid是0x100)送控制器,这个时候控制器已经知道了往哪里回复,那控制器这个时候不Packetout了,干脆下个flowmod(bufferid是0x100)吧,反正以后肯定还要有报文交互,那flowmod下下去了来匹配转发来个host的报文,那怎么来保证你本次这个arp应答也被转发呢?所以这个时候设计者非常巧妙地又让这个报文通过Packet_out到table再次进入交换机pipline通道一次,以保证本次交互不需要其他动作也能成功
Ryu测试buffer_id完整app代码
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 |
from ryu.base import app_manager from ryu.controller.handler import CONFIG_DISPATCHER from ryu.controller.handler import set_ev_cls from ryu.controller import ofp_event import logging import time import itertools from ryu.ofproto import ofproto_v1_3 from ryu.lib import mac LOG = logging.getLogger("buffer_id_test") class buffer_id_test(app_manager.RyuApp): def __init__(self, *args, **kwargs): self.__name__ = "buffer_id_test" super(buffer_id_test, self).__init__(*args, **kwargs) @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def buffer_id_test(self, ev): datapath = ev.msg.datapath ofp = datapath.ofproto parser = datapath.ofproto_parser print "#######" print '''Test Start''' print "#######" print "#######" print '''step 1. + Add table_miss_flow''' print "#######" match = parser.OFPMatch() oas = [] oa = parser.OFPActionOutput(ofproto_v1_3.OFPP_CONTROLLER, ofproto_v1_3.OFPCML_MAX) oas.append(oa) inst = parser.OFPInstructionActions(ofproto_v1_3.OFPIT_APPLY_ACTIONS, oas) insts = [] insts.append(inst) fm = parser.OFPFlowMod(datapath, 0, 0, 0, # table 0 ofproto_v1_3.OFPFC_ADD, 0, 0, 0, # must have higher priority. 0xffffffff, ofproto_v1_3.OFPP_ANY, 0xffffffff, 0, match, insts) datapath.send_msg(fm) print "#######" print '''step 2. + Send pkt ip_dst=1.1.1.1,send to controller''' print "#######" ###这里报文自己拿工具去发,推荐scapy time.sleep(10) print "#######" print '''step 3_1.(Flow_mod) + Add Flow with buffer_id of 0x100''' print "#######" match = parser.OFPMatch() match.set_dl_type(int(int(0x800))) match.set_ipv4_dst(int(16843009)) oas = [] oa = parser.OFPActionOutput(6, ofproto_v1_3.OFPCML_MAX) oas.append(oa) inst = parser.OFPInstructionActions(ofproto_v1_3.OFPIT_APPLY_ACTIONS, oas) insts = [] insts.append(inst) fm = parser.OFPFlowMod(datapath, 0, 0, 0, # table 0 ofproto_v1_3.OFPFC_ADD, 0, 0, 10, # must have higher priority. 0x100, ofproto_v1_3.OFPP_ANY, 0xffffffff, 0, match, insts) datapath.send_msg(fm) print "#######" print '''step 3_2.(Packet_out) + Add Packet_out message with buffer_id of 0x100''' print "#######" oa = parser.OFPActionOutput(6, ofproto_v1_3.OFPCML_MAX) oas = [] oas.append(oa) #pkt="\x00\x00\x00\x01\x01\x01\x00\x00\x00\x02\x02\x02\x08\x00\x45\x111111111111111111111111111111111111" po = parser.OFPPacketOut(datapath, 0x100, 0, oas ) datapath.send_msg(po) |
总结思考
目前ovs针对报文buffer的做法是一个报文就对应一个buffer,不管是不是同一个报文,这样的坏处浪费了交换机buffer的资源,更加优化的做法是交换机收到相同报文只buffer一次并且只上送同一个buffer_id给控制器。
关于作者
- 邮件(jinl@centecnetworks.com)
- 作者(金利#盛科网络SDN组测试工程师)
--------------华丽的分割线------------------
本文系《SDNLAB原创文章奖励计划》投稿文章,该计划旨在鼓励广大从业人员在SDN/NFV/Cloud网络领域创新技术、开源项目、产业动态等方面进行经验和成果的文字传播、分享、交流。有意向投稿的同学请通过官方唯一指定投稿通道进行文章投递,投稿细则请参考《SDNLAB原创文章奖励计划》
注:投稿文章仅出于传递更多信息之目的,系SDNLAB《原创文章奖励计划》的投稿文章,仅供参考,不代表证实其描述或赞同其观点,投资者据此操作,风险自担;技术问题请留言指正。