• SDN功能实现(五)修改Ryu源码实现自定义openflow基本字段(延迟更新)


    回顾:struct 类型表

    FormatC TypePython typeStandard sizeNotes
    x pad byte no value    
    c char string of length 1 1  
    b signed char integer 1 (3)
    B unsigned char integer 1 (3)
    ? _Bool bool 1 (1)
    h short integer 2 (3)
    H unsigned short integer 2 (3)
    i int integer 4 (3)
    I unsigned int integer 4 (3)
    l long integer 4 (3)
    L unsigned long integer 4 (3)
    q long long integer 8 (2), (3)
    Q unsigned long long integer 8 (2), (3)
    f float float 4 (4)
    d double float 8 (4)
    s char[] string 1  
    p char[] string    
    P void * integer   (5), (3)

    一:修改ofproto_v1_3.py中的_OFP_FLOW_MOD_PACK_STR0格式

    _OFP_FLOW_MOD_PACK_STR0 = 'QQBBHHHIIIH2xQQ' #8 8 1 1 2 2 2 4 4 4 2 2 8 8= 40 + 8 + 8 = 56
    OFP_FLOW_MOD_PACK_STR = '!' + _OFP_FLOW_MOD_PACK_STR0 + _OFP_MATCH_PACK_STR #_OFP_MATCH_PACK_STR = 'HHBBBB' 2 2 1 1 1 1 = 8
    OFP_FLOW_MOD_PACK_STR0 = '!' + _OFP_FLOW_MOD_PACK_STR0
    OFP_FLOW_MOD_SIZE = 72
    assert (calcsize(OFP_FLOW_MOD_PACK_STR) + OFP_HEADER_SIZE ==
            OFP_FLOW_MOD_SIZE) #OFP_HEADER_SIZE = 8

    “QQ”表示新自定义的两个字段effect_sec和effect_usec,各自占64位!!

    72表示OFP_FLOW_MOD_SIZE,为OFP_HEADER_SIZE=8 + _OFP_FLOW_MOD_PACK_STR0=56 + _OFP_MATCH_PACK_STR=8 === 72

    二:修改ofproto_v1_3_parser.py文件

    @_register_parser
    @_set_msg_type(ofproto.OFPT_FLOW_MOD)
    class OFPFlowMod(MsgBase):
        """
        Modify Flow entry message
    
        The controller sends this message to modify the flow table.
    
        ================ ======================================================
        Attribute        Description
        ================ ======================================================
        cookie           Opaque controller-issued identifier
        cookie_mask      Mask used to restrict the cookie bits that must match
                         when the command is ``OPFFC_MODIFY*`` or
                         ``OFPFC_DELETE*``
        table_id         ID of the table to put the flow in
        command          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 (or OFP_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
        ================ ======================================================
    
        Example::
    
            def send_flow_mod(self, datapath):
                ofp = datapath.ofproto
                ofp_parser = datapath.ofproto_parser
    
                cookie = cookie_mask = 0
                table_id = 0
                idle_timeout = hard_timeout = 0
                priority = 32768
                buffer_id = ofp.OFP_NO_BUFFER
                match = ofp_parser.OFPMatch(in_port=1, eth_dst='ff:ff:ff:ff:ff:ff')
                actions = [ofp_parser.OFPActionOutput(ofp.OFPP_NORMAL, 0)]
                inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
                                                         actions)]
                req = ofp_parser.OFPFlowMod(datapath, cookie, cookie_mask,
                                            table_id, ofp.OFPFC_ADD,
                                            idle_timeout, hard_timeout,
                                            priority, buffer_id,
                                            ofp.OFPP_ANY, ofp.OFPG_ANY,
                                            ofp.OFPFF_SEND_FLOW_REM,
                                            match, inst)
                datapath.send_msg(req)
        """
    
        def __init__(self, datapath, cookie=0, cookie_mask=0, table_id=0,
                     command=ofproto.OFPFC_ADD,
                     idle_timeout=0, hard_timeout=0,
                     priority=ofproto.OFP_DEFAULT_PRIORITY,
                     buffer_id=ofproto.OFP_NO_BUFFER,
                     out_port=0, out_group=0, flags=0,
                     effect_sec=0, effect_usec=0,
                     match=None,
                     instructions=None):
            instructions = instructions if instructions else []
            super(OFPFlowMod, self).__init__(datapath)
            self.cookie = cookie
            self.cookie_mask = cookie_mask
            self.table_id = table_id
            self.command = command
            self.idle_timeout = idle_timeout
            self.hard_timeout = hard_timeout
            self.priority = priority
            self.buffer_id = buffer_id
            self.out_port = out_port
            self.out_group = out_group
            self.flags = flags
            self.effect_sec = effect_sec
            self.effect_usec = effect_usec
            if match is None:
                match = OFPMatch()
            assert isinstance(match, OFPMatch)
            self.match = match
            for i in instructions:
                assert isinstance(i, OFPInstruction)
            self.instructions = instructions
    
        def _serialize_body(self):
            print("------_serialize_body------start-----------");
            print('======%d====%d=====',
                  self.effect_sec,self.effect_usec)
            print("------_serialize_body------end-----------");
            msg_pack_into(ofproto.OFP_FLOW_MOD_PACK_STR0, self.buf,
                          ofproto.OFP_HEADER_SIZE,
                          self.cookie, self.cookie_mask, self.table_id,
                          self.command, self.idle_timeout, self.hard_timeout,
                          self.priority, self.buffer_id, self.out_port,
                          self.out_group, self.flags, 
                          self.effect_sec,self.effect_usec)
    
            offset = (ofproto.OFP_FLOW_MOD_SIZE -
                      ofproto.OFP_MATCH_SIZE)
    
            match_len = self.match.serialize(self.buf, offset)
            offset += match_len
    
            for inst in self.instructions:
                inst.serialize(self.buf, offset)
                offset += inst.len
    
        @classmethod
        def parser(cls, datapath, version, msg_type, msg_len, xid, buf):
            msg = super(OFPFlowMod, cls).parser(
                datapath, version, msg_type, msg_len, xid, buf)
    
            (msg.cookie, msg.cookie_mask, msg.table_id,
             msg.command, msg.idle_timeout, msg.hard_timeout,
             msg.priority, msg.buffer_id, msg.out_port,
             msg.out_group, msg.flags, 
             msg.effect_sec, msg.effect_usec) = struct.unpack_from(
                ofproto.OFP_FLOW_MOD_PACK_STR0, msg.buf,
                ofproto.OFP_HEADER_SIZE)
    
            print("------parser------start-----------");
            print('======%d====%d=====',
                  msg.effect_sec, msg.effect_usec)
            print("------parser------end-----------");
            
            offset = ofproto.OFP_FLOW_MOD_SIZE - ofproto.OFP_HEADER_SIZE
    
            try:
                msg.match = OFPMatch.parser(buf, offset)
            except exception.OFPTruncatedMessage as e:
                msg.match = e.ofpmsg
                e.ofpmsg = msg
                raise e
    
            offset += utils.round_up(msg.match.length, 8)
    
            instructions = []
            try:
                while offset < msg_len:
                    i = OFPInstruction.parser(buf, offset)
                    instructions.append(i)
                    offset += i.len
            except exception.OFPTruncatedMessage as e:
                instructions.append(e.ofpmsg)
                msg.instructions = instructions
                e.ofpmsg = msg
                raise e
            except struct.error as e:
                msg.instructions = instructions
                raise exception.OFPTruncatedMessage(ofpmsg=msg,
                                                    residue=buf[offset:],
                                                    original_exception=e)
            msg.instructions = instructions
    
            return msg

    三:结合OVS+RYU实现openflow流表项的延迟更新

    (一)修改simple_switch_13.py代码,添加effect_sec字段

    # Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #    http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    # implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    from ryu.base import app_manager
    from ryu.controller import ofp_event
    from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
    from ryu.controller.handler import set_ev_cls
    from ryu.ofproto import ofproto_v1_3
    from ryu.lib.packet import packet
    from ryu.lib.packet import ethernet
    from ryu.lib.packet import ether_types
    
    
    class SimpleSwitch13(app_manager.RyuApp):
        OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    
        def __init__(self, *args, **kwargs):
            super(SimpleSwitch13, self).__init__(*args, **kwargs)
            self.mac_to_port = {}
    
        @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
        def switch_features_handler(self, ev):
            datapath = ev.msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            # install table-miss flow entry
            #
            # We specify NO BUFFER to max_len of the output action due to
            # OVS bug. At this moment, if we specify a lesser number, e.g.,
            # 128, OVS will send Packet-In with invalid buffer_id and
            # truncated packet data. In that case, we cannot output packets
            # correctly.  The bug has been fixed in OVS v2.1.0.
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                              ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)
    
        def add_flow(self, datapath, priority, match, actions, buffer_id=None):
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
    
            inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                                 actions)]
            if buffer_id:
                mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                        priority=priority, effect_sec=1625217050,
                                        match=match,
                                        instructions=inst)
            else:
                mod = parser.OFPFlowMod(datapath=datapath, priority=priority,effect_sec=1625217050,
                                        match=match, instructions=inst)
            datapath.send_msg(mod)
    
        @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
        def _packet_in_handler(self, ev):
            # If you hit this you might want to increase
            # the "miss_send_length" of your switch
            if ev.msg.msg_len < ev.msg.total_len:
                self.logger.debug("packet truncated: only %s of %s bytes",
                                  ev.msg.msg_len, ev.msg.total_len)
            msg = ev.msg
            datapath = msg.datapath
            ofproto = datapath.ofproto
            parser = datapath.ofproto_parser
            in_port = msg.match['in_port']
    
            pkt = packet.Packet(msg.data)
            eth = pkt.get_protocols(ethernet.ethernet)[0]
    
            if eth.ethertype == ether_types.ETH_TYPE_LLDP:
                # ignore lldp packet
                return
            dst = eth.dst
            src = eth.src
    
            dpid = format(datapath.id, "d").zfill(16)
            self.mac_to_port.setdefault(dpid, {})
    
            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 dst in self.mac_to_port[dpid]:
                out_port = self.mac_to_port[dpid][dst]
            else:
                out_port = ofproto.OFPP_FLOOD
    
            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, eth_src=src)
                # verify if we have a valid buffer_id, if yes avoid to send both
                # flow_mod & packet_out
                if msg.buffer_id != ofproto.OFP_NO_BUFFER:
                    self.add_flow(datapath, 1, match, actions, msg.buffer_id)
                    return
                else:
                    self.add_flow(datapath, 1, match, actions)
            data = None
            if msg.buffer_id == ofproto.OFP_NO_BUFFER:
                data = msg.data
    
            out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                                      in_port=in_port, actions=actions, data=data)
            datapath.send_msg(out)
    View Code

    (二)开启拓扑

    sudo mn --topo=linear,4 --controller=remote

    (三)查看控制器下发的延迟流表

    (四)查看OVS延迟更新的现象

     

    在流表为生效时,流表为空,当到达时间后,流表项插入,可以正常进行通信!!!

  • 相关阅读:
    mysql的安全漏洞的一种现象,就是利用转义字符把 ' ' 化没了,然后true 起作用啦
    maven项目中添加MySql依赖失败(以及maven的安装到maven项目的使用过程)
    mysql中的update(更新)与alter(更改)以及 change和modify的区别
    多线程:(充分利用定义任务后,开启多线程实现任务的理解)题目:模拟三个老师同时给50个小朋友发苹果,每个老师相当于一个线程。
    swing更改组件(删除后添加)得到心得:起码得刷新一下啊,可能还得再考虑重绘
    IE设置主页一直无果,尝试了右键软件看目标路径后缀无效,注册表也无效,最后在电脑管家里的工具浏览器保护搞定
    封装的localstorge的插件,store.js
    jquery.cookie用法详细解析,封装的操作cookie的库有jquery.cookie.js
    localstroge可以在页面间传递数值;
    移动开发阻止默认事件,1默认长按复制2拖动时页面默认移动
  • 原文地址:https://www.cnblogs.com/ssyfj/p/14964148.html
Copyright © 2020-2023  润新知