Featured image of post 测量SDN控制器控制时延

测量SDN控制器控制时延

测试控制器到交换机之间的Echo往返时延

时延测量原理

测试控制器到交换机之间的Echo往返时延,其测量方法是通过在控制器给交换机发送携带有时间戳的Echo_request报文,然后解析交换机返回的Echo_reply,并用当下时间减去解析出的发送时间,获得往返时间差

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 每隔3秒进行控制器向交换机发送一次Echo报文以获取往返时延
def _measure(self):
    SLEEP_PERIOD = 3
    while True:
        self._send_echo_request()
        hub.sleep(SLEEP_PERIOD)

def _send_echo_request(self):
    for datapath in self.datapaths.values():
        parser = datapath.ofproto_parser
        data = bytes("%.12f" % time.time(), encoding="utf8")
        echo_req = parser.OFPEchoRequest(datapath, data=data)
        datapath.send_msg(echo_req)
        hub.sleep(0.5)

@set_ev_cls(ofp_event.EventOFPEchoReply, MAIN_DISPATCHER)
def echo_reply_handler(self, ev):
    latency = time.time() - eval(ev.msg.data)
    latency = latency * 1000
    print("Delay of", ev.msg.datapath.id, "is", latency, "ms")

完整代码

  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
 99
100
101
102
103
104
105
106
107
108
# 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 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 import hub
import time

class SimpleSwitch13(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        super(SimpleSwitch13, self).__init__(*args, **kwargs)
        self.datapaths = {}
        self.detector_thread = hub.spawn(self._measure)

    # 处理交换机连接
    @set_ev_cls(ofp_event.EventOFPStateChange, MAIN_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        # 交换机新连接
        if ev.state == MAIN_DISPATCHER:
            # 断言dpid存在
            assert datapath.id is not None
            print("Switch Coming", datapath.id)
            self.datapaths[datapath.id] = datapath
            # 为交换机的流表新增Table-miss Flow Entry项 用于在无法匹配到流表项后与之匹配
            # match表示匹配约束 为空则说明可以匹配所有封包
            # action表示匹配成功后执行的操作为向Controller端口发送最大数据长度的封包
            # OFPCML_NO_BUFFER表示不需要在交换机上缓存封包将封包整体发给controller
            # 优先级为0 即最低的优先权
            match = parser.OFPMatch()
            actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                              ofproto.OFPCML_NO_BUFFER)]
            self.add_flow(datapath, 0, match, actions)

    # 每隔3秒进行控制器向交换机发送一次Echo报文以获取往返时延
    def _measure(self):
        SLEEP_PERIOD = 3
        while True:
            self._send_echo_request()
            hub.sleep(SLEEP_PERIOD)

    def _send_echo_request(self):
        for datapath in self.datapaths.values():
            parser = datapath.ofproto_parser
            data = bytes("%.12f" % time.time(), encoding="utf8")
            echo_req = parser.OFPEchoRequest(datapath, data=data)
            datapath.send_msg(echo_req)
            hub.sleep(0.5)

    @set_ev_cls(ofp_event.EventOFPEchoReply, MAIN_DISPATCHER)
    def echo_reply_handler(self, ev):
        latency = time.time() - eval(ev.msg.data)
        latency = latency * 1000
        print("Delay of", ev.msg.datapath.id, "is", latency, "ms")

    # 用于添加流表项的工具函数
    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,
                                    match=match,
                                    instructions=inst)
        else:
            mod = parser.OFPFlowMod(datapath=datapath,
                                    priority=priority,
                                    match=match,
                                    instructions=inst)
        datapath.send_msg(mod)

    # 控制器接收到Packet-In消息
    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        in_port = msg.match['in_port']
        # print("Recv PACKET_IN", datapath.id,"from",in_port)

        pkt = packet.Packet(msg.data)
        eth = pkt.get_protocols(ethernet.ethernet)[0]
        # print("Eth pkt: {0}".format(eth))

有负载情况下测试

测出的时间为:控制器到达交换机的往返时延+控制器发送排队时延+交换机处理时延+交换机接收发送排队时延

为交换机设置的流表规则为:当有数据包到达交换机时,上报控制器

在测试的同时,主机1使用Iperf不断向网络注入流量

峰值为5ms,平均在1~2ms

无负载情况下测试

该测试环境下,移除全部主机连接,为交换机设置流表规则为丢包

测试结果为:平均1ms,峰值2~3ms

Licensed under CC BY-NC-SA 4.0
皖ICP备2025083746号-1
公安备案 陕公网安备61019002003315号



使用 Hugo 构建
主题 StackJimmy 设计