sw test tool: Add support for throughput analysis

Signed-off-by: WATANABE Fumitaka <watanabe.fumitaka1@gmail.com>
Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Yuichi Ito 2014-03-28 13:25:25 +09:00 committed by FUJITA Tomonori
parent 1ff8957d70
commit 7e84cfac08

View File

@ -16,6 +16,7 @@
import inspect
import json
import logging
import math
import os
import signal
import sys
@ -86,6 +87,7 @@ CONTINUOUS_THREAD_INTVL = float(0.01) # sec
CONTINUOUS_PROGRESS_SPAN = 3 # sec
THROUGHPUT_PRIORITY = ofproto_v1_3.OFP_DEFAULT_PRIORITY+1
THROUGHPUT_COOKIE = THROUGHPUT_PRIORITY
THROUGHPUT_THRESHOLD = float(0.10) # expected throughput plus/minus 10 %
# Default settings for 'ingress: packets'
DEFAULT_DURATION_TIME = 30
@ -127,6 +129,7 @@ STATE_INIT_THROUGHPUT_FLOW = 13
STATE_THROUGHPUT_FLOW_INSTALL = 14
STATE_THROUGHPUT_FLOW_EXIST_CHK = 15
STATE_GET_THROUGHPUT = 16
STATE_THROUGHPUT_CHK = 17
STATE_DISCONNECTED = 99
@ -200,6 +203,8 @@ MSG = {STATE_INIT_FLOW:
STATE_GET_THROUGHPUT:
{TIMEOUT: 'Failed to request flow stats: request timeout.',
RCV_ERR: 'Failed to request flow stats: %(err_msg)s'},
STATE_THROUGHPUT_CHK:
{FAILURE: 'Received unexpected throughput: %(detail)s'},
STATE_DISCONNECTED:
{ERROR: 'Disconnected from switch'}}
@ -500,7 +505,8 @@ class OfTester(app_manager.RyuApp):
STATE_GET_MATCH_COUNT: self._test_get_match_count,
STATE_SEND_BARRIER: self._test_send_barrier,
STATE_FLOW_UNMATCH_CHK: self._test_flow_unmatching_check,
STATE_GET_THROUGHPUT: self._test_get_throughput}
STATE_GET_THROUGHPUT: self._test_get_throughput,
STATE_THROUGHPUT_CHK: self._test_throughput_check}
self.send_msg_xids = []
self.rcv_msgs = []
@ -858,6 +864,47 @@ class OfTester(app_manager.RyuApp):
result[str(stat.match)] = (stat.byte_count, stat.packet_count)
return (time.time(), result)
def _test_throughput_check(self, throughputs, start, end):
msgs = []
elapsed_sec = end[0] - start[0]
for throughput in throughputs:
match = str(throughput[KEY_FLOW].match)
# get oxm_fields of OFPMatch
fields = dict(throughput[KEY_FLOW].match._fields2)
if match not in start[1] or match not in end[1]:
raise TestError(self.state, match=match)
increased_bytes = end[1][match][0] - start[1][match][0]
increased_packets = end[1][match][1] - start[1][match][1]
if throughput[KEY_PKTPS]:
key = KEY_PKTPS
conv = 1
measured_value = increased_packets
unit = 'pktps'
elif throughput[KEY_KBPS]:
key = KEY_KBPS
conv = 1024 / 8 # Kilobits -> bytes
measured_value = increased_bytes
unit = 'kbps'
else:
raise RyuException(
'An invalid key exists that is neither "%s" nor "%s".'
% (KEY_KBPS, KEY_PKTPS))
expected_value = throughput[key] * elapsed_sec * conv
margin = expected_value * THROUGHPUT_THRESHOLD
self.logger.debug("measured_value:[%s]", measured_value)
self.logger.debug("expected_value:[%s]", expected_value)
self.logger.debug("margin:[%s]", margin)
if math.fabs(measured_value - expected_value) > margin:
msgs.append('{0} {1:.2f}{2}'.format(fields,
measured_value / elapsed_sec / conv, unit))
if msgs:
raise TestFailure(self.state, detail=', '.join(msgs))
def _wait(self):
""" Wait until specific OFP message received
or timer is exceeded. """