blob: 678758015a34bd0fb320c0dbfcbde304352f242a [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.
# Distributed under the OpenFlow Software License (see LICENSE)
# Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University
# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
"""
Flow stats test cases
These tests check the behavior of the flow stats request.
"""
import logging
import random
from oftest import config
import oftest.base_tests as base_tests
import ofp
import oftest.packet as scapy
from oftest.testutils import *
from oftest.parse import parse_ipv6
class AllFlowStats(base_tests.SimpleDataPlane):
"""
Retrieve all flows and verify the stats entries match the flow-mods sent
"""
def runTest(self):
port1, port2, port3 = openflow_ports(3)
table_id = test_param_get("table", 0)
delete_all_flows(self.controller)
flow1 = ofp.message.flow_add(
table_id=table_id,
priority=0x11,
idle_timeout=0x21,
hard_timeout=0x31,
flags=ofp.OFPFF_NO_PKT_COUNTS,
cookie=1,
match=ofp.match([
ofp.oxm.in_port(port1),
ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|1)]),
instructions=[
ofp.instruction.write_actions(
actions=[
ofp.action.output(
port=port1,
max_len=ofp.OFPCML_NO_BUFFER)])],
buffer_id=ofp.OFP_NO_BUFFER)
flow2 = ofp.message.flow_add(
table_id=table_id,
priority=0x12,
idle_timeout=0x22,
hard_timeout=0x32,
flags=ofp.OFPFF_NO_BYT_COUNTS,
cookie=2,
match=ofp.match([
ofp.oxm.in_port(port2),
ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|2)]),
instructions=[
ofp.instruction.write_actions(
actions=[
ofp.action.output(
port=port2,
max_len=ofp.OFPCML_NO_BUFFER)])],
buffer_id=ofp.OFP_NO_BUFFER)
flow3 = ofp.message.flow_add(
table_id=table_id,
priority=0x13,
idle_timeout=0x23,
hard_timeout=0x33,
flags=ofp.OFPFF_CHECK_OVERLAP,
cookie=3,
match=ofp.match([
ofp.oxm.in_port(port3),
ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|3)]),
instructions=[
ofp.instruction.write_actions(
actions=[
ofp.action.output(
port=port3,
max_len=ofp.OFPCML_NO_BUFFER)])],
buffer_id=ofp.OFP_NO_BUFFER)
flows = [flow1, flow2, flow3]
for flow in flows:
logging.debug(flow.show())
self.controller.message_send(flow)
flows_by_cookie = { flow.cookie: flow for flow in flows }
do_barrier(self.controller)
logging.info("Sending flow stats request")
stats = get_flow_stats(self, ofp.match())
logging.info("Received %d flow stats entries", len(stats))
seen_cookies = set()
for entry in stats:
logging.debug(entry.show())
self.assertTrue(entry.cookie in flows_by_cookie, "Unexpected cookie")
self.assertTrue(entry.cookie not in seen_cookies, "Duplicate cookie")
flow = flows_by_cookie[entry.cookie]
seen_cookies.add(entry.cookie)
self.assertEqual(entry.table_id, flow.table_id)
self.assertEqual(entry.priority, flow.priority)
self.assertEqual(entry.idle_timeout, flow.idle_timeout)
self.assertEqual(entry.hard_timeout, flow.hard_timeout)
self.assertEqual(entry.flags, flow.flags)
self.assertEqual(entry.cookie, flow.cookie)
self.assertEqual(sorted(entry.match.oxm_list), sorted(flow.match.oxm_list))
self.assertEqual(sorted(entry.instructions), sorted(flow.instructions))
self.assertEqual(seen_cookies, set([1,2,3]))
class CookieFlowStats(base_tests.SimpleDataPlane):
"""
Retrieve flows using various masks on the cookie
"""
def runTest(self):
delete_all_flows(self.controller)
# Also used as masks
cookies = [
0x0000000000000000,
0xDDDDDDDD00000000,
0x00000000DDDDDDDD,
0xDDDDDDDDDDDDDDDD,
0xDDDD0000DDDD0000,
0x0000DDDD0000DDDD,
0xDD00DD00DD00DD00,
0xD0D0D0D0D0D0D0D0,
0xF000000000000000,
0xFF00000000000000,
0xFFF0000000000000,
0xFFFF000000000000,
]
for i in range(0, 10):
cookies.append(random.getrandbits(64))
# Generate the matching cookies for each combination of cookie and mask
matches = {}
for mask in cookies:
for cookie in cookies:
matching = []
for cookie2 in cookies:
if cookie & mask == cookie2 & mask:
matching.append(cookie2)
matches[(cookie, mask)] = sorted(matching)
# Generate a flow for each cookie
flows = {}
table_id = test_param_get("table", 0)
for idx, cookie in enumerate(cookies):
flows[cookie] = ofp.message.flow_add(
table_id=table_id,
cookie=cookie,
match=ofp.match([ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT|idx)]),
buffer_id=ofp.OFP_NO_BUFFER)
# Install flows
for flow in flows.values():
self.controller.message_send(flow)
do_barrier(self.controller)
# For each combination of cookie and match, verify the correct flows
# are retrieved
for (cookie, mask), expected_cookies in matches.iteritems():
stats = get_flow_stats(self, ofp.match(), cookie=cookie, cookie_mask=mask)
received_cookies = sorted([entry.cookie for entry in stats])
logging.debug("expected 0x%016x/0x%016x: %s", cookie, mask,
' '.join(["0x%016x" % x for x in expected_cookies]))
logging.debug("received 0x%016x/0x%016x: %s", cookie, mask,
' '.join(["0x%016x" % x for x in received_cookies]))
self.assertEqual(expected_cookies, received_cookies)