Merge "Extend QoS L2 drivers interface to handle ingress rule types"

This commit is contained in:
Jenkins 2017-06-06 22:11:18 +00:00 committed by Gerrit Code Review
commit 864ca822fe
2 changed files with 121 additions and 23 deletions

View File

@ -26,7 +26,9 @@ from neutron.api.rpc.callbacks.consumer import registry
from neutron.api.rpc.callbacks import events
from neutron.api.rpc.callbacks import resources
from neutron.api.rpc.handlers import resources_rpc
from neutron.common import constants
from neutron import manager
from neutron.services.qos import qos_consts
LOG = logging.getLogger(__name__)
@ -47,7 +49,10 @@ class QosAgentDriver(object):
# delete_<type>
#
# where <type> is one of VALID_RULE_TYPES
SUPPORTED_RULES = set()
# There is exception from this rule for deletion of rules with
# attribute direction set to ingress (e.g. bandwidth limit rule).
# For deletion of such rule types delete handler has following name:
# delete_<type>_ingress
@abc.abstractmethod
def initialize(self):
@ -86,14 +91,15 @@ class QosAgentDriver(object):
:param qos_policy: the QoS policy to be removed from port.
"""
if qos_policy is None:
rule_types = self.SUPPORTED_RULES
for rule_type in self.SUPPORTED_RULES:
self._handle_rule_delete(port, rule_type)
if self._rule_type_has_ingress_direction(rule_type):
self._handle_rule_delete(port, rule_type, ingress=True)
else:
rule_types = set(
[rule.rule_type
for rule in self._iterate_rules(qos_policy.rules)])
for rule_type in rule_types:
self._handle_rule_delete(port, rule_type)
for rule in self._iterate_rules(qos_policy.rules):
self._handle_rule_delete(
port, rule.rule_type,
ingress=self._rule_is_ingress_direction(rule))
def _iterate_rules(self, rules):
for rule in rules:
@ -105,8 +111,11 @@ class QosAgentDriver(object):
'%(rule_type)s; skipping'),
{'rule_id': rule.id, 'rule_type': rule_type})
def _handle_rule_delete(self, port, rule_type):
def _handle_rule_delete(self, port, rule_type, ingress=False):
handler_name = "".join(("delete_", rule_type))
if ingress:
handler_name = "%s_%s" % (handler_name,
constants.INGRESS_DIRECTION)
handler = getattr(self, handler_name)
handler(port)
@ -120,6 +129,17 @@ class QosAgentDriver(object):
LOG.debug("Port %(port)s excluded from QoS rule %(rule)s",
{'port': port, 'rule': rule.id})
def _rule_type_has_ingress_direction(self, rule_type):
supported_rule = self.SUPPORTED_RULES[rule_type]
if qos_consts.DIRECTION not in supported_rule.keys():
return False
return (constants.INGRESS_DIRECTION in
supported_rule[qos_consts.DIRECTION]['type:values'])
def _rule_is_ingress_direction(self, rule):
rule_direction = getattr(rule, "direction", constants.EGRESS_DIRECTION)
return rule_direction == constants.INGRESS_DIRECTION
class PortPolicyMap(object):
def __init__(self):

View File

@ -23,6 +23,7 @@ from neutron.api.rpc.callbacks.consumer import registry
from neutron.api.rpc.callbacks import events
from neutron.api.rpc.callbacks import resources
from neutron.api.rpc.handlers import resources_rpc
from neutron.common import constants as common_constants
from neutron.objects.qos import policy
from neutron.objects.qos import rule
from neutron.plugins.ml2.drivers.openvswitch.agent import (
@ -52,18 +53,30 @@ TEST_PORT2 = {'port_id': 'test_port_id_2',
'qos_policy_id': TEST_POLICY2.id}
FAKE_RULE_ID = uuidutils.generate_uuid()
FAKE_RULE_ID_2 = uuidutils.generate_uuid()
REALLY_FAKE_RULE_ID = uuidutils.generate_uuid()
class FakeDriver(qos_linux.QosLinuxAgentDriver):
SUPPORTED_RULES = {qos_consts.RULE_TYPE_BANDWIDTH_LIMIT}
SUPPORTED_RULES = {
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: {
qos_consts.MAX_KBPS: {
'type:range': [0, common_constants.DB_INTEGER_MAX_VALUE]},
qos_consts.MAX_BURST: {
'type:range': [0, common_constants.DB_INTEGER_MAX_VALUE]},
qos_consts.DIRECTION: {
'type:values': [common_constants.EGRESS_DIRECTION,
common_constants.INGRESS_DIRECTION]}
},
}
def __init__(self):
super(FakeDriver, self).__init__()
self.create_bandwidth_limit = mock.Mock()
self.update_bandwidth_limit = mock.Mock()
self.delete_bandwidth_limit = mock.Mock()
self.delete_bandwidth_limit_ingress = mock.Mock()
def initialize(self):
pass
@ -80,11 +93,20 @@ class QosAgentDriverTestCase(base.BaseTestCase):
super(QosAgentDriverTestCase, self).setUp()
self.driver = FakeDriver()
self.policy = TEST_POLICY
self.rule = (
rule.QosBandwidthLimitRule(context=None, id=FAKE_RULE_ID,
qos_policy_id=self.policy.id,
max_kbps=100, max_burst_kbps=200))
self.policy.rules = [self.rule]
self.egress_bandwidth_limit_rule = (
rule.QosBandwidthLimitRule(
context=None, id=FAKE_RULE_ID,
qos_policy_id=self.policy.id,
max_kbps=100, max_burst_kbps=200,
direction=common_constants.EGRESS_DIRECTION))
self.ingress_bandwidth_limit_rule = (
rule.QosBandwidthLimitRule(
context=None, id=FAKE_RULE_ID_2,
qos_policy_id=self.policy.id,
max_kbps=100, max_burst_kbps=200,
direction=common_constants.INGRESS_DIRECTION))
self.policy.rules = [self.egress_bandwidth_limit_rule,
self.ingress_bandwidth_limit_rule]
self.port = {'qos_policy_id': None, 'network_qos_policy_id': None,
'device_owner': 'random-device-owner'}
@ -93,45 +115,101 @@ class QosAgentDriverTestCase(base.BaseTestCase):
def test_create(self):
self.driver.create(self.port, self.policy)
self.driver.create_bandwidth_limit.assert_called_with(
self.port, self.rule)
self.driver.create_bandwidth_limit.assert_has_calls([
mock.call(self.port, self.egress_bandwidth_limit_rule),
mock.call(self.port, self.ingress_bandwidth_limit_rule)
])
def test_update(self):
self.driver.update(self.port, self.policy)
self.driver.update_bandwidth_limit.assert_called_with(
self.port, self.rule)
self.driver.update_bandwidth_limit.assert_has_calls([
mock.call(self.port, self.egress_bandwidth_limit_rule),
mock.call(self.port, self.ingress_bandwidth_limit_rule)
])
def test_delete(self):
self.driver.delete(self.port, self.policy)
self.driver.delete_bandwidth_limit.assert_called_with(self.port)
self.driver.delete_bandwidth_limit_ingress.assert_called_with(
self.port)
def test_delete_no_policy(self):
self.driver.delete(self.port, qos_policy=None)
self.driver.delete_bandwidth_limit.assert_called_with(self.port)
self.driver.delete_bandwidth_limit_ingress.assert_called_with(
self.port)
def test__iterate_rules_with_unknown_rule_type(self):
self.policy.rules.append(self.fake_rule)
rules = list(self.driver._iterate_rules(self.policy.rules))
self.assertEqual(1, len(rules))
self.assertEqual(2, len(rules))
self.assertIsInstance(rules[0], rule.QosBandwidthLimitRule)
self.assertIsInstance(rules[1], rule.QosBandwidthLimitRule)
def test__handle_update_create_rules_checks_should_apply_to_port(self):
self.rule.should_apply_to_port = mock.Mock(return_value=False)
self.egress_bandwidth_limit_rule.should_apply_to_port = mock.Mock(
return_value=False)
self.ingress_bandwidth_limit_rule.should_apply_to_port = mock.Mock(
return_value=False)
self.driver.create(self.port, self.policy)
self.assertFalse(self.driver.create_bandwidth_limit.called)
self.rule.should_apply_to_port = mock.Mock(return_value=True)
self.egress_bandwidth_limit_rule.should_apply_to_port = mock.Mock(
return_value=True)
self.ingress_bandwidth_limit_rule.should_apply_to_port = mock.Mock(
return_value=True)
self.driver.create(self.port, self.policy)
self.assertTrue(self.driver.create_bandwidth_limit.called)
def test__get_max_burst_value(self):
rule = self.rule
rule = self.egress_bandwidth_limit_rule
rule.max_burst_kbps = 0
expected_burst = rule.max_kbps * qos_consts.DEFAULT_BURST_RATE
self.assertEqual(
expected_burst, self.driver._get_egress_burst_value(rule)
)
def test__rule_type_has_ingress_direction(self):
self.assertTrue(
self.driver._rule_type_has_ingress_direction(
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT))
# Should return False for rule type other than
# RULE_TYPE_BANDWIDTH_LIMIT
supported_rules = {
qos_consts.RULE_TYPE_DSCP_MARKING: {
qos_consts.DSCP_MARK: {
'type:values': common_constants.VALID_DSCP_MARKS}
}
}
with mock.patch.dict(self.driver.SUPPORTED_RULES, supported_rules):
self.assertFalse(
self.driver._rule_type_has_ingress_direction(
qos_consts.RULE_TYPE_DSCP_MARKING))
# Should return False for rule type RULE_TYPE_BANDWIDTH_LIMIT but
# without INGRESS_DIRECTION in supported values
supported_rules = {
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT: {
'type:values': [common_constants.EGRESS_DIRECTION]
}
}
with mock.patch.dict(self.driver.SUPPORTED_RULES, supported_rules):
self.assertFalse(
self.driver._rule_type_has_ingress_direction(
qos_consts.RULE_TYPE_BANDWIDTH_LIMIT))
def test__rule_is_ingress_direction(self):
self.assertFalse(
self.driver._rule_is_ingress_direction(
self.egress_bandwidth_limit_rule))
self.assertFalse(
self.driver._rule_is_ingress_direction(
self.fake_rule))
self.assertTrue(
self.driver._rule_is_ingress_direction(
self.ingress_bandwidth_limit_rule))
class QosExtensionBaseTestCase(base.BaseTestCase):