diff --git a/.gitreview b/.gitreview index e32805c1388..7cdf2521e50 100644 --- a/.gitreview +++ b/.gitreview @@ -1,5 +1,5 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/neutron.git -defaultbranch=stable/liberty +#[gerrit] +#host=review.openstack.org +#port=29418 +#project=openstack/neutron.git +#defaultbranch=stable/liberty diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py index 9fe9df230c8..1a35b499146 100644 --- a/neutron/agent/common/ovs_lib.py +++ b/neutron/agent/common/ovs_lib.py @@ -541,6 +541,16 @@ def delete_egress_bw_limit_for_port(self, port_name): self._set_egress_bw_limit_for_port( port_name, 0, 0) + def create_dscp_marking_rule_for_port(self, port, dscp_mark): + self.add_flow(priority=5, in_port=port, + actions="mod_nw_tos=%s,normal" % dscp_mark) + + def get_dscp_marking_rule_for_port(self, port): + pass + + def delete_dscp_marking_rule_for_port(self, port): + self.delete_flows(priority=5, in_port=port) + def __enter__(self): self.create() return self diff --git a/neutron/extensions/qos.py b/neutron/extensions/qos.py index 6653416b78b..a0b8434216d 100644 --- a/neutron/extensions/qos.py +++ b/neutron/extensions/qos.py @@ -229,6 +229,32 @@ def update_policy_bandwidth_limit_rule(self, context, rule_id, policy_id, def delete_policy_bandwidth_limit_rule(self, context, rule_id, policy_id): pass + @abc.abstractmethod + def get_policy_dscp_marking_rule(self, context, rule_id, + policy_id, fields=None): + pass + + @abc.abstractmethod + def get_policy_dscp_marking_rules(self, context, policy_id, + filters=None, fields=None, + sorts=None, limit=None, + marker=None, page_reverse=False): + pass + + @abc.abstractmethod + def create_policy_dscp_marking_rule(self, context, policy_id, + dscp_marking_rule): + pass + + @abc.abstractmethod + def update_policy_dscp_marking_rule(self, context, rule_id, policy_id, + dscp_marking_rule): + pass + + @abc.abstractmethod + def delete_policy_dscp_marking_rule(self, context, rule_id, policy_id): + pass + @abc.abstractmethod def get_rule_types(self, context, filters=None, fields=None, sorts=None, limit=None, diff --git a/neutron/objects/qos/rule.py b/neutron/objects/qos/rule.py index 2362fb7be99..1f168471300 100644 --- a/neutron/objects/qos/rule.py +++ b/neutron/objects/qos/rule.py @@ -86,3 +86,13 @@ class QosBandwidthLimitRule(QosRule): } rule_type = qos_consts.RULE_TYPE_BANDWIDTH_LIMIT + + +@obj_base.VersionedObjectRegistry.register +class QosDscpMarkingRule(QosRule): + + fields = { + 'dscp_tag': obj_fields.StringField(nullable=True), + } + + rule_type = qos_consts.RULE_TYPE_DSCP_MARKING diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py b/neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py index 5977083794c..dbdbeb29c8d 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py @@ -48,3 +48,12 @@ def update_bandwidth_limit(self, port, rule): def delete_bandwidth_limit(self, port): port_name = port['vif_port'].port_name self.br_int.delete_egress_bw_limit_for_port(port_name) + + def _create_dscp_marking_rule(self, qos_policy_id, dscp_tag): + self._update_dscp_marking_rule(qos_policy_id, dscp_tag) + + def _update_dscp_marking_rule(self, qos_policy_id, dscp_tag): + self.br_int.create_dscp_marking_rule(qos_policy_id, dscp_tag) + + def _delete_dscp_marking_rule(self, qos_policy_id): + self.br_int.delete_dscp_marking_rule(qos_policy_id) diff --git a/neutron/services/qos/qos_consts.py b/neutron/services/qos/qos_consts.py index 3eb78d517d5..5f092209cba 100644 --- a/neutron/services/qos/qos_consts.py +++ b/neutron/services/qos/qos_consts.py @@ -14,6 +14,8 @@ # under the License. RULE_TYPE_BANDWIDTH_LIMIT = 'bandwidth_limit' -VALID_RULE_TYPES = [RULE_TYPE_BANDWIDTH_LIMIT] +RULE_TYPE_DSCP_MARKING = 'dscp_marking' + +VALID_RULE_TYPES = [RULE_TYPE_BANDWIDTH_LIMIT, RULE_TYPE_DSCP_MARKING] QOS_POLICY_ID = 'qos_policy_id' diff --git a/neutron/services/qos/qos_plugin.py b/neutron/services/qos/qos_plugin.py index 29ff7b58ff1..86af2a13993 100644 --- a/neutron/services/qos/qos_plugin.py +++ b/neutron/services/qos/qos_plugin.py @@ -158,6 +158,27 @@ def get_policy_bandwidth_limit_rules(self, context, policy_id, return rule_object.QosBandwidthLimitRule.get_objects(context, **filters) + def create_policy_dscp_marking_rule(self, context, policy_id, + dscp_marking_rule): + pass + + def update_policy_dscp_marking_rule(self, context, rule_id, policy_id, + dscp_marking_rule): + pass + + def delete_policy_dscp_marking_rule(self, context, rule_id, policy_id): + pass + + def get_policy_dscp_marking_rule(self, context, rule_id, + policy_id, fields=None): + pass + + def get_policy_dscp_marking_rules(self, context, policy_id, + filters=None, fields=None, + sorts=None, limit=None, + marker=None, page_reverse=False): + pass + # TODO(QoS): enforce rule types when accessing rule objects @db_base_plugin_common.filter_fields @db_base_plugin_common.convert_result_to_dict diff --git a/neutron/tests/functional/agent/l2/extensions/test_ovs_agent_qos_extension.py b/neutron/tests/functional/agent/l2/extensions/test_ovs_agent_qos_extension.py index 9b73e733636..af88cd37bb6 100644 --- a/neutron/tests/functional/agent/l2/extensions/test_ovs_agent_qos_extension.py +++ b/neutron/tests/functional/agent/l2/extensions/test_ovs_agent_qos_extension.py @@ -29,6 +29,8 @@ TEST_POLICY_ID1 = "a2d72369-4246-4f19-bd3c-af51ec8d70cd" TEST_POLICY_ID2 = "46ebaec0-0570-43ac-82f6-60d2b03168c5" +TEST_DSCP_TAG_1 = 1 +TEST_DSCP_TAG_2 = 2 TEST_BW_LIMIT_RULE_1 = rule.QosBandwidthLimitRule( context=None, qos_policy_id=TEST_POLICY_ID1, @@ -107,6 +109,18 @@ def wait_until_bandwidth_limit_rule_applied(self, port, rule): l2_extensions.wait_until_bandwidth_limit_rule_applied( self.agent.int_br, port['vif_name'], rule) + def _assert_dscp_marking_rule_is_set(self, qos_policy, dscp_tag): + current_dscp_tag = self.agent.int_br.get_dscp_marking_rule(qos_policy) + self.assertEqual(dscp_tag, current_dscp_tag) + + def _assert_dscp_marking_rule_not_set(self, qos_policy, port): + current_dscp_tag = self.agent.int_br.get_dscp_marking_rule(qos_policy) + self.assertIsNone(current_dscp_tag) + + def wait_until_dscp_marking_rule_applied(self, qos_policy, dscp_tag): + l2_extensions.wait_until_dscp_marking_rule_applied( + self.agent.int_br, qos_policy, dscp_tag) + def _create_port_with_qos(self): port_dict = self._create_test_port_dict() port_dict['qos_policy_id'] = TEST_POLICY_ID1 @@ -185,7 +199,11 @@ def test_port_qos_update_policy_id(self): self.agent.port_update(None, port=port_dict) self.wait_until_bandwidth_limit_rule_applied(port_dict, - TEST_BW_LIMIT_RULE_2) + TEST_BW_LIMIT_RULE_1) + self.wait_until_dscp_marking_rule_applied(TEST_POLICY_ID1, + TEST_DSCP_TAG_1) + self.wait_until_dscp_marking_rule_applied(TEST_POLICY_ID2, + TEST_DSCP_TAG_2) def test_policy_rule_delete(self): port_dict = self._create_port_with_qos() diff --git a/neutron/tests/unit/agent/common/test_ovs_lib.py b/neutron/tests/unit/agent/common/test_ovs_lib.py index 468f953baa0..4c7d2c8c4ac 100644 --- a/neutron/tests/unit/agent/common/test_ovs_lib.py +++ b/neutron/tests/unit/agent/common/test_ovs_lib.py @@ -149,6 +149,11 @@ def test_add_flow(self): ('tun_id', lsw_id), ('actions', "mod_vlan_vid:%s,output:%s" % (vid, ofport))]) flow_dict_7 = collections.OrderedDict([ + ('cookie', 1334), + ('priority', 4), + ('in_port', ofport), + ('actions', 'mod_nw_tos=104')]) + flow_dict_8 = collections.OrderedDict([ ('cookie', 1256), ('priority', 4), ('nw_src', cidr), @@ -162,6 +167,7 @@ def test_add_flow(self): self.br.add_flow(**flow_dict_5) self.br.add_flow(**flow_dict_6) self.br.add_flow(**flow_dict_7) + self.br.add_flow(**flow_dict_8) expected_calls = [ self._ofctl_mock("add-flows", self.BR_NAME, '-', process_input=OFCTLParamListMatcher( @@ -193,6 +199,11 @@ def test_add_flow(self): "priority=3," "tun_id=%s,actions=mod_vlan_vid:%s,output:%s" % (lsw_id, vid, ofport))), + self._ofctl_mock("add-flows", self.BR_NAME, '-', + process_input=OFCTLParamListMatcher( + "hard_timeout=0,idle_timeout=0,cookie=1334," + "priority=4,in_port=%s,actions=mod_nw_tos=104" + % ofport)), self._ofctl_mock("add-flows", self.BR_NAME, '-', process_input=OFCTLParamListMatcher( "hard_timeout=0,idle_timeout=0,cookie=1256," @@ -324,7 +335,7 @@ def test_dump_flows_ovs_dead(self): run_ofctl = mock.patch.object(self.br, 'run_ofctl').start() run_ofctl.side_effect = [''] retflows = self.br.dump_flows_for_table(table) - self.assertEqual(None, retflows) + self.assertIsNone(retflows) def test_mod_flow_with_priority_set(self): params = {'in_port': '1', @@ -777,6 +788,24 @@ def test_get_vif_by_port_id_multiple_vifs(self): 'tap99id', data, extra_calls_and_values=extra_calls_and_values) self._assert_vif_port(vif_port, ofport=1337, mac="de:ad:be:ef:13:37") + def test_set_dscp_rule(self): + port = 999 + dscp_mark = 104 + self.br.create_dscp_marking_rule_for_port(port, dscp_mark) + expected = [ + self.br.add_flow(priority=5, in_port=port, + actions='mod_nw_tos:%s,normal' % dscp_mark), + ] + self.assertEqual(expected, self.mock.mock_calls) + + def test_remove_dscp_rule(self): + port = 999 + self.br.delete_dscp_marking_rule_for_port(port) + expected = [ + self.br.delete_flows(priority=5, in_port=port) + ] + self.assertEqual(expected, self.mock.mock_calls) + class TestDeferredOVSBridge(base.BaseTestCase):