blob: c803a62282215997351b6f583b381bdb12657def [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# 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.
"""These tests fall under Conformance Test-Suite (OF-SWITCH-1.0.0 TestCases).
Refer Documentation -- Detailed testing methodology
<Some of test-cases are directly taken from oftest> """
"Test Suite 2 --> Openflow Protocol messages"
import logging
import unittest
import random
from oftest import config
import oftest.controller as controller
import ofp
import oftest.dataplane as dataplane
import oftest.parse as parse
import oftest.base_tests as base_tests
from oftest.testutils import *
from time import sleep
from FuncUtils import *
class FeaturesRequest(base_tests.SimpleProtocol):
"""Verify Features_Request-Reply is implemented
a) Send OFPT_FEATURES_REQUEST
b) Verify OFPT_FEATURES_REPLY is received without errors"""
def runTest(self):
logging.info("Running Features_Request test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Sending Features_Request")
logging.info("Expecting Features_Reply")
request = ofp.message.features_request()
self.controller.message_send(request)
(response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_FEATURES_REPLY,
timeout=2)
self.assertTrue(response is not None,
'Did not receive Features Reply')
class ConfigurationRequest(base_tests.SimpleProtocol):
"""Check basic Get Config request is implemented
a) Send OFPT_GET_CONFIG_REQUEST
b) Verify OFPT_GET_CONFIG_REPLY is received without errors"""
def runTest(self):
logging.info("Running Configuration_Request test ")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Sending OFPT_GET_CONFIG_REQUEST ")
logging.info("Expecting OFPT_GET_CONFIG_REPLY ")
request = ofp.message.get_config_request()
self.controller.message_send(request)
(response, pkt) = self.controller.poll(exp_msg=ofp.OFPT_GET_CONFIG_REPLY,
timeout=2)
self.assertTrue(response is not None,
'Did not receive OFPT_GET_CONFIG_REPLY')
class ModifyStateAdd(base_tests.SimpleProtocol):
"""Check basic Flow Add request is implemented
a) Send OFPT_FLOW_MOD , command = OFPFC_ADD
c) Send ofp_table_stats request , verify active_count=1 in reply"""
def runTest(self):
logging.info("Running Modify_State_Add test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Inserting a flow entry")
logging.info("Expecting active_count=1 in table_stats_reply")
#Insert a flow entry matching on ingress_port
(pkt,match) = wildcard_all_except_ingress(self,of_ports)
# Send Table_Stats_Request and verify flow gets inserted.
verify_tablestats(self,expect_active=1)
class ModifyStateDelete(base_tests.SimpleProtocol):
"""Check Basic Flow Delete request is implemented
a) Send OFPT_FLOW_MOD, command = OFPFC_ADD
b) Send ofp_table_stats request , verify active_count=1 in reply
c) Send OFPT_FLOW_MOD, command = OFPFC_DELETE
c) Send ofp_table_stats request , verify active_count=0 in reply"""
def runTest(self):
logging.info("Running Modify_State_Delete test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Inserting a flow entry and then deleting it")
logging.info("Expecting the active_count=0 in table_stats_reply")
#Insert a flow matching on ingress_port
(pkt,match) = wildcard_all_except_ingress(self,of_ports)
#Verify Flow inserted.
verify_tablestats(self,expect_active=1)
#Delete the flow
nonstrict_delete(self,match)
# Send Table_Stats_Request and verify flow deleted.
verify_tablestats(self,expect_active=0)
class ModifyStateModify(base_tests.SimpleDataPlane):
"""Verify basic Flow Modify request is implemented
a) Send OFPT_FLOW_MOD, command = OFPFC_ADD, Action A
b) Send OFPT_FLOW_MOD, command = OFPFC_MODIFY , with output action A'
c) Send a packet matching the flow, verify packet implements action A' """
def runTest(self):
logging.info("Running Modify_State_Modify test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Inserting a flow entry and then modifying it")
logging.info("Expecting the Test Packet to implement the modified action")
# Insert a flow matching on ingress_port with action A (output to of_port[1])
(pkt,match) = wildcard_all_except_ingress(self,of_ports)
# Modify the flow action (output to of_port[2])
modify_flow_action(self,of_ports,match)
# Send the Test Packet and verify action implemented is A' (output to of_port[2])
send_packet(self,pkt,of_ports[0],of_ports[2])
class ReadState(base_tests.SimpleProtocol):
"""Test that a basic Read state request (like flow_stats_get request) does not generate an error
a) Send OFPT_FLOW_MOD, command = OFPFC_ADD
b) Send ofp_flow_stats request
b) Verify switch replies without errors"""
def runTest(self):
logging.info("Running Read_State test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear switch state
delete_all_flows(self.controller)
logging.info("Inserting a flow entry and then sending flow_stats request")
logging.info("Expecting the a flow_stats_reply without errors")
# Insert a flow with match on ingress_port
(pkt,match ) = wildcard_all_except_ingress(self,of_ports)
#Verify Flow_Stats request does not generate errors
get_flowstats(self,match)
class PacketOut(base_tests.SimpleDataPlane):
"""Test packet out function
a) Send packet out message for each dataplane port.
b) Verify the packet appears on the appropriate dataplane port"""
def runTest(self):
logging.info("Running Packet_Out test")
of_ports = config["port_map"].keys()
of_ports.sort()
#Clear Switch state
delete_all_flows(self.controller)
logging.info("Sending a packet-out for each dataplane port")
logging.info("Expecting the packet on appropriate dataplane port")
for dp_port in of_ports:
for outpkt, opt in [
(simple_tcp_packet(), "simple TCP packet"),
(simple_eth_packet(), "simple Ethernet packet"),
(simple_eth_packet(pktlen=40), "tiny Ethernet packet")]:
msg = ofp.message.packet_out()
msg.data = str(outpkt)
act = ofp.action.output()
act.port = dp_port
msg.actions.append(act)
msg.buffer_id = 0xffffffff
logging.info("PacketOut to: " + str(dp_port))
self.controller.message_send(msg)
exp_pkt_arg = None
exp_port = None
if config["relax"]:
exp_pkt_arg = outpkt
exp_port = dp_port
(of_port, pkt, pkt_time) = self.dataplane.poll(timeout=2,
port_number=exp_port,
exp_pkt=exp_pkt_arg)
self.assertTrue(pkt is not None, 'Packet not received')
logging.info("PacketOut: got pkt from " + str(of_port))
if of_port is not None:
self.assertEqual(of_port, dp_port, "Unexpected receive port")
if not dataplane.match_exp_pkt(outpkt, pkt):
logging.debug("Sent %s" % format_packet(outpkt))
logging.debug("Resp %s" % format_packet(
str(pkt)[:len(str(outpkt))]))
self.assertEqual(str(outpkt), str(pkt)[:len(str(outpkt))],
'Response packet does not match send packet')
class PacketIn(base_tests.SimpleDataPlane):
"""Test basic packet_in function
a) Send a simple tcp packet to a dataplane port, without any flow-entry
b) Verify that a packet_in event is sent to the controller"""
def runTest(self):
logging.info("Running Packet_In test")
of_ports = config["port_map"].keys()
of_ports.sort()
ingress_port = of_ports[0]
#Clear Switch state
delete_all_flows(self.controller)
do_barrier(self.controller)
logging.info("Sending a Simple tcp packet a dataplane port")
logging.info("Expecting a packet_in event on the control plane")
# Send packet on dataplane port and verify packet_in event gets generated.
pkt = simple_tcp_packet()
self.dataplane.send(ingress_port, str(pkt))
logging.info("Sending packet to dp port " + str(ingress_port) +
", expecting packet_in on control plane" )
verify_packet_in(self, str(pkt), ingress_port, ofp.OFPR_NO_MATCH)
class EchoWithoutBody(base_tests.SimpleProtocol):
"""Test basic echo-reply is implemented
a) Send echo-request from the controller side, note echo body is empty here.
b) Verify switch responds back with echo-reply with same xid """
def runTest(self):
logging.info("Running Echo_Without_Body test")
logging.info("Sending Echo Request")
logging.info("Expecting a Echo Reply with version--1.0.0 and same xid")
# Send echo_request
request = ofp.message.echo_request()
(response, pkt) = self.controller.transact(request)
self.assertEqual(response.type, ofp.OFPT_ECHO_REPLY,'response is not echo_reply')
self.assertEqual(request.xid, response.xid,
'response xid != request xid')
self.assertTrue(response.version == 0x01, 'switch openflow-version field is not 1.0.1')
self.assertEqual(len(response.data), 0, 'response data non-empty')
class BarrierRequestReply(base_tests.SimpleProtocol):
""" Check basic Barrier request is implemented
a) Send OFPT_BARRIER_REQUEST
c) Verify OFPT_BARRIER_REPLY is recieved"""
def runTest(self):
logging.info("Running Barrier_Request_Reply test")
logging.info("Sending Barrier Request")
logging.info("Expecting a Barrier Reply with same xid")
#Send Barrier Request
request = ofp.message.barrier_request()
(response,pkt) = self.controller.transact(request)
self.assertEqual(response.type, ofp.OFPT_BARRIER_REPLY,'response is not barrier_reply')
self.assertEqual(request.xid, response.xid,
'response xid != request xid')