test: add integrated OVS test suite

This patch adds a test framework with OVS to test various matches and
actions; adding various matches and actions and check `ovs-ofctl
dump-flows' output.

First, create 'br-tester' bridge:

fujita@rose:~$ sudo ovs-vsctl add-br br-tester

Secondly, configure the bridge to use the local controller:

fujita@rose:~$ sudo ovs-vsctl set-controller br-tester tcp:127.0.0.1

Thirdly, run what you want to test. If you want to try adding flows on
OF1.0:

fujita@rose:~$ ryu-manager --verbose --run_test_mod ryu.tests.integrated.test_add_flow_v10 ryu.tests.integrated.tester

This patch adds three test sets:

ryu.tests.integrated.test_add_flow_v10
ryu.tests.integrated.test_add_flow_v12_actions
ryu.tests.integrated.test_add_flow_v12_matches

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
FUJITA Tomonori 2012-07-19 17:35:53 +09:00
parent bdaafadc3f
commit 475ca44ef4
5 changed files with 4159 additions and 0 deletions

View File

@ -32,6 +32,7 @@ from ryu import utils
from ryu.app import wsgi
from ryu.base.app_manager import AppManager
from ryu.controller import controller
from ryu.tests.integrated import tester
FLAGS = gflags.FLAGS

View File

@ -0,0 +1,707 @@
# Copyright (C) 2012 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.
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import logging
from ryu.controller import handler
from ryu.controller.handler import set_ev_cls
from ryu.tests.integrated import tester
from ryu.ofproto import nx_match
LOG = logging.getLogger(__name__)
_target = 'br-tester'
class RunTest(tester.RunTestBase):
def __init__(self):
super(RunTest, self).__init__()
def send_flow_mod(self, rule, cookie, command, idle_timeout, hard_timeout,
priority=None, buffer_id=0xffffffff,
out_port=None, flags=0, actions=None):
if priority is None:
priority = self.ofproto.OFP_DEFAULT_PRIORITY
if out_port is None:
out_port = self.ofproto.OFPP_NONE
match_tuple = rule.match_tuple()
match = self.ofproto_parser.OFPMatch(*match_tuple)
flow_mod = self.ofproto_parser.OFPFlowMod(
self.datapath, match, cookie, command, idle_timeout, hard_timeout,
priority, buffer_id, out_port, flags, actions)
self.datapath.send_msg(flow_mod)
def test_action_output(self):
datapath = self.datapath
ofproto = self.ofproto
out_port = 2
self.set_val('out_port', out_port)
actions = [
datapath.ofproto_parser.OFPActionOutput(out_port),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_output(self):
ovs_actions = {}
out_port = self.get_val('out_port')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_out_port = ovs_actions['output']
except (KeyError, IndexError):
ovs_out_port = ''
if ovs_out_port == '' or int(ovs_out_port) != out_port:
err = 'send_actions=[output:%s] ovs_actions=[%s]' \
% (out_port, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_vlan_vid(self):
datapath = self.datapath
ofproto = self.ofproto
vlan_vid = 3
self.set_val('vlan_vid', vlan_vid)
actions = [
datapath.ofproto_parser.OFPActionVlanVid(vlan_vid),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_vlan_vid(self):
ovs_actions = {}
vlan_vid = self.get_val('vlan_vid')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_vlan_vid = ovs_actions['mod_vlan_vid']
except (KeyError, IndexError):
ovs_vlan_vid = ''
if ovs_vlan_vid == '' or int(ovs_vlan_vid) != vlan_vid:
err = 'send_actions=[vlan_vid:%s] ovs_actions=[%s]' \
% (vlan_vid, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_vlan_pcp(self):
datapath = self.datapath
ofproto = self.ofproto
vlan_pcp = 4
self.set_val('vlan_pcp', vlan_pcp)
actions = [
datapath.ofproto_parser.OFPActionVlanPcp(vlan_pcp),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_vlan_pcp(self):
ovs_actions = {}
vlan_pcp = self.get_val('vlan_pcp')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_vlan_pcp = ovs_actions['mod_vlan_pcp']
except (KeyError, IndexError):
ovs_vlan_pcp = ''
if ovs_vlan_pcp == '' or int(ovs_vlan_pcp) != vlan_pcp:
err = 'send_actions=[vlan_vid:%s] ovs_actions=[%s]' \
% (vlan_pcp, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_strip_vlan(self):
datapath = self.datapath
ofproto = self.ofproto
actions = [
datapath.ofproto_parser.OFPActionStripVlan(),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_strip_vlan(self):
ovs_actions = {}
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
except (KeyError, IndexError):
pass
if not 'strip_vlan' in ovs_actions:
err = 'send_actions=[strip_vlan] ovs_actions=[%s]' \
% (self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_dl_src(self):
datapath = self.datapath
ofproto = self.ofproto
dl_src = '56:b3:42:04:b2:7a'
self.set_val('dl_src', dl_src)
dl_src_bin = self.haddr_to_bin(dl_src)
actions = [
datapath.ofproto_parser.OFPActionSetDlSrc(dl_src_bin),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_dl_src(self):
ovs_actions = {}
dl_src = self.get_val('dl_src')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_dl_src = ovs_actions['mod_dl_src']
except (KeyError, IndexError):
ovs_dl_src = ''
if ovs_dl_src == '' or ovs_dl_src != dl_src:
err = 'send_actions=[dl_src:%s] ovs_actions=[%s]' \
% (dl_src, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_dl_dst(self):
datapath = self.datapath
ofproto = self.ofproto
dl_dst = 'c2:93:a2:fb:d0:f4'
self.set_val('dl_dst', dl_dst)
dl_dst_bin = self.haddr_to_bin(dl_dst)
actions = [
datapath.ofproto_parser.OFPActionSetDlDst(dl_dst_bin),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_dl_dst(self):
ovs_actions = {}
dl_dst = self.get_val('dl_dst')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_dl_dst = ovs_actions['mod_dl_dst']
except (KeyError, IndexError):
ovs_dl_dst = ''
if ovs_dl_dst == '' or ovs_dl_dst != dl_dst:
err = 'send_actions=[dl_dst:%s] ovs_actions=[%s]' \
% (dl_dst, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_nw_src(self):
datapath = self.datapath
ofproto = self.ofproto
nw_src = '216.132.81.105'
self.set_val('nw_src', nw_src)
nw_src_int = self.ipv4_to_int(nw_src)
actions = [
datapath.ofproto_parser.OFPActionSetNwSrc(nw_src_int),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_nw_src(self):
ovs_actions = {}
nw_src = self.get_val('nw_src')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_nw_src = ovs_actions['mod_nw_src']
except (KeyError, IndexError):
ovs_nw_src = ''
if ovs_nw_src == '' or ovs_nw_src != nw_src:
err = 'send_actions=[nw_src:%s] ovs_actions=[%s]' \
% (nw_src, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_nw_dst(self):
datapath = self.datapath
ofproto = self.ofproto
nw_dst = '223.201.206.3'
self.set_val('nw_dst', nw_dst)
nw_dst_int = self.ipv4_to_int(nw_dst)
actions = [
datapath.ofproto_parser.OFPActionSetNwDst(nw_dst_int),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_nw_dst(self):
ovs_actions = {}
nw_dst = self.get_val('nw_dst')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_nw_dst = ovs_actions['mod_nw_dst']
except (KeyError, IndexError):
ovs_nw_dst = ''
if ovs_nw_dst == '' or ovs_nw_dst != nw_dst:
err = 'send_actions=[nw_dst:%s] ovs_actions=[%s]' \
% (nw_dst, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_nw_tos(self):
datapath = self.datapath
ofproto = self.ofproto
nw_tos = 111
self.set_val('nw_tos', nw_tos)
actions = [
datapath.ofproto_parser.OFPActionSetNwTos(nw_tos),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_nw_tos(self):
ovs_actions = {}
nw_tos = self.get_val('nw_tos')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_nw_tos = ovs_actions['mod_nw_tos']
except (KeyError, IndexError):
ovs_nw_tos = ''
if ovs_nw_tos == '' or int(ovs_nw_tos) != nw_tos:
err = 'send_actions=[nw_tos:%s] ovs_actions=[%s]' \
% (nw_tos, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_tp_src(self):
datapath = self.datapath
ofproto = self.ofproto
tp_src = 55420
self.set_val('tp_src', tp_src)
actions = [
datapath.ofproto_parser.OFPActionSetTpSrc(tp_src),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_tp_src(self):
ovs_actions = {}
tp_src = self.get_val('tp_src')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_tp_src = ovs_actions['mod_tp_src']
except (KeyError, IndexError):
ovs_tp_src = ''
if ovs_tp_src == '' or int(ovs_tp_src) != tp_src:
err = 'send_actions=[tp_src:%s] ovs_actions=[%s]' \
% (tp_src, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_set_tp_dst(self):
datapath = self.datapath
ofproto = self.ofproto
tp_dst = 15430
self.set_val('tp_dst', tp_dst)
actions = [
datapath.ofproto_parser.OFPActionSetTpDst(tp_dst),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_set_tp_dst(self):
ovs_actions = {}
tp_dst = self.get_val('tp_dst')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_tp_dst = ovs_actions['mod_tp_dst']
except (KeyError, IndexError):
ovs_tp_dst = ''
if ovs_tp_dst == '' or int(ovs_tp_dst) != tp_dst:
err = 'send_actions=[tp_src:%s] ovs_actions=[%s]' \
% (tp_dst, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_action_enqueue(self):
datapath = self.datapath
ofproto = self.ofproto
port = 207
queue_id = 4287508753
self.set_val('enqueue', str(port) + 'q' + str(queue_id))
actions = [
datapath.ofproto_parser.OFPActionEnqueue(port, queue_id),
]
rule = nx_match.ClsRule()
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_action_enqueue(self):
ovs_actions = {}
enqueue = self.get_val('enqueue')
try:
ovs_actions = self.get_ovs_flows(_target)[0]['actions']
ovs_enqueue = ovs_actions['enqueue']
except (KeyError, IndexError):
ovs_enqueue = ''
if ovs_enqueue == '' or ovs_enqueue != enqueue:
err = 'send_actions=[enqueue:%s] ovs_actions=[%s]' \
% (enqueue, self.cnv_txt(ovs_actions))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_in_port(self):
datapath = self.datapath
ofproto = self.ofproto
in_port = 32
self.set_val('in_port', in_port)
actions = []
rule = nx_match.ClsRule()
rule.set_in_port(in_port)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_in_port(self):
ovs_rules = {}
in_port = self.get_val('in_port')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
ovs_in_port = ovs_rules['in_port']
except (KeyError, IndexError):
ovs_in_port = ''
if ovs_in_port == '' or int(ovs_in_port) != in_port:
err = 'send_rules=[in_port:%s] ovs_rules=[%s]' \
% (in_port, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_src(self):
datapath = self.datapath
ofproto = self.ofproto
dl_src = 'b8:a1:94:51:78:83'
self.set_val('dl_src', dl_src)
dl_src_bin = self.haddr_to_bin(dl_src)
actions = []
rule = nx_match.ClsRule()
rule.set_dl_src(dl_src_bin)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_src(self):
ovs_rules = {}
dl_src = self.get_val('dl_src')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
ovs_dl_src = ovs_rules['dl_src']
except (KeyError, IndexError):
ovs_dl_src = ''
if ovs_dl_src == '' or ovs_dl_src != dl_src:
err = 'send_rules=[dl_src:%s] ovs_rules=[%s]' \
% (dl_src, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_type_ip(self):
datapath = self.datapath
ofproto = self.ofproto
dl_type = nx_match.ETH_TYPE_IP
self.set_val('dl_type', 'ip')
actions = []
rule = nx_match.ClsRule()
rule.set_dl_type(dl_type)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_type_ip(self):
ovs_rules = {}
dl_type = self.get_val('dl_type')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
except (KeyError, IndexError):
pass
if not dl_type in ovs_rules:
err = 'send_rules=[dl_type:%s] ovs_rules=[%s]' \
% (dl_type, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_type_arp(self):
datapath = self.datapath
ofproto = self.ofproto
dl_type = nx_match.ETH_TYPE_ARP
self.set_val('dl_type', 'arp')
actions = []
rule = nx_match.ClsRule()
rule.set_dl_type(dl_type)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_type_arp(self):
ovs_rules = {}
dl_type = self.get_val('dl_type')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
except (KeyError, IndexError):
pass
if not dl_type in ovs_rules:
err = 'send_rules=[dl_type:%s] ovs_rules=[%s]' \
% (dl_type, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_type_vlan(self):
datapath = self.datapath
ofproto = self.ofproto
dl_type = nx_match.ETH_TYPE_VLAN
self.set_val('dl_type', nx_match.ETH_TYPE_VLAN)
actions = []
rule = nx_match.ClsRule()
rule.set_dl_type(dl_type)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_type_vlan(self):
ovs_rules = {}
dl_type = self.get_val('dl_type')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
ovs_dl_type = ovs_rules['dl_type']
except (KeyError, IndexError):
ovs_dl_type = ''
if ovs_dl_type == '' or int(ovs_dl_type, 16) != dl_type:
err = 'send_rules=[dl_src:%s] ovs_rules=[%s]' \
% (dl_type, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_type_ipv6(self):
datapath = self.datapath
ofproto = self.ofproto
dl_type = nx_match.ETH_TYPE_IPV6
self.set_val('dl_type', 'ipv6')
actions = []
rule = nx_match.ClsRule()
rule.set_dl_type(dl_type)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_type_ipv6(self):
ovs_rules = {}
dl_type = self.get_val('dl_type')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
except (KeyError, IndexError):
pass
if not dl_type in ovs_rules:
err = 'send_rules=[dl_type:%s] ovs_rules=[%s]' \
% (dl_type, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()
def test_rule_set_dl_type_lacp(self):
datapath = self.datapath
ofproto = self.ofproto
dl_type = nx_match.ETH_TYPE_LACP
self.set_val('dl_type', nx_match.ETH_TYPE_LACP)
actions = []
rule = nx_match.ClsRule()
rule.set_dl_type(dl_type)
self.send_flow_mod(
rule=rule, cookie=0, command=ofproto.OFPFC_ADD,
idle_timeout=0, hard_timeout=0,
priority=ofproto.OFP_DEFAULT_PRIORITY,
flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions)
def check_rule_set_dl_type_lacp(self):
ovs_rules = {}
dl_type = self.get_val('dl_type')
try:
ovs_rules = self.get_ovs_flows(_target)[0]['rules']
ovs_dl_type = ovs_rules['dl_type']
except (KeyError, IndexError):
ovs_dl_type = ''
if ovs_dl_type == '' or int(ovs_dl_type, 16) != dl_type:
err = 'send_rules=[dl_src:%s] ovs_rules=[%s]' \
% (dl_type, self.cnv_txt(ovs_rules))
self.results(ret=False, msg=err)
return
self.results()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,351 @@
# Copyright (C) 2012 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.
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import sys
import gflags
import logging
import subprocess
import traceback
from ryu import utils
from ryu.lib import mac
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller import dispatcher
from ryu.controller import event
from ryu.controller import handler
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import nx_match
from ryu.ofproto import ofproto_v1_0
from ryu.ofproto import ofproto_v1_2
LOG = logging.getLogger(__name__)
FLAGS = gflags.FLAGS
gflags.DEFINE_string('run_test_mod', '', 'Test run the module name.')
class EventRunTest(event.EventBase):
def __init__(self, datapath):
super(EventRunTest, self).__init__()
self.datapath = datapath
QUEUE_NAME_RUN_TEST_EV = 'run_test_event'
DISPATCHER_NAME_RUN_TEST_EV = 'run_test_event'
RUN_TEST_EV_DISPATCHER = dispatcher.EventDispatcher(
DISPATCHER_NAME_RUN_TEST_EV)
LOG_TEST_START = 'TEST_START: %s'
LOG_TEST_RESULTS = 'TEST_RESULTS:'
LOG_TEST_FINISH = 'TEST_FINISHED: Completed=[%s], OK=[%s], NG=[%s]'
class Tester(app_manager.RyuApp):
def __init__(self, *args, **kwargs):
super(Tester, self).__init__()
self.ev_q = dispatcher.EventQueue(QUEUE_NAME_RUN_TEST_EV,
RUN_TEST_EV_DISPATCHER)
run_test_mod = utils.import_module(FLAGS.run_test_mod)
LOG.debug('import run_test_mod.[%s]', run_test_mod.__name__)
self.run_test = run_test_mod.RunTest(*args, **kwargs)
handler.register_instance(self.run_test)
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
send_delete_all_flows(datapath)
datapath.send_barrier()
@set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
def barrier_replay_handler(self, ev):
self.ev_q.queue(EventRunTest(ev.msg.datapath))
@set_ev_cls(EventRunTest, RUN_TEST_EV_DISPATCHER)
def run_test_halder(self, ev):
dp = ev.datapath
t = self.run_test
if not t._test_started():
t._test_init(dp)
if not self._run_test(t):
# run_test was throwing exception.
LOG.info(LOG_TEST_FINISH, False, t._RESULTS_OK, t._RESULTS_NG)
return
if not t._test_completed():
t.datapath.send_barrier()
return
# Completed all tests.
LOG.info(LOG_TEST_FINISH, True, t._RESULTS_OK, t._RESULTS_NG)
def _run_test(self, t):
running = t._running()
if len(running) == 0:
# next test
name = t._pop_test()
LOG.info(LOG_TEST_START, name)
try:
getattr(t, name)()
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value,
exc_traceback, file=sys.stdout)
send_delete_all_flows(t.datapath)
return False
else:
# check
name = 'check_' + running[5:]
if not name in dir(t):
name = '_check_default'
err = 0
try:
# LOG.debug('_run_test: CHECK_TEST = [%s]', name)
getattr(t, name)()
except Exception:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value,
exc_traceback, file=sys.stdout)
err = 1
finally:
send_delete_all_flows(t.datapath)
if err:
return False
t._check_run()
return True
def _send_delete_all_flows_v10(dp):
rule = nx_match.ClsRule()
match = dp.ofproto_parser.OFPMatch(dp.ofproto.OFPFW_ALL,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0)
m = dp.ofproto_parser.OFPFlowMod(
dp, match, 0,
dp.ofproto.OFPFC_DELETE,
0, 0, 0, 0,
dp.ofproto.OFPP_NONE, 0, None)
dp.send_msg(m)
def _send_delete_all_flows_v12(dp):
match = dp.ofproto_parser.OFPMatch()
inst = []
m = dp.ofproto_parser.OFPFlowMod(dp, 0, 0, 0,
dp.ofproto.OFPFC_DELETE,
0, 0, 0, 0,
dp.ofproto.OFPP_ANY, 0xffffffff,
0, match, inst)
dp.send_msg(m)
def send_delete_all_flows(dp):
assert dp.ofproto in (ofproto_v1_0, ofproto_v1_2)
if dp.ofproto == ofproto_v1_0:
_send_delete_all_flows_v10(dp)
elif dp.ofproto == ofproto_v1_2:
_send_delete_all_flows_v12(dp)
else:
# this function will be remove.
dp.send_delete_all_flows()
def run_command(cmd, redirect_output=True, check_exit_code=True, env=None):
if redirect_output:
stdout = subprocess.PIPE
else:
stdout = None
proc = subprocess.Popen(cmd, stdout=stdout,
stderr=subprocess.STDOUT, env=env)
output = proc.communicate()[0]
LOG.debug('Exec command "%s" \n%s', ' '.join(cmd), output)
if check_exit_code and proc.returncode != 0:
raise Exception('Command "%s" failed.\n%s' % (' '.join(cmd), output))
return output
class RunTestBase(object):
"""
To run the tests is required for the following pair of functions.
1. test_<test name>()
To send flows to switch.
2. check_<test name>() or _check_default()
To check flows of switch.
To deal common values to the functions(test_ and check_)
can use `set_val('name', val)` and `get_val('name')`.
This values is initialized before the next tests.
"""
def __init__(self):
super(RunTestBase, self).__init__()
self._TEST_STARTED = False
self._TESTS = []
self._RUNNING = ''
self._RESULTS_OK = 0
self._RESULTS_NG = 0
self._CHECK = {}
def _test_started(self):
return self._TEST_STARTED
def _test_init(self, dp):
self.datapath = dp
self.ofproto = dp.ofproto
self.ofproto_parser = dp.ofproto_parser
for name in dir(self):
if name.startswith("test_"):
self._TESTS.append(name)
self._TEST_STARTED = True
def _test_completed(self):
if self._TEST_STARTED:
if len(self._RUNNING) + len(self._TESTS) == 0:
return True
return False
def _pop_test(self):
self._RUNNING = self._TESTS.pop()
return self._RUNNING
def _running(self):
return self._RUNNING
def _check_run(self):
self._RUNNING = ''
def _check_default(self):
err = 'function %s() is not found.' % (self._RUNNING, )
self.results(ret=False, msg=err)
def results(self, name=None, ret=True, msg=''):
if not name:
name = self._RUNNING
if ret:
res = 'OK'
self._RESULTS_OK += 1
else:
res = 'NG'
self._RESULTS_NG += 1
LOG.info('%s %s [%s] %s', LOG_TEST_RESULTS, name, res, '\n' + msg)
def set_val(self, name, val):
self._CHECK[name] = val
def get_val(self, name):
return self._CHECK[name]
def del_val(self, name):
del self._CHECK[name]
def del_val_all(self):
self._CHECK.clear()
def get_ovs_flows(self, target):
# flows (return):
# [flow1, flow2,...]
# flow:
# {'actions': actions, 'rules': rules}
# or {'apply_actions': actions, 'rules': rules}
# or {'write_actions': actions, 'rules': rules}
# or {'clear_actions': actions, 'rules': rules}
# actions, rules:
# {'<name>': <val>}
cmd = ('sudo', 'ovs-ofctl', 'dump-flows', target)
output = run_command(cmd)
flows = []
for line in output.splitlines():
if line.startswith(" "):
flow = {}
rules, actions = line.split('actions=')
rules = self.cnv_list(rules, '=')
if actions.startswith("apply_actions"):
a_name = 'apply_actions'
actions = actions[len(a_name) + 1:-1]
elif actions.startswith("write_actions"):
a_name = 'write_actions'
actions = actions[len(a_name) + 1:-1]
elif actions.startswith("clear_actions"):
a_name = 'clear_actions'
actions = actions[len(a_name) + 1:-1]
else:
a_name = 'actions'
actions = self.cnv_list(actions, ':')
flows.append({'rules': rules, a_name: actions, })
return flows
def cnv_list(self, tmp, sep):
list_ = {}
for p in tmp.split(','):
if len(p.strip()) == 0:
continue
if p.find(sep) > 0:
name, val = p.strip().split(sep, 1)
else:
name = val = p.strip()
list_[name] = val
return list_
def cnv_txt(self, tmp, sep='='):
return ",".join([(str(x) + sep + str(tmp[x])) for x in tmp if x >= 0])
def haddr_to_str(self, addr):
return mac.haddr_to_str(addr)
def haddr_to_bin(self, string):
return mac.haddr_to_bin(string)
def ipv4_to_int(self, string):
ip = string.split('.')
assert len(ip) == 4
i = 0
for b in ip:
b = int(b)
i = (i << 8) | b
return i
def ipv6_to_int(self, string):
ip = string.split(':')
assert len(ip) == 8
return [int(x, 16) for x in ip]