Merge "Add setting default max_burst value if not given by user"
This commit is contained in:
@@ -23,6 +23,7 @@ import six
|
|||||||
|
|
||||||
from neutron._i18n import _LW, _LI
|
from neutron._i18n import _LW, _LI
|
||||||
from neutron.agent.l2 import agent_extension
|
from neutron.agent.l2 import agent_extension
|
||||||
|
from neutron.agent.linux import tc_lib
|
||||||
from neutron.api.rpc.callbacks.consumer import registry
|
from neutron.api.rpc.callbacks.consumer import registry
|
||||||
from neutron.api.rpc.callbacks import events
|
from neutron.api.rpc.callbacks import events
|
||||||
from neutron.api.rpc.callbacks import resources
|
from neutron.api.rpc.callbacks import resources
|
||||||
@@ -121,6 +122,15 @@ class QosAgentDriver(object):
|
|||||||
LOG.debug("Port %(port)s excluded from QoS rule %(rule)s",
|
LOG.debug("Port %(port)s excluded from QoS rule %(rule)s",
|
||||||
{'port': port, 'rule': rule.id})
|
{'port': port, 'rule': rule.id})
|
||||||
|
|
||||||
|
def _get_egress_burst_value(self, rule):
|
||||||
|
"""Return burst value used for egress bandwidth limitation.
|
||||||
|
|
||||||
|
Because Egress bw_limit is done on ingress qdisc by LB and ovs drivers
|
||||||
|
so it will return burst_value used by tc on as ingress_qdisc.
|
||||||
|
"""
|
||||||
|
return tc_lib.TcCommand.get_ingress_qdisc_burst_value(
|
||||||
|
rule.max_kbps, rule.max_burst_kbps)
|
||||||
|
|
||||||
|
|
||||||
class PortPolicyMap(object):
|
class PortPolicyMap(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from neutron_lib import exceptions
|
|||||||
|
|
||||||
from neutron._i18n import _
|
from neutron._i18n import _
|
||||||
from neutron.agent.linux import ip_lib
|
from neutron.agent.linux import ip_lib
|
||||||
|
from neutron.services.qos import qos_consts
|
||||||
|
|
||||||
|
|
||||||
INGRESS_QDISC_ID = "ffff:"
|
INGRESS_QDISC_ID = "ffff:"
|
||||||
@@ -102,6 +103,17 @@ class TcCommand(ip_lib.IPDevice):
|
|||||||
ip_wrapper = ip_lib.IPWrapper(self.namespace)
|
ip_wrapper = ip_lib.IPWrapper(self.namespace)
|
||||||
return ip_wrapper.netns.execute(cmd, run_as_root=True, **kwargs)
|
return ip_wrapper.netns.execute(cmd, run_as_root=True, **kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_ingress_qdisc_burst_value(bw_limit, burst_limit):
|
||||||
|
"""Return burst value used in ingress qdisc.
|
||||||
|
|
||||||
|
If burst value is not specified given than it will be set to default
|
||||||
|
rate to ensure that limit for TCP traffic will work well
|
||||||
|
"""
|
||||||
|
if not burst_limit:
|
||||||
|
return float(bw_limit) * qos_consts.DEFAULT_BURST_RATE
|
||||||
|
return burst_limit
|
||||||
|
|
||||||
def get_filters_bw_limits(self, qdisc_id=INGRESS_QDISC_ID):
|
def get_filters_bw_limits(self, qdisc_id=INGRESS_QDISC_ID):
|
||||||
cmd = ['filter', 'show', 'dev', self.name, 'parent', qdisc_id]
|
cmd = ['filter', 'show', 'dev', self.name, 'parent', qdisc_id]
|
||||||
cmd_result = self._execute_tc_cmd(cmd)
|
cmd_result = self._execute_tc_cmd(cmd)
|
||||||
@@ -190,14 +202,6 @@ class TcCommand(ip_lib.IPDevice):
|
|||||||
# are trying to delete qdisc
|
# are trying to delete qdisc
|
||||||
return self._execute_tc_cmd(cmd, extra_ok_codes=[2])
|
return self._execute_tc_cmd(cmd, extra_ok_codes=[2])
|
||||||
|
|
||||||
def _get_filters_burst_value(self, bw_limit, burst_limit):
|
|
||||||
if not burst_limit:
|
|
||||||
# NOTE(slaweq): If burst value was not specified by user than it
|
|
||||||
# will be set as 80% of bw_limit to ensure that limit for TCP
|
|
||||||
# traffic will work well:
|
|
||||||
return float(bw_limit) * 0.8
|
|
||||||
return burst_limit
|
|
||||||
|
|
||||||
def _get_tbf_burst_value(self, bw_limit, burst_limit):
|
def _get_tbf_burst_value(self, bw_limit, burst_limit):
|
||||||
min_burst_value = float(bw_limit) / float(self.kernel_hz)
|
min_burst_value = float(bw_limit) / float(self.kernel_hz)
|
||||||
return max(min_burst_value, burst_limit)
|
return max(min_burst_value, burst_limit)
|
||||||
@@ -220,7 +224,9 @@ class TcCommand(ip_lib.IPDevice):
|
|||||||
qdisc_id=INGRESS_QDISC_ID):
|
qdisc_id=INGRESS_QDISC_ID):
|
||||||
rate_limit = "%s%s" % (bw_limit, BW_LIMIT_UNIT)
|
rate_limit = "%s%s" % (bw_limit, BW_LIMIT_UNIT)
|
||||||
burst = "%s%s" % (
|
burst = "%s%s" % (
|
||||||
self._get_filters_burst_value(bw_limit, burst_limit), BURST_UNIT)
|
self.get_ingress_qdisc_burst_value(bw_limit, burst_limit),
|
||||||
|
BURST_UNIT
|
||||||
|
)
|
||||||
#NOTE(slaweq): it is made in exactly same way how openvswitch is doing
|
#NOTE(slaweq): it is made in exactly same way how openvswitch is doing
|
||||||
# it when configuing ingress traffic limit on port. It can be found in
|
# it when configuing ingress traffic limit on port. It can be found in
|
||||||
# lib/netdev-linux.c#L4698 in openvswitch sources:
|
# lib/netdev-linux.c#L4698 in openvswitch sources:
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ class QosLinuxbridgeAgentDriver(qos.QosAgentDriver):
|
|||||||
def create_bandwidth_limit(self, port, rule):
|
def create_bandwidth_limit(self, port, rule):
|
||||||
tc_wrapper = self._get_tc_wrapper(port)
|
tc_wrapper = self._get_tc_wrapper(port)
|
||||||
tc_wrapper.set_filters_bw_limit(
|
tc_wrapper.set_filters_bw_limit(
|
||||||
rule.max_kbps, rule.max_burst_kbps
|
rule.max_kbps, self._get_egress_burst_value(rule)
|
||||||
)
|
)
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def update_bandwidth_limit(self, port, rule):
|
def update_bandwidth_limit(self, port, rule):
|
||||||
tc_wrapper = self._get_tc_wrapper(port)
|
tc_wrapper = self._get_tc_wrapper(port)
|
||||||
tc_wrapper.update_filters_bw_limit(
|
tc_wrapper.update_filters_bw_limit(
|
||||||
rule.max_kbps, rule.max_burst_kbps
|
rule.max_kbps, self._get_egress_burst_value(rule)
|
||||||
)
|
)
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ class QosOVSAgentDriver(qos.QosAgentDriver):
|
|||||||
"deleted", port_id)
|
"deleted", port_id)
|
||||||
return
|
return
|
||||||
max_kbps = rule.max_kbps
|
max_kbps = rule.max_kbps
|
||||||
max_burst_kbps = rule.max_burst_kbps
|
# NOTE(slaweq): According to ovs docs:
|
||||||
|
# http://openvswitch.org/support/dist-docs/ovs-vswitchd.conf.db.5.html
|
||||||
|
# ovs accepts only integer values of burst:
|
||||||
|
max_burst_kbps = int(self._get_egress_burst_value(rule))
|
||||||
|
|
||||||
self.br_int.create_egress_bw_limit_for_port(vif_port.port_name,
|
self.br_int.create_egress_bw_limit_for_port(vif_port.port_name,
|
||||||
max_kbps,
|
max_kbps,
|
||||||
|
|||||||
@@ -18,3 +18,9 @@ RULE_TYPE_DSCP_MARK = 'dscp_marking'
|
|||||||
VALID_RULE_TYPES = [RULE_TYPE_BANDWIDTH_LIMIT, RULE_TYPE_DSCP_MARK]
|
VALID_RULE_TYPES = [RULE_TYPE_BANDWIDTH_LIMIT, RULE_TYPE_DSCP_MARK]
|
||||||
|
|
||||||
QOS_POLICY_ID = 'qos_policy_id'
|
QOS_POLICY_ID = 'qos_policy_id'
|
||||||
|
|
||||||
|
# NOTE(slaweq): Value used to calculate burst value for egress bandwidth limit
|
||||||
|
# if burst is not given by user. In such case burst value will be calculated
|
||||||
|
# as 80% of bw_limit to ensure that at least limits for TCP traffic will work
|
||||||
|
# fine.
|
||||||
|
DEFAULT_BURST_RATE = 0.8
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ class TestQoSWithL2Agent(base.BaseFullStackTestCase):
|
|||||||
|
|
||||||
def test_qos_policy_rule_lifecycle(self):
|
def test_qos_policy_rule_lifecycle(self):
|
||||||
new_limit = BANDWIDTH_LIMIT + 100
|
new_limit = BANDWIDTH_LIMIT + 100
|
||||||
new_burst = BANDWIDTH_BURST + 50
|
|
||||||
|
|
||||||
self.tenant_id = uuidutils.generate_uuid()
|
self.tenant_id = uuidutils.generate_uuid()
|
||||||
self.network = self.safe_client.create_network(self.tenant_id,
|
self.network = self.safe_client.create_network(self.tenant_id,
|
||||||
@@ -141,10 +140,15 @@ class TestQoSWithL2Agent(base.BaseFullStackTestCase):
|
|||||||
self.client.delete_bandwidth_limit_rule(rule['id'], qos_policy_id)
|
self.client.delete_bandwidth_limit_rule(rule['id'], qos_policy_id)
|
||||||
_wait_for_rule_removed(vm)
|
_wait_for_rule_removed(vm)
|
||||||
|
|
||||||
# Create new rule
|
# Create new rule with no given burst value, in such case ovs and lb
|
||||||
|
# agent should apply burst value as
|
||||||
|
# bandwidth_limit * qos_consts.DEFAULT_BURST_RATE
|
||||||
|
new_expected_burst = int(
|
||||||
|
new_limit * qos_consts.DEFAULT_BURST_RATE
|
||||||
|
)
|
||||||
new_rule = self.safe_client.create_bandwidth_limit_rule(
|
new_rule = self.safe_client.create_bandwidth_limit_rule(
|
||||||
self.tenant_id, qos_policy_id, new_limit, new_burst)
|
self.tenant_id, qos_policy_id, new_limit)
|
||||||
_wait_for_rule_applied(vm, new_limit, new_burst)
|
_wait_for_rule_applied(vm, new_limit, new_expected_burst)
|
||||||
|
|
||||||
# Update qos policy rule id
|
# Update qos policy rule id
|
||||||
self.client.update_bandwidth_limit_rule(
|
self.client.update_bandwidth_limit_rule(
|
||||||
|
|||||||
@@ -124,6 +124,14 @@ class QosAgentDriverTestCase(base.BaseTestCase):
|
|||||||
self.driver.create(self.port, self.policy)
|
self.driver.create(self.port, self.policy)
|
||||||
self.assertTrue(self.driver.create_bandwidth_limit.called)
|
self.assertTrue(self.driver.create_bandwidth_limit.called)
|
||||||
|
|
||||||
|
def test__get_max_burst_value(self):
|
||||||
|
rule = self.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)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class QosExtensionBaseTestCase(base.BaseTestCase):
|
class QosExtensionBaseTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from neutron.agent.linux import tc_lib
|
from neutron.agent.linux import tc_lib
|
||||||
|
from neutron.services.qos import qos_consts
|
||||||
from neutron.tests import base
|
from neutron.tests import base
|
||||||
|
|
||||||
DEVICE_NAME = "tap_device"
|
DEVICE_NAME = "tap_device"
|
||||||
@@ -275,23 +276,23 @@ class TestTcCommand(base.BaseTestCase):
|
|||||||
extra_ok_codes=[2]
|
extra_ok_codes=[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
def test__get_filters_burst_value_burst_not_none(self):
|
def test_get_ingress_qdisc_burst_value_burst_not_none(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
BURST, self.tc._get_filters_burst_value(BW_LIMIT, BURST)
|
BURST, self.tc.get_ingress_qdisc_burst_value(BW_LIMIT, BURST)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test__get_filters_burst_no_burst_value_given(self):
|
def test_get_ingress_qdisc_burst_no_burst_value_given(self):
|
||||||
expected_burst = BW_LIMIT * 0.8
|
expected_burst = BW_LIMIT * qos_consts.DEFAULT_BURST_RATE
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_burst,
|
expected_burst,
|
||||||
self.tc._get_filters_burst_value(BW_LIMIT, None)
|
self.tc.get_ingress_qdisc_burst_value(BW_LIMIT, None)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test__get_filters_burst_burst_value_zero(self):
|
def test_get_ingress_qdisc_burst_burst_value_zero(self):
|
||||||
expected_burst = BW_LIMIT * 0.8
|
expected_burst = BW_LIMIT * qos_consts.DEFAULT_BURST_RATE
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
expected_burst,
|
expected_burst,
|
||||||
self.tc._get_filters_burst_value(BW_LIMIT, 0)
|
self.tc.get_ingress_qdisc_burst_value(BW_LIMIT, 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test__get_tbf_burst_value_when_burst_bigger_then_minimal(self):
|
def test__get_tbf_burst_value_when_burst_bigger_then_minimal(self):
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
By default, the QoS driver for the Open vSwitch
|
||||||
|
and Linuxbridge agents calculates the burst value
|
||||||
|
as 80% of the available bandwidth.
|
||||||
|
fixes:
|
||||||
|
- Fixes bug 1572670
|
||||||
Reference in New Issue
Block a user