363 lines
15 KiB
Python
363 lines
15 KiB
Python
# Copyright (c) 2015 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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.
|
|
|
|
import copy
|
|
|
|
import mock
|
|
from neutron_lib import constants
|
|
from oslo_utils import uuidutils
|
|
import testscenarios
|
|
|
|
from neutron.api.rpc.callbacks.consumer import registry as consumer_reg
|
|
from neutron.api.rpc.callbacks import events
|
|
from neutron.api.rpc.callbacks import resources
|
|
from neutron.objects.qos import policy
|
|
from neutron.objects.qos import rule
|
|
from neutron.tests.common.agents import l2_extensions
|
|
from neutron.tests.functional.agent.l2 import base
|
|
|
|
|
|
load_tests = testscenarios.load_tests_apply_scenarios
|
|
|
|
TEST_POLICY_ID1 = "a2d72369-4246-4f19-bd3c-af51ec8d70cd"
|
|
TEST_POLICY_ID2 = "46ebaec0-0570-43ac-82f6-60d2b03168c5"
|
|
TEST_DSCP_MARK_1 = 14
|
|
TEST_DSCP_MARK_2 = 30
|
|
|
|
|
|
class OVSAgentQoSExtensionTestFramework(base.OVSAgentTestFramework):
|
|
|
|
test_dscp_marking_rule_1 = rule.QosDscpMarkingRule(
|
|
context=None,
|
|
qos_policy_id=TEST_POLICY_ID1,
|
|
id="9f126d84-551a-4dcf-bb01-0e9c0df0c793",
|
|
dscp_mark=TEST_DSCP_MARK_1)
|
|
test_dscp_marking_rule_2 = rule.QosDscpMarkingRule(
|
|
context=None,
|
|
qos_policy_id=TEST_POLICY_ID2,
|
|
id="7f126d84-551a-4dcf-bb01-0e9c0df0c793",
|
|
dscp_mark=TEST_DSCP_MARK_2)
|
|
test_bw_limit_rule_1 = rule.QosBandwidthLimitRule(
|
|
context=None,
|
|
qos_policy_id=TEST_POLICY_ID1,
|
|
id="5f126d84-551a-4dcf-bb01-0e9c0df0c793",
|
|
max_kbps=1000,
|
|
max_burst_kbps=10)
|
|
test_bw_limit_rule_2 = rule.QosBandwidthLimitRule(
|
|
context=None,
|
|
qos_policy_id=TEST_POLICY_ID2,
|
|
id="fa9128d9-44af-49b2-99bb-96548378ad42",
|
|
max_kbps=900,
|
|
max_burst_kbps=9)
|
|
|
|
def setUp(self):
|
|
super(OVSAgentQoSExtensionTestFramework, self).setUp()
|
|
self.config.set_override('extensions', ['qos'], 'agent')
|
|
self._set_pull_mock()
|
|
self.set_test_qos_rules(TEST_POLICY_ID1,
|
|
[self.test_bw_limit_rule_1,
|
|
self.test_dscp_marking_rule_1])
|
|
self.set_test_qos_rules(TEST_POLICY_ID2,
|
|
[self.test_bw_limit_rule_2,
|
|
self.test_dscp_marking_rule_2])
|
|
|
|
def _set_pull_mock(self):
|
|
|
|
self.qos_policies = {}
|
|
|
|
def _pull_mock(context, resource_type, resource_id):
|
|
return self.qos_policies[resource_id]
|
|
|
|
self.pull = mock.patch(
|
|
'neutron.api.rpc.handlers.resources_rpc.'
|
|
'ResourcesPullRpcApi.pull').start()
|
|
self.pull.side_effect = _pull_mock
|
|
|
|
def set_test_qos_rules(self, policy_id, policy_rules):
|
|
"""This function sets the policy test rules to be exposed."""
|
|
|
|
qos_policy = policy.QosPolicy(
|
|
context=None,
|
|
project_id=uuidutils.generate_uuid(),
|
|
id=policy_id,
|
|
name="Test Policy Name",
|
|
description="This is a policy for testing purposes",
|
|
shared=False,
|
|
rules=policy_rules)
|
|
|
|
qos_policy.obj_reset_changes()
|
|
self.qos_policies[policy_id] = qos_policy
|
|
|
|
def _create_test_port_dict(self, policy_id=None):
|
|
port_dict = super(OVSAgentQoSExtensionTestFramework,
|
|
self)._create_test_port_dict()
|
|
port_dict['qos_policy_id'] = policy_id
|
|
port_dict['network_qos_policy_id'] = None
|
|
return port_dict
|
|
|
|
def _get_device_details(self, port, network):
|
|
dev = super(OVSAgentQoSExtensionTestFramework,
|
|
self)._get_device_details(port, network)
|
|
dev['qos_policy_id'] = port['qos_policy_id']
|
|
return dev
|
|
|
|
def _assert_bandwidth_limit_rule_is_set(self, port, rule):
|
|
if rule.direction == constants.INGRESS_DIRECTION:
|
|
max_rate, burst = (
|
|
self.agent.int_br.get_ingress_bw_limit_for_port(
|
|
port['vif_name']))
|
|
else:
|
|
max_rate, burst = (
|
|
self.agent.int_br.get_egress_bw_limit_for_port(
|
|
port['vif_name']))
|
|
self.assertEqual(max_rate, rule.max_kbps)
|
|
self.assertEqual(burst, rule.max_burst_kbps)
|
|
|
|
def _assert_bandwidth_limit_rule_not_set(self, port, rule_direction):
|
|
if rule_direction == constants.INGRESS_DIRECTION:
|
|
max_rate, burst = (
|
|
self.agent.int_br.get_ingress_bw_limit_for_port(
|
|
port['vif_name']))
|
|
else:
|
|
max_rate, burst = (
|
|
self.agent.int_br.get_egress_bw_limit_for_port(
|
|
port['vif_name']))
|
|
self.assertIsNone(max_rate)
|
|
self.assertIsNone(burst)
|
|
|
|
def wait_until_bandwidth_limit_rule_applied(self, port, rule):
|
|
if rule and rule.direction == constants.INGRESS_DIRECTION:
|
|
l2_extensions.wait_until_ingress_bandwidth_limit_rule_applied(
|
|
self.agent.int_br, port['vif_name'], rule)
|
|
else:
|
|
l2_extensions.wait_until_egress_bandwidth_limit_rule_applied(
|
|
self.agent.int_br, port['vif_name'], rule)
|
|
|
|
def _assert_dscp_marking_rule_is_set(self, port, dscp_rule):
|
|
port_num = self.agent.int_br._get_port_val(port['vif_name'], 'ofport')
|
|
|
|
flows = self.agent.int_br.dump_flows_for(table='0',
|
|
in_port=str(port_num))
|
|
tos_mark = l2_extensions.extract_mod_nw_tos_action(flows)
|
|
self.assertEqual(dscp_rule.dscp_mark << 2, tos_mark)
|
|
|
|
def _assert_dscp_marking_rule_not_set(self, port):
|
|
port_num = self.agent.int_br._get_port_val(port['vif_name'], 'ofport')
|
|
|
|
flows = self.agent.int_br.dump_flows_for(table='0',
|
|
in_port=str(port_num))
|
|
|
|
tos_mark = l2_extensions.extract_mod_nw_tos_action(flows)
|
|
self.assertIsNone(tos_mark)
|
|
|
|
def wait_until_dscp_marking_rule_applied(self, port, dscp_mark):
|
|
l2_extensions.wait_until_dscp_marking_rule_applied_ovs(
|
|
self.agent.int_br, port['vif_name'], dscp_mark)
|
|
|
|
def _create_port_with_qos(self):
|
|
port_dict = self._create_test_port_dict()
|
|
port_dict['qos_policy_id'] = TEST_POLICY_ID1
|
|
self.setup_agent_and_ports([port_dict])
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
self.wait_until_bandwidth_limit_rule_applied(port_dict,
|
|
self.test_bw_limit_rule_1)
|
|
return port_dict
|
|
|
|
|
|
class TestOVSAgentQosExtension(OVSAgentQoSExtensionTestFramework):
|
|
|
|
scenarios = [
|
|
('ingress', {'direction': constants.INGRESS_DIRECTION}),
|
|
('egress', {'direction': constants.EGRESS_DIRECTION})
|
|
]
|
|
|
|
def setUp(self):
|
|
super(TestOVSAgentQosExtension, self).setUp()
|
|
self.test_bw_limit_rule_1.direction = self.direction
|
|
self.test_bw_limit_rule_2.direction = self.direction
|
|
|
|
@property
|
|
def reverse_direction(self):
|
|
if self.direction == constants.INGRESS_DIRECTION:
|
|
return constants.EGRESS_DIRECTION
|
|
elif self.direction == constants.EGRESS_DIRECTION:
|
|
return constants.INGRESS_DIRECTION
|
|
|
|
def test_port_creation_with_bandwidth_limit(self):
|
|
"""Make sure bandwidth limit rules are set in low level to ports."""
|
|
|
|
self.setup_agent_and_ports(
|
|
port_dicts=self.create_test_ports(amount=1,
|
|
policy_id=TEST_POLICY_ID1))
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
for port in self.ports:
|
|
self._assert_bandwidth_limit_rule_is_set(
|
|
port, self.test_bw_limit_rule_1)
|
|
|
|
def test_port_creation_with_bandwidth_limits_both_directions(self):
|
|
"""Make sure bandwidth limit rules are set in low level to ports.
|
|
|
|
This test is checking applying rules for both possible
|
|
directions at once
|
|
"""
|
|
|
|
reverse_direction_bw_limit_rule = copy.deepcopy(
|
|
self.test_bw_limit_rule_1)
|
|
reverse_direction_bw_limit_rule.direction = self.reverse_direction
|
|
self.qos_policies[TEST_POLICY_ID1].rules.append(
|
|
reverse_direction_bw_limit_rule)
|
|
|
|
self.setup_agent_and_ports(
|
|
port_dicts=self.create_test_ports(amount=1,
|
|
policy_id=TEST_POLICY_ID1))
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
for port in self.ports:
|
|
self._assert_bandwidth_limit_rule_is_set(
|
|
port, self.test_bw_limit_rule_1)
|
|
self._assert_bandwidth_limit_rule_is_set(
|
|
port, reverse_direction_bw_limit_rule)
|
|
|
|
def test_port_creation_with_different_bandwidth_limits(self):
|
|
"""Make sure different types of policies end on the right ports."""
|
|
|
|
port_dicts = self.create_test_ports(amount=3)
|
|
|
|
port_dicts[0]['qos_policy_id'] = TEST_POLICY_ID1
|
|
port_dicts[1]['qos_policy_id'] = TEST_POLICY_ID2
|
|
|
|
self.setup_agent_and_ports(port_dicts)
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
self._assert_bandwidth_limit_rule_is_set(self.ports[0],
|
|
self.test_bw_limit_rule_1)
|
|
|
|
self._assert_bandwidth_limit_rule_is_set(self.ports[1],
|
|
self.test_bw_limit_rule_2)
|
|
|
|
self._assert_bandwidth_limit_rule_not_set(self.ports[2],
|
|
self.direction)
|
|
|
|
def test_port_creation_with_dscp_marking(self):
|
|
"""Make sure dscp marking rules are set in low level to ports."""
|
|
|
|
self.setup_agent_and_ports(
|
|
port_dicts=self.create_test_ports(amount=1,
|
|
policy_id=TEST_POLICY_ID1))
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
for port in self.ports:
|
|
self._assert_dscp_marking_rule_is_set(
|
|
port, self.test_dscp_marking_rule_1)
|
|
|
|
def test_port_creation_with_different_dscp_markings(self):
|
|
"""Make sure different types of policies end on the right ports."""
|
|
|
|
port_dicts = self.create_test_ports(amount=3)
|
|
|
|
port_dicts[0]['qos_policy_id'] = TEST_POLICY_ID1
|
|
port_dicts[1]['qos_policy_id'] = TEST_POLICY_ID2
|
|
|
|
self.setup_agent_and_ports(port_dicts)
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
self._assert_dscp_marking_rule_is_set(self.ports[0],
|
|
self.test_dscp_marking_rule_1)
|
|
|
|
self._assert_dscp_marking_rule_is_set(self.ports[1],
|
|
self.test_dscp_marking_rule_2)
|
|
|
|
self._assert_dscp_marking_rule_not_set(self.ports[2])
|
|
|
|
def test_simple_port_policy_update(self):
|
|
self.setup_agent_and_ports(
|
|
port_dicts=self.create_test_ports(amount=1,
|
|
policy_id=TEST_POLICY_ID1))
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
self._assert_dscp_marking_rule_is_set(self.ports[0],
|
|
self.test_dscp_marking_rule_1)
|
|
policy_copy = copy.deepcopy(self.qos_policies[TEST_POLICY_ID1])
|
|
policy_copy.rules[0].max_kbps = 500
|
|
policy_copy.rules[0].max_burst_kbps = 5
|
|
policy_copy.rules[1].dscp_mark = TEST_DSCP_MARK_2
|
|
context = mock.Mock()
|
|
consumer_reg.push(context, resources.QOS_POLICY,
|
|
[policy_copy], events.UPDATED)
|
|
self.wait_until_bandwidth_limit_rule_applied(self.ports[0],
|
|
policy_copy.rules[0])
|
|
self._assert_bandwidth_limit_rule_is_set(self.ports[0],
|
|
policy_copy.rules[0])
|
|
self._assert_dscp_marking_rule_is_set(self.ports[0],
|
|
self.test_dscp_marking_rule_2)
|
|
|
|
def test_simple_port_policy_update_change_bw_limit_direction(self):
|
|
self.setup_agent_and_ports(
|
|
port_dicts=self.create_test_ports(amount=1,
|
|
policy_id=TEST_POLICY_ID1))
|
|
self.wait_until_ports_state(self.ports, up=True)
|
|
|
|
self._assert_bandwidth_limit_rule_is_set(self.ports[0],
|
|
self.test_bw_limit_rule_1)
|
|
self._assert_bandwidth_limit_rule_not_set(self.ports[0],
|
|
self.reverse_direction)
|
|
|
|
policy_copy = copy.deepcopy(self.qos_policies[TEST_POLICY_ID1])
|
|
policy_copy.rules[0].direction = self.reverse_direction
|
|
context = mock.Mock()
|
|
consumer_reg.push(context, resources.QOS_POLICY,
|
|
[policy_copy], events.UPDATED)
|
|
self.wait_until_bandwidth_limit_rule_applied(self.ports[0],
|
|
policy_copy.rules[0])
|
|
|
|
self._assert_bandwidth_limit_rule_not_set(self.ports[0],
|
|
self.direction)
|
|
self._assert_bandwidth_limit_rule_is_set(self.ports[0],
|
|
policy_copy.rules[0])
|
|
|
|
def test_port_qos_disassociation(self):
|
|
"""Test that qos_policy_id set to None will remove all qos rules from
|
|
given port.
|
|
"""
|
|
port_dict = self._create_port_with_qos()
|
|
|
|
port_dict['qos_policy_id'] = None
|
|
self.agent.port_update(None, port=port_dict)
|
|
|
|
self.wait_until_bandwidth_limit_rule_applied(port_dict, None)
|
|
|
|
def test_port_qos_update_policy_id(self):
|
|
"""Test that change of qos policy id on given port refreshes all its
|
|
rules.
|
|
"""
|
|
port_dict = self._create_port_with_qos()
|
|
|
|
port_dict['qos_policy_id'] = TEST_POLICY_ID2
|
|
self.agent.port_update(None, port=port_dict)
|
|
|
|
self.wait_until_bandwidth_limit_rule_applied(port_dict,
|
|
self.test_bw_limit_rule_2)
|
|
|
|
def test_policy_rule_delete(self):
|
|
port_dict = self._create_port_with_qos()
|
|
|
|
policy_copy = copy.deepcopy(self.qos_policies[TEST_POLICY_ID1])
|
|
policy_copy.rules = list()
|
|
context = mock.Mock()
|
|
consumer_reg.push(context, resources.QOS_POLICY, [policy_copy],
|
|
events.UPDATED)
|
|
|
|
self.wait_until_bandwidth_limit_rule_applied(port_dict, None)
|