Openflow细节理解之—Buffer_id篇

时间:2022-05-06
本文章向大家介绍Openflow细节理解之—Buffer_id篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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代码

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="x00x00x00x01x01x01x00x00x00x02x02x02x08x00x45x111111111111111111111111111111111111"
        po = parser.OFPPacketOut(datapath, 0x100, 0,
                                              oas
                                              )
        datapath.send_msg(po)

总结思考

目前ovs针对报文buffer的做法是一个报文就对应一个buffer,不管是不是同一个报文,这样的坏处浪费了交换机buffer的资源,更加优化的做法是交换机收到相同报文只buffer一次并且只上送同一个buffer_id给控制器。