From 3c5d0d4ff6762cbe0bb2192f4e1bbfac81a6b724 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Mon, 19 Jun 2017 15:43:21 +0300 Subject: [PATCH] NSX|V3: Support QoS ingress rules Commit Ia13568879c2b6f80fb190ccafe7e19ca05b0c6a8 added the ingress direction BW rules. This patch adds this support for the nSX-V3 QoS driver. Depends-on: I34ae54b7c4b5810694e4ea05265421c8e4c903d8 Change-Id: I886896c4f9cc6b6456d72c3bec05ee76e18fea3b --- vmware_nsx/services/qos/nsx_v3/driver.py | 14 +-- vmware_nsx/services/qos/nsx_v3/utils.py | 41 +++++-- .../services/qos/test_nsxv3_notification.py | 102 ++++++++++++++---- 3 files changed, 116 insertions(+), 41 deletions(-) diff --git a/vmware_nsx/services/qos/nsx_v3/driver.py b/vmware_nsx/services/qos/nsx_v3/driver.py index 2af7b33beb..5ec6c5393e 100644 --- a/vmware_nsx/services/qos/nsx_v3/driver.py +++ b/vmware_nsx/services/qos/nsx_v3/driver.py @@ -33,7 +33,8 @@ SUPPORTED_RULES = { qos_consts.MAX_BURST: { 'type:range': [0, n_consts.DB_INTEGER_MAX_VALUE]}, 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.DSCP_MARK: {'type:values': n_consts.VALID_DSCP_MARKS} @@ -67,17 +68,8 @@ class NSXv3QosDriver(base.DriverBase): def update_policy(self, context, policy): 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( - context, policy.id, bw_rule, dscp_rule) + context, policy.id, policy["rules"]) # May also need to update name / description self.handler.update_policy(context, policy.id, policy) diff --git a/vmware_nsx/services/qos/nsx_v3/utils.py b/vmware_nsx/services/qos/nsx_v3/utils.py index 4959de88dc..980525330b 100644 --- a/vmware_nsx/services/qos/nsx_v3/utils.py +++ b/vmware_nsx/services/qos/nsx_v3/utils.py @@ -17,6 +17,7 @@ from oslo_config import cfg from oslo_log import log as logging +from neutron.common import constants as n_consts from neutron.services.qos import qos_consts from neutron_lib.api import validators from neutron_lib import exceptions as n_exc @@ -150,25 +151,45 @@ class QosNotificationsHandler(object): 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 DSCP marking configuration """ profile_id = nsx_db.get_switch_profile_by_qos_policy( context.session, policy_id) - (shaping_enabled, burst_size, peak_bw, - average_bw) = self._get_bw_values_from_rule(bw_rule) + ingress_bw_rule = None + 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) - self._nsxlib_qos.update_shaping( + + self._nsxlib_qos.set_profile_shaping( profile_id, - shaping_enabled=shaping_enabled, - burst_size=burst_size, - peak_bandwidth=peak_bw, - average_bandwidth=average_bw, - qos_marking=qos_marking, - dscp=dscp) + ingress_bw_enabled=ingress_bw_enabled, + ingress_burst_size=ingress_burst_size, + ingress_peak_bandwidth=ingress_peak_bw, + ingress_average_bandwidth=ingress_average_bw, + egress_bw_enabled=egress_bw_enabled, + 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): """Raise an exception if the rule values are not supported""" diff --git a/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py b/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py index 88ee7bd71e..b51e634936 100644 --- a/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py +++ b/vmware_nsx/tests/unit/services/qos/test_nsxv3_notification.py @@ -57,6 +57,11 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, 'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(), 'max_kbps': 2000, '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 = { 'dscp_marking_rule': {'id': uuidutils.generate_uuid(), 'dscp_mark': 22}} @@ -64,8 +69,12 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, self.policy = policy_object.QosPolicy( self.ctxt, **self.policy_data['policy']) + # egress BW limit rule self.rule = rule_object.QosBandwidthLimitRule( 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.ctxt, **self.dscp_rule_data['dscp_marking_rule']) @@ -140,7 +149,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, @mock.patch.object(policy_object.QosPolicy, '_reload_rules') 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( self.ctxt, **self.policy_data['policy']) # add a rule to the policy @@ -149,7 +158,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, return_value=_policy): with mock.patch( 'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.' - 'update_shaping' + 'set_profile_shaping' ) as update_profile: with mock.patch('neutron.objects.db.api.update_object', return_value=self.rule_data): @@ -162,14 +171,59 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, rule_dict['max_kbps']) / 1024)) expected_burst = rule_dict['max_burst_kbps'] * 128 expected_peak = int(expected_bw * self.peak_bw_multiplier) + # egress neutron rule -> ingress nsx args update_profile.assert_called_once_with( self.fake_profile_id, - average_bandwidth=expected_bw, - burst_size=expected_burst, - peak_bandwidth=expected_peak, - shaping_enabled=True, - qos_marking='trusted', - dscp=0 + ingress_bw_enabled=True, + ingress_burst_size=expected_burst, + ingress_peak_bandwidth=expected_peak, + ingress_average_bandwidth=expected_bw, + egress_bw_enabled=False, + 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') @@ -233,7 +287,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, return_value=_policy): with mock.patch( 'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.' - 'update_shaping' + 'set_profile_shaping' ) as update_profile: with mock.patch('neutron.objects.db.api.' 'update_object', return_value=self.dscp_rule_data): @@ -246,12 +300,16 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, dscp_mark = rule_dict['dscp_mark'] update_profile.assert_called_once_with( self.fake_profile_id, - average_bandwidth=None, - burst_size=None, - peak_bandwidth=None, - shaping_enabled=False, - qos_marking='untrusted', - dscp=dscp_mark + ingress_bw_enabled=False, + ingress_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=dscp_mark, + qos_marking='untrusted' ) def test_rule_delete_profile(self): @@ -264,7 +322,7 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, return_value=_policy): with mock.patch( 'vmware_nsxlib.v3.core_resources.NsxLibQosSwitchingProfile.' - 'update_shaping' + 'set_profile_shaping' ) as update_profile: setattr(_policy, "rules", [self.rule]) self.qos_plugin.delete_policy_bandwidth_limit_rule( @@ -272,11 +330,15 @@ class TestQosNsxV3Notification(base.BaseQosTestCase, # validate the data on the profile update_profile.assert_called_once_with( self.fake_profile_id, - shaping_enabled=False, - average_bandwidth=None, - burst_size=None, + ingress_bw_enabled=False, + ingress_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, - peak_bandwidth=None, qos_marking='trusted' )