Merge "NSX|V3: Support QoS ingress rules"
This commit is contained in:
commit
63154b510b
@ -33,7 +33,8 @@ SUPPORTED_RULES = {
|
|||||||
qos_consts.MAX_BURST: {
|
qos_consts.MAX_BURST: {
|
||||||
'type:range': [0, n_consts.DB_INTEGER_MAX_VALUE]},
|
'type:range': [0, n_consts.DB_INTEGER_MAX_VALUE]},
|
||||||
qos_consts.DIRECTION: {
|
qos_consts.DIRECTION: {
|
||||||
'type:values': [n_consts.EGRESS_DIRECTION]}
|
'type:values': [n_consts.EGRESS_DIRECTION,
|
||||||
|
n_consts.INGRESS_DIRECTION]}
|
||||||
},
|
},
|
||||||
qos_consts.RULE_TYPE_DSCP_MARKING: {
|
qos_consts.RULE_TYPE_DSCP_MARKING: {
|
||||||
qos_consts.DSCP_MARK: {'type:values': n_consts.VALID_DSCP_MARKS}
|
qos_consts.DSCP_MARK: {'type:values': n_consts.VALID_DSCP_MARKS}
|
||||||
@ -67,17 +68,8 @@ class NSXv3QosDriver(base.DriverBase):
|
|||||||
|
|
||||||
def update_policy(self, context, policy):
|
def update_policy(self, context, policy):
|
||||||
if (hasattr(policy, "rules")):
|
if (hasattr(policy, "rules")):
|
||||||
# we may have up to 1 rule of each type
|
|
||||||
bw_rule = None
|
|
||||||
dscp_rule = None
|
|
||||||
for rule in policy["rules"]:
|
|
||||||
if rule.rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT:
|
|
||||||
bw_rule = rule
|
|
||||||
else:
|
|
||||||
dscp_rule = rule
|
|
||||||
|
|
||||||
self.handler.update_policy_rules(
|
self.handler.update_policy_rules(
|
||||||
context, policy.id, bw_rule, dscp_rule)
|
context, policy.id, policy["rules"])
|
||||||
|
|
||||||
# May also need to update name / description
|
# May also need to update name / description
|
||||||
self.handler.update_policy(context, policy.id, policy)
|
self.handler.update_policy(context, policy.id, policy)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from neutron.common import constants as n_consts
|
||||||
from neutron.services.qos import qos_consts
|
from neutron.services.qos import qos_consts
|
||||||
from neutron_lib.api import validators
|
from neutron_lib.api import validators
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
@ -150,25 +151,45 @@ class QosNotificationsHandler(object):
|
|||||||
|
|
||||||
return qos_marking, dscp
|
return qos_marking, dscp
|
||||||
|
|
||||||
def update_policy_rules(self, context, policy_id, bw_rule, dscp_rule):
|
def update_policy_rules(self, context, policy_id, rules):
|
||||||
"""Update the QoS switch profile with the BW limitations and
|
"""Update the QoS switch profile with the BW limitations and
|
||||||
DSCP marking configuration
|
DSCP marking configuration
|
||||||
"""
|
"""
|
||||||
profile_id = nsx_db.get_switch_profile_by_qos_policy(
|
profile_id = nsx_db.get_switch_profile_by_qos_policy(
|
||||||
context.session, policy_id)
|
context.session, policy_id)
|
||||||
|
|
||||||
(shaping_enabled, burst_size, peak_bw,
|
ingress_bw_rule = None
|
||||||
average_bw) = self._get_bw_values_from_rule(bw_rule)
|
egress_bw_rule = None
|
||||||
|
dscp_rule = None
|
||||||
|
for rule in rules:
|
||||||
|
if rule.rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT:
|
||||||
|
if rule.direction == n_consts.EGRESS_DIRECTION:
|
||||||
|
egress_bw_rule = rule
|
||||||
|
else:
|
||||||
|
ingress_bw_rule = rule
|
||||||
|
else:
|
||||||
|
dscp_rule = rule
|
||||||
|
|
||||||
|
# the NSX direction is opposite to the neutron direction
|
||||||
|
(ingress_bw_enabled, ingress_burst_size, ingress_peak_bw,
|
||||||
|
ingress_average_bw) = self._get_bw_values_from_rule(egress_bw_rule)
|
||||||
|
|
||||||
|
(egress_bw_enabled, egress_burst_size, egress_peak_bw,
|
||||||
|
egress_average_bw) = self._get_bw_values_from_rule(ingress_bw_rule)
|
||||||
|
|
||||||
qos_marking, dscp = self._get_dscp_values_from_rule(dscp_rule)
|
qos_marking, dscp = self._get_dscp_values_from_rule(dscp_rule)
|
||||||
self._nsxlib_qos.update_shaping(
|
|
||||||
|
self._nsxlib_qos.set_profile_shaping(
|
||||||
profile_id,
|
profile_id,
|
||||||
shaping_enabled=shaping_enabled,
|
ingress_bw_enabled=ingress_bw_enabled,
|
||||||
burst_size=burst_size,
|
ingress_burst_size=ingress_burst_size,
|
||||||
peak_bandwidth=peak_bw,
|
ingress_peak_bandwidth=ingress_peak_bw,
|
||||||
average_bandwidth=average_bw,
|
ingress_average_bandwidth=ingress_average_bw,
|
||||||
qos_marking=qos_marking,
|
egress_bw_enabled=egress_bw_enabled,
|
||||||
dscp=dscp)
|
egress_burst_size=egress_burst_size,
|
||||||
|
egress_peak_bandwidth=egress_peak_bw,
|
||||||
|
egress_average_bandwidth=egress_average_bw,
|
||||||
|
qos_marking=qos_marking, dscp=dscp)
|
||||||
|
|
||||||
def validate_policy_rule(self, context, policy_id, rule):
|
def validate_policy_rule(self, context, policy_id, rule):
|
||||||
"""Raise an exception if the rule values are not supported"""
|
"""Raise an exception if the rule values are not supported"""
|
||||||
|
@ -57,6 +57,11 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
||||||
'max_kbps': 2000,
|
'max_kbps': 2000,
|
||||||
'max_burst_kbps': 150}}
|
'max_burst_kbps': 150}}
|
||||||
|
self.ingress_rule_data = {
|
||||||
|
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
||||||
|
'max_kbps': 3000,
|
||||||
|
'max_burst_kbps': 350,
|
||||||
|
'direction': 'ingress'}}
|
||||||
self.dscp_rule_data = {
|
self.dscp_rule_data = {
|
||||||
'dscp_marking_rule': {'id': uuidutils.generate_uuid(),
|
'dscp_marking_rule': {'id': uuidutils.generate_uuid(),
|
||||||
'dscp_mark': 22}}
|
'dscp_mark': 22}}
|
||||||
@ -64,8 +69,12 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
self.policy = policy_object.QosPolicy(
|
self.policy = policy_object.QosPolicy(
|
||||||
self.ctxt, **self.policy_data['policy'])
|
self.ctxt, **self.policy_data['policy'])
|
||||||
|
|
||||||
|
# egress BW limit rule
|
||||||
self.rule = rule_object.QosBandwidthLimitRule(
|
self.rule = rule_object.QosBandwidthLimitRule(
|
||||||
self.ctxt, **self.rule_data['bandwidth_limit_rule'])
|
self.ctxt, **self.rule_data['bandwidth_limit_rule'])
|
||||||
|
# ingress bw limit rule
|
||||||
|
self.ingress_rule = rule_object.QosBandwidthLimitRule(
|
||||||
|
self.ctxt, **self.ingress_rule_data['bandwidth_limit_rule'])
|
||||||
self.dscp_rule = rule_object.QosDscpMarkingRule(
|
self.dscp_rule = rule_object.QosDscpMarkingRule(
|
||||||
self.ctxt, **self.dscp_rule_data['dscp_marking_rule'])
|
self.ctxt, **self.dscp_rule_data['dscp_marking_rule'])
|
||||||
|
|
||||||
@ -140,7 +149,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
|
|
||||||
@mock.patch.object(policy_object.QosPolicy, '_reload_rules')
|
@mock.patch.object(policy_object.QosPolicy, '_reload_rules')
|
||||||
def test_bw_rule_create_profile(self, *mocks):
|
def test_bw_rule_create_profile(self, *mocks):
|
||||||
# test the switch profile update when a QoS BW rule is created
|
# test the switch profile update when a egress QoS BW rule is created
|
||||||
_policy = policy_object.QosPolicy(
|
_policy = policy_object.QosPolicy(
|
||||||
self.ctxt, **self.policy_data['policy'])
|
self.ctxt, **self.policy_data['policy'])
|
||||||
# add a rule to the policy
|
# add a rule to the policy
|
||||||
@ -149,7 +158,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
return_value=_policy):
|
return_value=_policy):
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
||||||
'update_shaping'
|
'set_profile_shaping'
|
||||||
) as update_profile:
|
) as update_profile:
|
||||||
with mock.patch('neutron.objects.db.api.update_object',
|
with mock.patch('neutron.objects.db.api.update_object',
|
||||||
return_value=self.rule_data):
|
return_value=self.rule_data):
|
||||||
@ -162,14 +171,59 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
rule_dict['max_kbps']) / 1024))
|
rule_dict['max_kbps']) / 1024))
|
||||||
expected_burst = rule_dict['max_burst_kbps'] * 128
|
expected_burst = rule_dict['max_burst_kbps'] * 128
|
||||||
expected_peak = int(expected_bw * self.peak_bw_multiplier)
|
expected_peak = int(expected_bw * self.peak_bw_multiplier)
|
||||||
|
# egress neutron rule -> ingress nsx args
|
||||||
update_profile.assert_called_once_with(
|
update_profile.assert_called_once_with(
|
||||||
self.fake_profile_id,
|
self.fake_profile_id,
|
||||||
average_bandwidth=expected_bw,
|
ingress_bw_enabled=True,
|
||||||
burst_size=expected_burst,
|
ingress_burst_size=expected_burst,
|
||||||
peak_bandwidth=expected_peak,
|
ingress_peak_bandwidth=expected_peak,
|
||||||
shaping_enabled=True,
|
ingress_average_bandwidth=expected_bw,
|
||||||
qos_marking='trusted',
|
egress_bw_enabled=False,
|
||||||
dscp=0
|
egress_burst_size=None,
|
||||||
|
egress_peak_bandwidth=None,
|
||||||
|
egress_average_bandwidth=None,
|
||||||
|
dscp=0,
|
||||||
|
qos_marking='trusted'
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch.object(policy_object.QosPolicy, '_reload_rules')
|
||||||
|
def test_ingress_bw_rule_create_profile(self, *mocks):
|
||||||
|
# test the switch profile update when a ingress QoS BW rule is created
|
||||||
|
_policy = policy_object.QosPolicy(
|
||||||
|
self.ctxt, **self.policy_data['policy'])
|
||||||
|
# add a rule to the policy
|
||||||
|
setattr(_policy, "rules", [self.ingress_rule])
|
||||||
|
with mock.patch('neutron.objects.qos.policy.QosPolicy.get_object',
|
||||||
|
return_value=_policy):
|
||||||
|
with mock.patch(
|
||||||
|
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
||||||
|
'set_profile_shaping'
|
||||||
|
) as update_profile:
|
||||||
|
with mock.patch('neutron.objects.db.api.update_object',
|
||||||
|
return_value=self.ingress_rule_data):
|
||||||
|
self.qos_plugin.update_policy_bandwidth_limit_rule(
|
||||||
|
self.ctxt, self.ingress_rule.id, _policy.id,
|
||||||
|
self.ingress_rule_data)
|
||||||
|
|
||||||
|
# validate the data on the profile
|
||||||
|
rule_dict = self.ingress_rule_data['bandwidth_limit_rule']
|
||||||
|
expected_bw = int(round(float(
|
||||||
|
rule_dict['max_kbps']) / 1024))
|
||||||
|
expected_burst = rule_dict['max_burst_kbps'] * 128
|
||||||
|
expected_peak = int(expected_bw * self.peak_bw_multiplier)
|
||||||
|
# ingress neutron rule -> egress nsx args
|
||||||
|
update_profile.assert_called_once_with(
|
||||||
|
self.fake_profile_id,
|
||||||
|
egress_bw_enabled=True,
|
||||||
|
egress_burst_size=expected_burst,
|
||||||
|
egress_peak_bandwidth=expected_peak,
|
||||||
|
egress_average_bandwidth=expected_bw,
|
||||||
|
ingress_bw_enabled=False,
|
||||||
|
ingress_burst_size=None,
|
||||||
|
ingress_peak_bandwidth=None,
|
||||||
|
ingress_average_bandwidth=None,
|
||||||
|
dscp=0,
|
||||||
|
qos_marking='trusted'
|
||||||
)
|
)
|
||||||
|
|
||||||
@mock.patch.object(policy_object.QosPolicy, '_reload_rules')
|
@mock.patch.object(policy_object.QosPolicy, '_reload_rules')
|
||||||
@ -233,7 +287,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
return_value=_policy):
|
return_value=_policy):
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
||||||
'update_shaping'
|
'set_profile_shaping'
|
||||||
) as update_profile:
|
) as update_profile:
|
||||||
with mock.patch('neutron.objects.db.api.'
|
with mock.patch('neutron.objects.db.api.'
|
||||||
'update_object', return_value=self.dscp_rule_data):
|
'update_object', return_value=self.dscp_rule_data):
|
||||||
@ -246,12 +300,16 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
dscp_mark = rule_dict['dscp_mark']
|
dscp_mark = rule_dict['dscp_mark']
|
||||||
update_profile.assert_called_once_with(
|
update_profile.assert_called_once_with(
|
||||||
self.fake_profile_id,
|
self.fake_profile_id,
|
||||||
average_bandwidth=None,
|
ingress_bw_enabled=False,
|
||||||
burst_size=None,
|
ingress_burst_size=None,
|
||||||
peak_bandwidth=None,
|
ingress_peak_bandwidth=None,
|
||||||
shaping_enabled=False,
|
ingress_average_bandwidth=None,
|
||||||
qos_marking='untrusted',
|
egress_bw_enabled=False,
|
||||||
dscp=dscp_mark
|
egress_burst_size=None,
|
||||||
|
egress_peak_bandwidth=None,
|
||||||
|
egress_average_bandwidth=None,
|
||||||
|
dscp=dscp_mark,
|
||||||
|
qos_marking='untrusted'
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_rule_delete_profile(self):
|
def test_rule_delete_profile(self):
|
||||||
@ -264,7 +322,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
return_value=_policy):
|
return_value=_policy):
|
||||||
with mock.patch(
|
with mock.patch(
|
||||||
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.'
|
||||||
'update_shaping'
|
'set_profile_shaping'
|
||||||
) as update_profile:
|
) as update_profile:
|
||||||
setattr(_policy, "rules", [self.rule])
|
setattr(_policy, "rules", [self.rule])
|
||||||
self.qos_plugin.delete_policy_bandwidth_limit_rule(
|
self.qos_plugin.delete_policy_bandwidth_limit_rule(
|
||||||
@ -272,11 +330,15 @@ class TestQosNsxV3Notification(base.BaseQosTestCase,
|
|||||||
# validate the data on the profile
|
# validate the data on the profile
|
||||||
update_profile.assert_called_once_with(
|
update_profile.assert_called_once_with(
|
||||||
self.fake_profile_id,
|
self.fake_profile_id,
|
||||||
shaping_enabled=False,
|
ingress_bw_enabled=False,
|
||||||
average_bandwidth=None,
|
ingress_burst_size=None,
|
||||||
burst_size=None,
|
ingress_peak_bandwidth=None,
|
||||||
|
ingress_average_bandwidth=None,
|
||||||
|
egress_bw_enabled=False,
|
||||||
|
egress_burst_size=None,
|
||||||
|
egress_peak_bandwidth=None,
|
||||||
|
egress_average_bandwidth=None,
|
||||||
dscp=0,
|
dscp=0,
|
||||||
peak_bandwidth=None,
|
|
||||||
qos_marking='trusted'
|
qos_marking='trusted'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user