summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/devref/quality_of_service.rst21
-rw-r--r--neutron/agent/common/ovs_lib.py91
-rw-r--r--neutron/common/utils.py8
-rw-r--r--neutron/core_extensions/qos.py12
-rw-r--r--neutron/plugins/ml2/common/exceptions.py5
-rw-r--r--neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py26
-rw-r--r--neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py2
-rw-r--r--neutron/plugins/ml2/drivers/openvswitch/agent/extension_drivers/qos_driver.py16
-rw-r--r--neutron/plugins/ml2/managers.py40
-rw-r--r--neutron/tests/api/test_qos.py40
-rw-r--r--neutron/tests/common/agents/l2_extensions.py2
-rw-r--r--neutron/tests/functional/agent/l2/extensions/test_ovs_agent_qos_extension.py36
-rw-r--r--neutron/tests/functional/agent/test_ovs_lib.py10
-rw-r--r--neutron/tests/unit/common/test_utils.py10
-rw-r--r--neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py35
-rw-r--r--neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/extension_drivers/test_qos_driver.py20
-rw-r--r--neutron/tests/unit/plugins/ml2/test_extension_driver_api.py53
17 files changed, 264 insertions, 163 deletions
diff --git a/doc/source/devref/quality_of_service.rst b/doc/source/devref/quality_of_service.rst
index 0418aa2a35..bd4a8c716d 100644
--- a/doc/source/devref/quality_of_service.rst
+++ b/doc/source/devref/quality_of_service.rst
@@ -267,20 +267,17 @@ Open vSwitch
Open vSwitch implementation relies on the new ovs_lib OVSBridge functions:
-* create_qos_bw_limit_for_port
-* get_qos_bw_limit_for_port
-* del_qos_bw_limit_for_port
+* get_egress_bw_limit_for_port
+* create_egress_bw_limit_for_port
+* delete_egress_bw_limit_for_port
-An egress bandwidth limit is effectively configured on the port by creating a
-single QoS queue with min-rate=rule.max_kbps, max-rate=rule.max_kbps and
-burst=rule.max_burst_kbps. Then a linux-htb QoS policy is defined on the port,
-attached to the queue.
-
-HTB queues are supported at least in all 2.x versions of Open vSwitch.
-
-More details about HTB in `the blog post
-<https://virtualandy.wordpress.com/2013/04/29/deep-dive-htb-rate-limiting-qos-on-with-open-vswitch-and-xenserver/>`_.
+An egress bandwidth limit is effectively configured on the port by setting
+the port Interface parameters ingress_policing_rate and
+ingress_policing_burst.
+That approach is less flexible than linux-htb, Queues and OvS QoS profiles,
+which we may explore in the future, but which will need to be used in
+combination with openflow rules.
SR-IOV
~~~~~~
diff --git a/neutron/agent/common/ovs_lib.py b/neutron/agent/common/ovs_lib.py
index a4b22ea127..9c23dd6ba6 100644
--- a/neutron/agent/common/ovs_lib.py
+++ b/neutron/agent/common/ovs_lib.py
@@ -489,80 +489,35 @@ class OVSBridge(BaseOVS):
txn.add(self.ovsdb.db_set('Controller',
controller_uuid, *attr))
- def _create_qos_bw_limit_queue(self, port_name, max_bw_in_bits,
- max_burst_in_bits):
- external_ids = {'id': port_name}
- queue_other_config = {'min-rate': max_bw_in_bits,
- 'max-rate': max_bw_in_bits,
- 'burst': max_burst_in_bits}
-
- self.ovsdb.db_create(
- 'Queue', external_ids=external_ids,
- other_config=queue_other_config).execute(check_error=True)
-
- def _create_qos_bw_limit_profile(self, port_name, max_bw_in_bits):
- external_ids = {'id': port_name}
- queue = self.ovsdb.db_find(
- 'Queue',
- ('external_ids', '=', {'id': port_name}),
- columns=['_uuid']).execute(
- check_error=True)
- queues = {}
- queues[0] = queue[0]['_uuid']
- qos_other_config = {'max-rate': max_bw_in_bits}
- self.ovsdb.db_create('QoS', external_ids=external_ids,
- other_config=qos_other_config,
- type='linux-htb',
- queues=queues).execute(check_error=True)
-
- def create_qos_bw_limit_for_port(self, port_name, max_kbps,
- max_burst_kbps):
- # TODO(QoS) implement this with transactions,
- # or roll back on failure
- max_bw_in_bits = str(max_kbps * 1000)
- max_burst_in_bits = str(max_burst_kbps * 1000)
-
- self._create_qos_bw_limit_queue(port_name, max_bw_in_bits,
- max_burst_in_bits)
- self._create_qos_bw_limit_profile(port_name, max_bw_in_bits)
-
- qos = self.ovsdb.db_find('QoS',
- ('external_ids', '=', {'id': port_name}),
- columns=['_uuid']).execute(check_error=True)
- qos_profile = qos[0]['_uuid']
- self.set_db_attribute('Port', port_name, 'qos', qos_profile,
- check_error=True)
+ def _set_egress_bw_limit_for_port(self, port_name, max_kbps,
+ max_burst_kbps):
+ with self.ovsdb.transaction(check_error=True) as txn:
+ txn.add(self.ovsdb.db_set('Interface', port_name,
+ ('ingress_policing_rate', max_kbps)))
+ txn.add(self.ovsdb.db_set('Interface', port_name,
+ ('ingress_policing_burst',
+ max_burst_kbps)))
- def get_qos_bw_limit_for_port(self, port_name):
+ def create_egress_bw_limit_for_port(self, port_name, max_kbps,
+ max_burst_kbps):
+ self._set_egress_bw_limit_for_port(
+ port_name, max_kbps, max_burst_kbps)
- res = self.ovsdb.db_find(
- 'Queue',
- ('external_ids', '=', {'id': port_name}),
- columns=['other_config']).execute(check_error=True)
+ def get_egress_bw_limit_for_port(self, port_name):
- if res is None or len(res) == 0:
- return None, None
+ max_kbps = self.db_get_val('Interface', port_name,
+ 'ingress_policing_rate')
+ max_burst_kbps = self.db_get_val('Interface', port_name,
+ 'ingress_policing_burst')
- other_config = res[0]['other_config']
- max_kbps = int(other_config['max-rate']) / 1000
- max_burst_kbps = int(other_config['burst']) / 1000
- return max_kbps, max_burst_kbps
+ max_kbps = max_kbps or None
+ max_burst_kbps = max_burst_kbps or None
- def del_qos_bw_limit_for_port(self, port_name):
- qos = self.ovsdb.db_find('QoS',
- ('external_ids', '=', {'id': port_name}),
- columns=['_uuid']).execute(check_error=True)
- qos_row = qos[0]['_uuid']
-
- queue = self.ovsdb.db_find('Queue',
- ('external_ids', '=', {'id': port_name}),
- columns=['_uuid']).execute(check_error=True)
- queue_row = queue[0]['_uuid']
+ return max_kbps, max_burst_kbps
- with self.ovsdb.transaction(check_error=True) as txn:
- txn.add(self.ovsdb.db_set('Port', port_name, ('qos', [])))
- txn.add(self.ovsdb.db_destroy('QoS', qos_row))
- txn.add(self.ovsdb.db_destroy('Queue', queue_row))
+ def delete_egress_bw_limit_for_port(self, port_name):
+ self._set_egress_bw_limit_for_port(
+ port_name, 0, 0)
def __enter__(self):
self.create()
diff --git a/neutron/common/utils.py b/neutron/common/utils.py
index 579766fb42..6c9d9b17b7 100644
--- a/neutron/common/utils.py
+++ b/neutron/common/utils.py
@@ -19,6 +19,7 @@
"""Utilities and helper functions."""
import datetime
+import decimal
import errno
import functools
import hashlib
@@ -442,3 +443,10 @@ class DelayedStringRenderer(object):
def camelize(s):
return ''.join(s.replace('_', ' ').title().split())
+
+
+def round_val(val):
+ # we rely on decimal module since it behaves consistently across Python
+ # versions (2.x vs. 3.x)
+ return int(decimal.Decimal(val).quantize(decimal.Decimal('1'),
+ rounding=decimal.ROUND_HALF_UP))
diff --git a/neutron/core_extensions/qos.py b/neutron/core_extensions/qos.py
index c2caae0cf8..72fb898836 100644
--- a/neutron/core_extensions/qos.py
+++ b/neutron/core_extensions/qos.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from neutron.common import exceptions as n_exc
from neutron.core_extensions import base
from neutron.db import api as db_api
from neutron import manager
@@ -31,7 +32,10 @@ class QosCoreResourceExtension(base.CoreResourceExtension):
return self._plugin_loaded
def _get_policy_obj(self, context, policy_id):
- return policy_object.QosPolicy.get_by_id(context, policy_id)
+ obj = policy_object.QosPolicy.get_by_id(context, policy_id)
+ if obj is None:
+ raise n_exc.QosPolicyNotFound(policy_id=policy_id)
+ return obj
def _update_port_policy(self, context, port, port_changes):
old_policy = policy_object.QosPolicy.get_port_policy(
@@ -42,9 +46,6 @@ class QosCoreResourceExtension(base.CoreResourceExtension):
qos_policy_id = port_changes.get(qos_consts.QOS_POLICY_ID)
if qos_policy_id is not None:
policy = self._get_policy_obj(context, qos_policy_id)
- #TODO(QoS): If the policy doesn't exist (or if it is not shared and
- # the tenant id doesn't match the context's), this will
- # raise an exception (policy is None).
policy.attach_port(port['id'])
port[qos_consts.QOS_POLICY_ID] = qos_policy_id
@@ -57,9 +58,6 @@ class QosCoreResourceExtension(base.CoreResourceExtension):
qos_policy_id = network_changes.get(qos_consts.QOS_POLICY_ID)
if qos_policy_id is not None:
policy = self._get_policy_obj(context, qos_policy_id)
- #TODO(QoS): If the policy doesn't exist (or if it is not shared and
- # the tenant id doesn't match the context's), this will
- # raise an exception (policy is None).
policy.attach_network(network['id'])
network[qos_consts.QOS_POLICY_ID] = qos_policy_id
diff --git a/neutron/plugins/ml2/common/exceptions.py b/neutron/plugins/ml2/common/exceptions.py
index ed94b1e1f1..166711d8ee 100644
--- a/neutron/plugins/ml2/common/exceptions.py
+++ b/neutron/plugins/ml2/common/exceptions.py
@@ -21,3 +21,8 @@ from neutron.common import exceptions
class MechanismDriverError(exceptions.NeutronException):
"""Mechanism driver call failed."""
message = _("%(method)s failed.")
+
+
+class ExtensionDriverError(exceptions.InvalidInput):
+ """Extension driver call failed."""
+ message = _("Extension %(driver)s failed.")
diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py
index c426794373..12168883e8 100644
--- a/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py
+++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/eswitch_manager.py
@@ -20,6 +20,7 @@ import re
from oslo_log import log as logging
import six
+from neutron.common import utils
from neutron.i18n import _LE, _LW
from neutron.plugins.ml2.drivers.mech_sriov.agent.common \
import exceptions as exc
@@ -163,7 +164,30 @@ class EmbSwitch(object):
@param max_kbps: device max rate in kbps
"""
vf_index = self._get_vf_index(pci_slot)
- return self.pci_dev_wrapper.set_vf_max_rate(vf_index, max_kbps)
+ #(Note): ip link set max rate in Mbps therefore
+ #we need to convert the max_kbps to Mbps.
+ #Zero means to disable the rate so the lowest rate
+ #available is 1Mbps. Floating numbers are not allowed
+ if max_kbps > 0 and max_kbps < 1000:
+ max_mbps = 1
+ else:
+ max_mbps = utils.round_val(max_kbps / 1000.0)
+
+ log_dict = {
+ 'max_rate': max_mbps,
+ 'max_kbps': max_kbps,
+ 'vf_index': vf_index
+ }
+ if max_kbps % 1000 != 0:
+ LOG.debug("Maximum rate for SR-IOV ports is counted in Mbps; "
+ "setting %(max_rate)s Mbps limit for port %(vf_index)s "
+ "instead of %(max_kbps)s kbps",
+ log_dict)
+ else:
+ LOG.debug("Setting %(max_rate)s Mbps limit for port %(vf_index)s",
+ log_dict)
+
+ return self.pci_dev_wrapper.set_vf_max_rate(vf_index, max_mbps)
def _get_vf_index(self, pci_slot):
vf_index = self.pci_slot_map.get(pci_slot)
diff --git a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py
index a1e31cd666..8f984e0aac 100644
--- a/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py
+++ b/neutron/plugins/ml2/drivers/mech_sriov/agent/pci_lib.py
@@ -126,7 +126,7 @@ class PciDeviceIPWrapper(ip_lib.IPWrapper):
"""sets vf max rate.
@param vf_index: vf index
- @param max_tx_rate: vf max tx rate
+ @param max_tx_rate: vf max tx rate in Mbps
"""
try:
self._as_root([], "link", ("set", self.dev_name, "vf",
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 51c6564f58..ce9f286878 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
@@ -67,18 +67,10 @@ class QosOVSAgentDriver(qos.QosAgentDriver):
max_kbps = rule.max_kbps
max_burst_kbps = rule.max_burst_kbps
- current_max_kbps, current_max_burst = (
- self.br_int.get_qos_bw_limit_for_port(port_name))
- if current_max_kbps is not None or current_max_burst is not None:
- self.br_int.del_qos_bw_limit_for_port(port_name)
-
- self.br_int.create_qos_bw_limit_for_port(port_name,
- max_kbps,
- max_burst_kbps)
+ self.br_int.create_egress_bw_limit_for_port(port_name,
+ max_kbps,
+ max_burst_kbps)
def _delete_bandwidth_limit(self, port):
port_name = port['vif_port'].port_name
- current_max_kbps, current_max_burst = (
- self.br_int.get_qos_bw_limit_for_port(port_name))
- if current_max_kbps is not None or current_max_burst is not None:
- self.br_int.del_qos_bw_limit_for_port(port_name)
+ self.br_int.delete_egress_bw_limit_for_port(port_name)
diff --git a/neutron/plugins/ml2/managers.py b/neutron/plugins/ml2/managers.py
index d4b4908811..690e4ab4e2 100644
--- a/neutron/plugins/ml2/managers.py
+++ b/neutron/plugins/ml2/managers.py
@@ -15,6 +15,7 @@
from oslo_config import cfg
from oslo_log import log
+from oslo_utils import excutils
import six
import stevedore
@@ -800,10 +801,10 @@ class ExtensionManager(stevedore.named.NamedExtensionManager):
try:
getattr(driver.obj, method_name)(plugin_context, data, result)
except Exception:
- LOG.exception(
- _LE("Extension driver '%(name)s' failed in %(method)s"),
- {'name': driver.name, 'method': method_name}
- )
+ with excutils.save_and_reraise_exception():
+ LOG.info(_LI("Extension driver '%(name)s' failed in "
+ "%(method)s"),
+ {'name': driver.name, 'method': method_name})
def process_create_network(self, plugin_context, data, result):
"""Notify all extension drivers during network creation."""
@@ -835,23 +836,30 @@ class ExtensionManager(stevedore.named.NamedExtensionManager):
self._call_on_ext_drivers("process_update_port", plugin_context,
data, result)
+ def _call_on_dict_driver(self, method_name, session, base_model, result):
+ for driver in self.ordered_ext_drivers:
+ try:
+ getattr(driver.obj, method_name)(session, base_model, result)
+ except Exception:
+ LOG.error(_LE("Extension driver '%(name)s' failed in "
+ "%(method)s"),
+ {'name': driver.name, 'method': method_name})
+ raise ml2_exc.ExtensionDriverError(driver=driver.name)
+
+ LOG.debug("%(method)s succeeded for driver %(driver)s",
+ {'method': method_name, 'driver': driver.name})
+
def extend_network_dict(self, session, base_model, result):
"""Notify all extension drivers to extend network dictionary."""
- for driver in self.ordered_ext_drivers:
- driver.obj.extend_network_dict(session, base_model, result)
- LOG.debug("Extended network dict for driver '%(drv)s'",
- {'drv': driver.name})
+ self._call_on_dict_driver("extend_network_dict", session, base_model,
+ result)
def extend_subnet_dict(self, session, base_model, result):
"""Notify all extension drivers to extend subnet dictionary."""
- for driver in self.ordered_ext_drivers:
- driver.obj.extend_subnet_dict(session, base_model, result)
- LOG.debug("Extended subnet dict for driver '%(drv)s'",
- {'drv': driver.name})
+ self._call_on_dict_driver("extend_subnet_dict", session, base_model,
+ result)
def extend_port_dict(self, session, base_model, result):
"""Notify all extension drivers to extend port dictionary."""
- for driver in self.ordered_ext_drivers:
- driver.obj.extend_port_dict(session, base_model, result)
- LOG.debug("Extended port dict for driver '%(drv)s'",
- {'drv': driver.name})
+ self._call_on_dict_driver("extend_port_dict", session, base_model,
+ result)
diff --git a/neutron/tests/api/test_qos.py b/neutron/tests/api/test_qos.py
index b4cb4cc864..d281094b36 100644
--- a/neutron/tests/api/test_qos.py
+++ b/neutron/tests/api/test_qos.py
@@ -158,18 +158,24 @@ class QosTestJSON(base.BaseAdminNetworkTest):
self._disassociate_network(self.client, network['id'])
@test.attr(type='smoke')
+ @test.idempotent_id('9efe63d0-836f-4cc2-b00c-468e63aa614e')
+ def test_policy_association_with_network_nonexistent_policy(self):
+ self.assertRaises(
+ exceptions.NotFound,
+ self.create_network,
+ 'test network',
+ qos_policy_id='9efe63d0-836f-4cc2-b00c-468e63aa614e')
+
+ @test.attr(type='smoke')
@test.idempotent_id('1aa55a79-324f-47d9-a076-894a8fc2448b')
def test_policy_association_with_network_non_shared_policy(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
shared=False)
- #TODO(QoS): This currently raises an exception on the server side. See
- # core_extensions/qos.py for comments on this subject.
- network = self.create_network('test network',
- qos_policy_id=policy['id'])
-
- retrieved_network = self.admin_client.show_network(network['id'])
- self.assertIsNone(retrieved_network['network']['qos_policy_id'])
+ self.assertRaises(
+ exceptions.NotFound,
+ self.create_network,
+ 'test network', qos_policy_id=policy['id'])
@test.attr(type='smoke')
@test.idempotent_id('09a9392c-1359-4cbb-989f-fb768e5834a8')
@@ -210,18 +216,26 @@ class QosTestJSON(base.BaseAdminNetworkTest):
self._disassociate_port(port['id'])
@test.attr(type='smoke')
+ @test.idempotent_id('49e02f5a-e1dd-41d5-9855-cfa37f2d195e')
+ def test_policy_association_with_port_nonexistent_policy(self):
+ network = self.create_shared_network('test network')
+ self.assertRaises(
+ exceptions.NotFound,
+ self.create_port,
+ network,
+ qos_policy_id='49e02f5a-e1dd-41d5-9855-cfa37f2d195e')
+
+ @test.attr(type='smoke')
@test.idempotent_id('f53d961c-9fe5-4422-8b66-7add972c6031')
def test_policy_association_with_port_non_shared_policy(self):
policy = self.create_qos_policy(name='test-policy',
description='test policy',
shared=False)
network = self.create_shared_network('test network')
- #TODO(QoS): This currently raises an exception on the server side. See
- # core_extensions/qos.py for comments on this subject.
- port = self.create_port(network, qos_policy_id=policy['id'])
-
- retrieved_port = self.admin_client.show_port(port['id'])
- self.assertIsNone(retrieved_port['port']['qos_policy_id'])
+ self.assertRaises(
+ exceptions.NotFound,
+ self.create_port,
+ network, qos_policy_id=policy['id'])
@test.attr(type='smoke')
@test.idempotent_id('f8163237-fba9-4db5-9526-bad6d2343c76')
diff --git a/neutron/tests/common/agents/l2_extensions.py b/neutron/tests/common/agents/l2_extensions.py
index 0d46d3676d..11b354eeb3 100644
--- a/neutron/tests/common/agents/l2_extensions.py
+++ b/neutron/tests/common/agents/l2_extensions.py
@@ -18,7 +18,7 @@ from neutron.agent.linux import utils as agent_utils
def wait_until_bandwidth_limit_rule_applied(bridge, port_vif, rule):
def _bandwidth_limit_rule_applied():
- bw_rule = bridge.get_qos_bw_limit_for_port(port_vif)
+ bw_rule = bridge.get_egress_bw_limit_for_port(port_vif)
expected = None, None
if rule:
expected = rule.max_kbps, rule.max_burst_kbps
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 8fd8ee18b4..ad6e38b214 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
@@ -90,13 +90,13 @@ class OVSAgentQoSExtensionTestFramework(base.OVSAgentTestFramework):
def _assert_bandwidth_limit_rule_is_set(self, port, rule):
max_rate, burst = (
- self.agent.int_br.get_qos_bw_limit_for_port(port['vif_name']))
+ 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):
max_rate, burst = (
- self.agent.int_br.get_qos_bw_limit_for_port(port['vif_name']))
+ self.agent.int_br.get_egress_bw_limit_for_port(port['vif_name']))
self.assertIsNone(max_rate)
self.assertIsNone(burst)
@@ -104,6 +104,15 @@ class OVSAgentQoSExtensionTestFramework(base.OVSAgentTestFramework):
l2_extensions.wait_until_bandwidth_limit_rule_applied(
self.agent.int_br, port['vif_name'], rule)
+ 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,
+ TEST_BW_LIMIT_RULE_1)
+ return port_dict
+
class TestOVSAgentQosExtension(OVSAgentQoSExtensionTestFramework):
@@ -156,12 +165,7 @@ class TestOVSAgentQosExtension(OVSAgentQoSExtensionTestFramework):
"""Test that qos_policy_id set to None will remove all qos rules from
given port.
"""
- 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,
- TEST_BW_LIMIT_RULE_1)
+ port_dict = self._create_port_with_qos()
port_dict['qos_policy_id'] = None
self.agent.port_update(None, port=port_dict)
@@ -172,15 +176,19 @@ class TestOVSAgentQosExtension(OVSAgentQoSExtensionTestFramework):
"""Test that change of qos policy id on given port refreshes all its
rules.
"""
- 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,
- TEST_BW_LIMIT_RULE_1)
+ 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,
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()
+ consumer_reg.push(resources.QOS_POLICY, policy_copy, events.UPDATED)
+
+ self.wait_until_bandwidth_limit_rule_applied(port_dict, None)
diff --git a/neutron/tests/functional/agent/test_ovs_lib.py b/neutron/tests/functional/agent/test_ovs_lib.py
index fee80d8d3c..768209424a 100644
--- a/neutron/tests/functional/agent/test_ovs_lib.py
+++ b/neutron/tests/functional/agent/test_ovs_lib.py
@@ -311,14 +311,14 @@ class OVSBridgeTestCase(OVSBridgeTestBase):
controller,
'connection_mode'))
- def test_qos_bw_limit(self):
+ def test_egress_bw_limit(self):
port_name, _ = self.create_ovs_port()
- self.br.create_qos_bw_limit_for_port(port_name, 700, 70)
- max_rate, burst = self.br.get_qos_bw_limit_for_port(port_name)
+ self.br.create_egress_bw_limit_for_port(port_name, 700, 70)
+ max_rate, burst = self.br.get_egress_bw_limit_for_port(port_name)
self.assertEqual(700, max_rate)
self.assertEqual(70, burst)
- self.br.del_qos_bw_limit_for_port(port_name)
- max_rate, burst = self.br.get_qos_bw_limit_for_port(port_name)
+ self.br.delete_egress_bw_limit_for_port(port_name)
+ max_rate, burst = self.br.get_egress_bw_limit_for_port(port_name)
self.assertIsNone(max_rate)
self.assertIsNone(burst)
diff --git a/neutron/tests/unit/common/test_utils.py b/neutron/tests/unit/common/test_utils.py
index 20e764bfad..b604bbb27a 100644
--- a/neutron/tests/unit/common/test_utils.py
+++ b/neutron/tests/unit/common/test_utils.py
@@ -690,3 +690,13 @@ class TestCamelize(base.BaseTestCase):
for s, expected in data.items():
self.assertEqual(expected, utils.camelize(s))
+
+
+class TestRoundVal(base.BaseTestCase):
+ def test_round_val_ok(self):
+ for expected, value in ((0, 0),
+ (0, 0.1),
+ (1, 0.5),
+ (1, 1.49),
+ (2, 1.5)):
+ self.assertEqual(expected, utils.round_val(value))
diff --git a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py
index a2b480c705..b3a7d958a8 100644
--- a/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py
+++ b/neutron/tests/unit/plugins/ml2/drivers/mech_sriov/agent/test_eswitch_manager.py
@@ -297,8 +297,39 @@ class TestEmbSwitch(base.BaseTestCase):
def test_set_device_max_rate_ok(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
- "PciDeviceIPWrapper.set_vf_max_rate"):
- self.emb_switch.set_device_max_rate(self.PCI_SLOT, 1000)
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2000)
+ pci_lib_mock.assert_called_with(0, 2)
+
+ def test_set_device_max_rate_ok2(self):
+ with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 99)
+ pci_lib_mock.assert_called_with(0, 1)
+
+ def test_set_device_max_rate_rounded_ok(self):
+ with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2001)
+ pci_lib_mock.assert_called_with(0, 2)
+
+ def test_set_device_max_rate_rounded_ok2(self):
+ with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2499)
+ pci_lib_mock.assert_called_with(0, 2)
+
+ def test_set_device_max_rate_rounded_ok3(self):
+ with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 2500)
+ pci_lib_mock.assert_called_with(0, 3)
+
+ def test_set_device_max_rate_disable(self):
+ with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
+ "PciDeviceIPWrapper.set_vf_max_rate") as pci_lib_mock:
+ self.emb_switch.set_device_max_rate(self.PCI_SLOT, 0)
+ pci_lib_mock.assert_called_with(0, 0)
def test_set_device_max_rate_fail(self):
with mock.patch("neutron.plugins.ml2.drivers.mech_sriov.agent.pci_lib."
diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/extension_drivers/test_qos_driver.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/extension_drivers/test_qos_driver.py
index 7b6c430b7f..c9e276c72a 100644
--- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/extension_drivers/test_qos_driver.py
+++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/extension_drivers/test_qos_driver.py
@@ -30,13 +30,13 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
self.qos_driver = qos_driver.QosOVSAgentDriver()
self.qos_driver.initialize()
self.qos_driver.br_int = mock.Mock()
- self.qos_driver.br_int.get_qos_bw_limit_for_port = mock.Mock(
+ self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock(
return_value=(1000, 10))
- self.get = self.qos_driver.br_int.get_qos_bw_limit_for_port
- self.qos_driver.br_int.del_qos_bw_limit_for_port = mock.Mock()
- self.delete = self.qos_driver.br_int.del_qos_bw_limit_for_port
- self.qos_driver.br_int.create_qos_bw_limit_for_port = mock.Mock()
- self.create = self.qos_driver.br_int.create_qos_bw_limit_for_port
+ self.get = self.qos_driver.br_int.get_egress_bw_limit_for_port
+ self.qos_driver.br_int.del_egress_bw_limit_for_port = mock.Mock()
+ self.delete = self.qos_driver.br_int.delete_egress_bw_limit_for_port
+ self.qos_driver.br_int.create_egress_bw_limit_for_port = mock.Mock()
+ self.create = self.qos_driver.br_int.create_egress_bw_limit_for_port
self.rule = self._create_bw_limit_rule_obj()
self.qos_policy = self._create_qos_policy_obj([self.rule])
self.port = self._create_fake_port()
@@ -69,12 +69,12 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
return {'vif_port': FakeVifPort()}
def test_create_new_rule(self):
- self.qos_driver.br_int.get_qos_bw_limit_for_port = mock.Mock(
+ self.qos_driver.br_int.get_egress_bw_limit_for_port = mock.Mock(
return_value=(None, None))
self.qos_driver.create(self.port, self.qos_policy)
# Assert create is the last call
self.assertEqual(
- 'create_qos_bw_limit_for_port',
+ 'create_egress_bw_limit_for_port',
self.qos_driver.br_int.method_calls[-1][0])
self.assertEqual(0, self.delete.call_count)
self.create.assert_called_once_with(
@@ -96,11 +96,9 @@ class QosOVSAgentDriverTestCase(ovs_test_base.OVSAgentConfigTestBase):
def _assert_rule_create_updated(self):
# Assert create is the last call
self.assertEqual(
- 'create_qos_bw_limit_for_port',
+ 'create_egress_bw_limit_for_port',
self.qos_driver.br_int.method_calls[-1][0])
- self.delete.assert_called_once_with(self.port_name)
-
self.create.assert_called_once_with(
self.port_name, self.rule.max_kbps,
self.rule.max_burst_kbps)
diff --git a/neutron/tests/unit/plugins/ml2/test_extension_driver_api.py b/neutron/tests/unit/plugins/ml2/test_extension_driver_api.py
index bff70fecb5..78d6353385 100644
--- a/neutron/tests/unit/plugins/ml2/test_extension_driver_api.py
+++ b/neutron/tests/unit/plugins/ml2/test_extension_driver_api.py
@@ -11,6 +11,7 @@
# under the License.
import mock
+import uuid
from neutron import context
from neutron import manager
@@ -31,6 +32,58 @@ class ExtensionDriverTestCase(test_plugin.Ml2PluginV2TestCase):
self._plugin = manager.NeutronManager.get_plugin()
self._ctxt = context.get_admin_context()
+ def _verify_network_create(self, code, exc_reason):
+ tenant_id = str(uuid.uuid4())
+ data = {'network': {'name': 'net1',
+ 'tenant_id': tenant_id}}
+ req = self.new_create_request('networks', data)
+ res = req.get_response(self.api)
+ self.assertEqual(code, res.status_int)
+
+ network = self.deserialize(self.fmt, res)
+ if exc_reason:
+ self.assertEqual(exc_reason,
+ network['NeutronError']['type'])
+
+ return (network, tenant_id)
+
+ def _verify_network_update(self, network, code, exc_reason):
+ net_id = network['network']['id']
+ new_name = 'a_brand_new_name'
+ data = {'network': {'name': new_name}}
+ req = self.new_update_request('networks', data, net_id)
+ res = req.get_response(self.api)
+ self.assertEqual(code, res.status_int)
+ error = self.deserialize(self.fmt, res)
+ self.assertEqual(exc_reason,
+ error['NeutronError']['type'])
+
+ def test_faulty_process_create(self):
+ with mock.patch.object(ext_test.TestExtensionDriver,
+ 'process_create_network',
+ side_effect=TypeError):
+ net, tenant_id = self._verify_network_create(500,
+ 'HTTPInternalServerError')
+ # Verify the operation is rolled back
+ query_params = "tenant_id=%s" % tenant_id
+ nets = self._list('networks', query_params=query_params)
+ self.assertFalse(nets['networks'])
+
+ def test_faulty_process_update(self):
+ with mock.patch.object(ext_test.TestExtensionDriver,
+ 'process_update_network',
+ side_effect=TypeError):
+ network, tid = self._verify_network_create(201, None)
+ self._verify_network_update(network, 500,
+ 'HTTPInternalServerError')
+
+ def test_faulty_extend_dict(self):
+ with mock.patch.object(ext_test.TestExtensionDriver,
+ 'extend_network_dict',
+ side_effect=TypeError):
+ network, tid = self._verify_network_create(201, None)
+ self._verify_network_update(network, 400, 'ExtensionDriverError')
+
def test_network_attr(self):
with self.network() as network:
# Test create network