Merge "DSCP packet marking support in Linuxbridge agent"
This commit is contained in:
commit
920ddeaf58
@ -18,7 +18,9 @@ from oslo_log import log
|
||||
|
||||
from neutron._i18n import _LI
|
||||
from neutron.agent.l2.extensions import qos
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.agent.linux import tc_lib
|
||||
import neutron.common.constants as const
|
||||
from neutron.plugins.ml2.drivers.linuxbridge.mech_driver import (
|
||||
mech_linuxbridge)
|
||||
|
||||
@ -31,8 +33,28 @@ class QosLinuxbridgeAgentDriver(qos.QosAgentDriver):
|
||||
mech_linuxbridge.LinuxbridgeMechanismDriver.supported_qos_rule_types
|
||||
)
|
||||
|
||||
IPTABLES_DIRECTION = {const.INGRESS_DIRECTION: 'physdev-out',
|
||||
const.EGRESS_DIRECTION: 'physdev-in'}
|
||||
IPTABLES_DIRECTION_PREFIX = {const.INGRESS_DIRECTION: "i",
|
||||
const.EGRESS_DIRECTION: "o"}
|
||||
|
||||
def initialize(self):
|
||||
LOG.info(_LI("Initializing Linux bridge QoS extension"))
|
||||
self.iptables_manager = iptables_manager.IptablesManager(use_ipv6=True)
|
||||
|
||||
def _dscp_chain_name(self, direction, device):
|
||||
return iptables_manager.get_chain_name(
|
||||
"qos-%s%s" % (self.IPTABLES_DIRECTION_PREFIX[direction],
|
||||
device[3:]))
|
||||
|
||||
def _dscp_rule(self, direction, device):
|
||||
return ('-m physdev --%s %s --physdev-is-bridged '
|
||||
'-j $%s') % (self.IPTABLES_DIRECTION[direction],
|
||||
device,
|
||||
self._dscp_chain_name(direction, device))
|
||||
|
||||
def _dscp_rule_tag(self, device):
|
||||
return "dscp-%s" % device
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_bandwidth_limit(self, port, rule):
|
||||
@ -53,6 +75,74 @@ class QosLinuxbridgeAgentDriver(qos.QosAgentDriver):
|
||||
tc_wrapper = self._get_tc_wrapper(port)
|
||||
tc_wrapper.delete_filters_bw_limit()
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def create_dscp_marking(self, port, rule):
|
||||
with self.iptables_manager.defer_apply():
|
||||
self._set_outgoing_qos_chain_for_port(port)
|
||||
self._set_dscp_mark_rule(port, rule.dscp_mark)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def update_dscp_marking(self, port, rule):
|
||||
with self.iptables_manager.defer_apply():
|
||||
self._delete_dscp_mark_rule(port)
|
||||
self._set_outgoing_qos_chain_for_port(port)
|
||||
self._set_dscp_mark_rule(port, rule.dscp_mark)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def delete_dscp_marking(self, port):
|
||||
with self.iptables_manager.defer_apply():
|
||||
self._delete_dscp_mark_rule(port)
|
||||
self._delete_outgoing_qos_chain_for_port(port)
|
||||
|
||||
def _set_outgoing_qos_chain_for_port(self, port):
|
||||
chain_name = self._dscp_chain_name(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
chain_rule = self._dscp_rule(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
self.iptables_manager.ipv4['mangle'].add_chain(chain_name)
|
||||
self.iptables_manager.ipv6['mangle'].add_chain(chain_name)
|
||||
|
||||
self.iptables_manager.ipv4['mangle'].add_rule('POSTROUTING',
|
||||
chain_rule)
|
||||
self.iptables_manager.ipv6['mangle'].add_rule('POSTROUTING',
|
||||
chain_rule)
|
||||
|
||||
def _delete_outgoing_qos_chain_for_port(self, port):
|
||||
chain_name = self._dscp_chain_name(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
chain_rule = self._dscp_rule(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
if self._qos_chain_is_empty(port, 4):
|
||||
self.iptables_manager.ipv4['mangle'].remove_chain(chain_name)
|
||||
self.iptables_manager.ipv4['mangle'].remove_rule('POSTROUTING',
|
||||
chain_rule)
|
||||
if self._qos_chain_is_empty(port, 6):
|
||||
self.iptables_manager.ipv6['mangle'].remove_chain(chain_name)
|
||||
self.iptables_manager.ipv6['mangle'].remove_rule('POSTROUTING',
|
||||
chain_rule)
|
||||
|
||||
def _set_dscp_mark_rule(self, port, dscp_value):
|
||||
chain_name = self._dscp_chain_name(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
rule = "-j DSCP --set-dscp %s" % dscp_value
|
||||
self.iptables_manager.ipv4['mangle'].add_rule(
|
||||
chain_name, rule, tag=self._dscp_rule_tag(port['device']))
|
||||
self.iptables_manager.ipv6['mangle'].add_rule(
|
||||
chain_name, rule, tag=self._dscp_rule_tag(port['device']))
|
||||
|
||||
def _delete_dscp_mark_rule(self, port):
|
||||
self.iptables_manager.ipv4['mangle'].clear_rules_by_tag(
|
||||
self._dscp_rule_tag(port['device']))
|
||||
self.iptables_manager.ipv6['mangle'].clear_rules_by_tag(
|
||||
self._dscp_rule_tag(port['device']))
|
||||
|
||||
def _qos_chain_is_empty(self, port, ip_version=4):
|
||||
chain_name = self._dscp_chain_name(
|
||||
const.EGRESS_DIRECTION, port['device'])
|
||||
rules_in_chain = self.iptables_manager.get_chain(
|
||||
"mangle", chain_name, ip_version=ip_version)
|
||||
return len(rules_in_chain) == 0
|
||||
|
||||
def _get_tc_wrapper(self, port):
|
||||
return tc_lib.TcCommand(
|
||||
port['device'],
|
||||
|
@ -32,7 +32,8 @@ class LinuxbridgeMechanismDriver(mech_agent.SimpleAgentMechanismDriverBase):
|
||||
network.
|
||||
"""
|
||||
|
||||
supported_qos_rule_types = [qos_consts.RULE_TYPE_BANDWIDTH_LIMIT]
|
||||
supported_qos_rule_types = [qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_DSCP_MARKING]
|
||||
|
||||
def __init__(self):
|
||||
sg_enabled = securitygroups_rpc.is_firewall_enabled()
|
||||
|
@ -16,6 +16,7 @@
|
||||
import re
|
||||
|
||||
from neutron.agent.linux import async_process
|
||||
from neutron.agent.linux import iptables_manager
|
||||
from neutron.common import utils as common_utils
|
||||
|
||||
|
||||
@ -38,6 +39,15 @@ def extract_mod_nw_tos_action(flows):
|
||||
return tos_mark
|
||||
|
||||
|
||||
def extract_dscp_value_from_iptables_rules(rules):
|
||||
pattern = (r"^-A neutron-linuxbri-qos-.* -j DSCP "
|
||||
"--set-dscp (?P<dscp_value>0x[A-Fa-f0-9]+)$")
|
||||
for rule in rules:
|
||||
m = re.match(pattern, rule)
|
||||
if m:
|
||||
return int(m.group("dscp_value"), 16)
|
||||
|
||||
|
||||
def wait_until_bandwidth_limit_rule_applied(bridge, port_vif, rule):
|
||||
def _bandwidth_limit_rule_applied():
|
||||
bw_rule = bridge.get_egress_bw_limit_for_port(port_vif)
|
||||
@ -49,7 +59,7 @@ def wait_until_bandwidth_limit_rule_applied(bridge, port_vif, rule):
|
||||
common_utils.wait_until_true(_bandwidth_limit_rule_applied)
|
||||
|
||||
|
||||
def wait_until_dscp_marking_rule_applied(bridge, port_vif, rule):
|
||||
def wait_until_dscp_marking_rule_applied_ovs(bridge, port_vif, rule):
|
||||
def _dscp_marking_rule_applied():
|
||||
port_num = bridge.get_port_ofport(port_vif)
|
||||
|
||||
@ -64,6 +74,20 @@ def wait_until_dscp_marking_rule_applied(bridge, port_vif, rule):
|
||||
common_utils.wait_until_true(_dscp_marking_rule_applied)
|
||||
|
||||
|
||||
def wait_until_dscp_marking_rule_applied_linuxbridge(
|
||||
namespace, port_vif, expected_rule):
|
||||
|
||||
iptables = iptables_manager.IptablesManager(
|
||||
namespace=namespace)
|
||||
|
||||
def _dscp_marking_rule_applied():
|
||||
mangle_rules = iptables.get_rules_for_table("mangle")
|
||||
dscp_mark = extract_dscp_value_from_iptables_rules(mangle_rules)
|
||||
return dscp_mark == expected_rule
|
||||
|
||||
common_utils.wait_until_true(_dscp_marking_rule_applied)
|
||||
|
||||
|
||||
def wait_for_dscp_marked_packet(sender_vm, receiver_vm, dscp_mark):
|
||||
cmd = ["tcpdump", "-i", receiver_vm.port.name, "-nlt"]
|
||||
if dscp_mark:
|
||||
|
@ -45,14 +45,18 @@ DSCP_MARK = 16
|
||||
class BaseQoSRuleTestCase(object):
|
||||
of_interface = None
|
||||
ovsdb_interface = None
|
||||
number_of_hosts = 1
|
||||
|
||||
def setUp(self):
|
||||
host_desc = [environment.HostDescription(
|
||||
l3_agent=False,
|
||||
of_interface=self.of_interface,
|
||||
ovsdb_interface=self.ovsdb_interface,
|
||||
l2_agent_type=self.l2_agent_type)]
|
||||
env_desc = environment.EnvironmentDescription(qos=True)
|
||||
host_desc = [
|
||||
environment.HostDescription(
|
||||
l3_agent=False,
|
||||
of_interface=self.of_interface,
|
||||
ovsdb_interface=self.ovsdb_interface,
|
||||
l2_agent_type=self.l2_agent_type
|
||||
) for _ in range(self.number_of_hosts)]
|
||||
env_desc = environment.EnvironmentDescription(
|
||||
qos=True)
|
||||
env = environment.Environment(env_desc, host_desc)
|
||||
super(BaseQoSRuleTestCase, self).setUp(env)
|
||||
|
||||
@ -95,6 +99,9 @@ class BaseQoSRuleTestCase(object):
|
||||
|
||||
|
||||
class _TestBwLimitQoS(BaseQoSRuleTestCase):
|
||||
|
||||
number_of_hosts = 1
|
||||
|
||||
def _wait_for_bw_rule_removed(self, vm):
|
||||
# No values are provided when port doesn't have qos policy
|
||||
self._wait_for_bw_rule_applied(vm, None, None)
|
||||
@ -172,36 +179,9 @@ class TestBwLimitQoSLinuxbridge(_TestBwLimitQoS, base.BaseFullStackTestCase):
|
||||
lambda: tc.get_filters_bw_limits() == (limit, burst))
|
||||
|
||||
|
||||
class TestDscpMarkingQoSOvs(BaseQoSRuleTestCase, base.BaseFullStackTestCase):
|
||||
scenarios = fullstack_utils.get_ovs_interface_scenarios()
|
||||
l2_agent_type = constants.AGENT_TYPE_OVS
|
||||
class _TestDscpMarkingQoS(BaseQoSRuleTestCase):
|
||||
|
||||
def setUp(self):
|
||||
host_desc = [
|
||||
environment.HostDescription(
|
||||
l3_agent=False,
|
||||
of_interface=self.of_interface,
|
||||
ovsdb_interface=self.ovsdb_interface,
|
||||
l2_agent_type=self.l2_agent_type
|
||||
) for _ in range(2)]
|
||||
env_desc = environment.EnvironmentDescription(
|
||||
qos=True)
|
||||
env = environment.Environment(env_desc, host_desc)
|
||||
super(BaseQoSRuleTestCase, self).setUp(env)
|
||||
|
||||
self.tenant_id = uuidutils.generate_uuid()
|
||||
self.network = self.safe_client.create_network(self.tenant_id,
|
||||
'network-test')
|
||||
self.subnet = self.safe_client.create_subnet(
|
||||
self.tenant_id, self.network['id'],
|
||||
cidr='10.0.0.0/24',
|
||||
gateway_ip='10.0.0.1',
|
||||
name='subnet-test',
|
||||
enable_dhcp=False)
|
||||
|
||||
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
|
||||
l2_extensions.wait_until_dscp_marking_rule_applied(
|
||||
vm.bridge, vm.port.name, dscp_mark)
|
||||
number_of_hosts = 2
|
||||
|
||||
def _wait_for_dscp_marking_rule_removed(self, vm):
|
||||
self._wait_for_dscp_marking_rule_applied(vm, None)
|
||||
@ -272,19 +252,29 @@ class TestDscpMarkingQoSOvs(BaseQoSRuleTestCase, base.BaseFullStackTestCase):
|
||||
sender, receiver, DSCP_MARK)
|
||||
|
||||
|
||||
class TestDscpMarkingQoSOvs(_TestDscpMarkingQoS, base.BaseFullStackTestCase):
|
||||
scenarios = fullstack_utils.get_ovs_interface_scenarios()
|
||||
l2_agent_type = constants.AGENT_TYPE_OVS
|
||||
|
||||
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
|
||||
l2_extensions.wait_until_dscp_marking_rule_applied_ovs(
|
||||
vm.bridge, vm.port.name, dscp_mark)
|
||||
|
||||
|
||||
class TestDscpMarkingQoSLinuxbridge(_TestDscpMarkingQoS,
|
||||
base.BaseFullStackTestCase):
|
||||
l2_agent_type = constants.AGENT_TYPE_LINUXBRIDGE
|
||||
|
||||
def _wait_for_dscp_marking_rule_applied(self, vm, dscp_mark):
|
||||
l2_extensions.wait_until_dscp_marking_rule_applied_linuxbridge(
|
||||
vm.host.host_namespace, vm.port.name, dscp_mark)
|
||||
|
||||
|
||||
class TestQoSWithL2Population(base.BaseFullStackTestCase):
|
||||
|
||||
def setUp(self):
|
||||
# We limit this test to using the openvswitch mech driver, because DSCP
|
||||
# is presently not implemented for Linux Bridge. The 'rule_types' API
|
||||
# call only returns rule types that are supported by all configured
|
||||
# mech drivers. So in a fullstack scenario, where both the OVS and the
|
||||
# Linux Bridge mech drivers are configured, the DSCP rule type will be
|
||||
# unavailable since it is not implemented in Linux Bridge.
|
||||
mech_driver = 'openvswitch'
|
||||
host_desc = [] # No need to register agents for this test case
|
||||
env_desc = environment.EnvironmentDescription(qos=True, l2_pop=True,
|
||||
mech_drivers=mech_driver)
|
||||
env_desc = environment.EnvironmentDescription(qos=True, l2_pop=True)
|
||||
env = environment.Environment(env_desc, host_desc)
|
||||
super(TestQoSWithL2Population, self).setUp(env)
|
||||
|
||||
|
@ -141,7 +141,7 @@ class OVSAgentQoSExtensionTestFramework(base.OVSAgentTestFramework):
|
||||
self.assertIsNone(tos_mark)
|
||||
|
||||
def wait_until_dscp_marking_rule_applied(self, port, dscp_mark):
|
||||
l2_extensions.wait_until_dscp_marking_rule_applied(
|
||||
l2_extensions.wait_until_dscp_marking_rule_applied_ovs(
|
||||
self.agent.int_br, port['vif_name'], dscp_mark)
|
||||
|
||||
def _create_port_with_qos(self):
|
||||
|
@ -26,6 +26,7 @@ from neutron.tests import base
|
||||
|
||||
|
||||
TEST_LATENCY_VALUE = 100
|
||||
DSCP_VALUE = 32
|
||||
|
||||
|
||||
class QosLinuxbridgeAgentDriverTestCase(base.BaseTestCase):
|
||||
@ -35,7 +36,8 @@ class QosLinuxbridgeAgentDriverTestCase(base.BaseTestCase):
|
||||
cfg.CONF.set_override("tbf_latency", TEST_LATENCY_VALUE, "QOS")
|
||||
self.qos_driver = qos_driver.QosLinuxbridgeAgentDriver()
|
||||
self.qos_driver.initialize()
|
||||
self.rule = self._create_bw_limit_rule_obj()
|
||||
self.rule_bw_limit = self._create_bw_limit_rule_obj()
|
||||
self.rule_dscp_marking = self._create_dscp_marking_rule_obj()
|
||||
self.port = self._create_fake_port(uuidutils.generate_uuid())
|
||||
|
||||
def _create_bw_limit_rule_obj(self):
|
||||
@ -46,32 +48,150 @@ class QosLinuxbridgeAgentDriverTestCase(base.BaseTestCase):
|
||||
rule_obj.obj_reset_changes()
|
||||
return rule_obj
|
||||
|
||||
def _create_dscp_marking_rule_obj(self):
|
||||
rule_obj = rule.QosDscpMarkingRule()
|
||||
rule_obj.id = uuidutils.generate_uuid()
|
||||
rule_obj.dscp_mark = DSCP_VALUE
|
||||
rule_obj.obj_reset_changes()
|
||||
return rule_obj
|
||||
|
||||
def _create_fake_port(self, policy_id):
|
||||
return {'qos_policy_id': policy_id,
|
||||
'network_qos_policy_id': None,
|
||||
'device': 'fake_tap'}
|
||||
|
||||
def test_create_rule(self):
|
||||
def _dscp_mark_chain_name(self, device):
|
||||
return "qos-o%s" % device[3:]
|
||||
|
||||
def _dscp_postrouting_rule(self, device):
|
||||
return ("-m physdev --physdev-in %s --physdev-is-bridged "
|
||||
"-j $qos-o%s") % (device, device[3:])
|
||||
|
||||
def _dscp_rule(self, dscp_mark_value):
|
||||
return "-j DSCP --set-dscp %s" % dscp_mark_value
|
||||
|
||||
def _dscp_rule_tag(self, device):
|
||||
return "dscp-%s" % device
|
||||
|
||||
def test_create_bandwidth_limit(self):
|
||||
with mock.patch.object(
|
||||
tc_lib.TcCommand, "set_filters_bw_limit"
|
||||
) as set_bw_limit:
|
||||
self.qos_driver.create_bandwidth_limit(self.port, self.rule)
|
||||
self.qos_driver.create_bandwidth_limit(self.port,
|
||||
self.rule_bw_limit)
|
||||
set_bw_limit.assert_called_once_with(
|
||||
self.rule.max_kbps, self.rule.max_burst_kbps,
|
||||
self.rule_bw_limit.max_kbps, self.rule_bw_limit.max_burst_kbps,
|
||||
)
|
||||
|
||||
def test_update_rule(self):
|
||||
def test_update_bandwidth_limit(self):
|
||||
with mock.patch.object(
|
||||
tc_lib.TcCommand, "update_filters_bw_limit"
|
||||
) as update_bw_limit:
|
||||
self.qos_driver.update_bandwidth_limit(self.port, self.rule)
|
||||
self.qos_driver.update_bandwidth_limit(self.port,
|
||||
self.rule_bw_limit)
|
||||
update_bw_limit.assert_called_once_with(
|
||||
self.rule.max_kbps, self.rule.max_burst_kbps,
|
||||
self.rule_bw_limit.max_kbps, self.rule_bw_limit.max_burst_kbps,
|
||||
)
|
||||
|
||||
def test_delete_rule(self):
|
||||
def test_delete_bandwidth_limit(self):
|
||||
with mock.patch.object(
|
||||
tc_lib.TcCommand, "delete_filters_bw_limit"
|
||||
) as delete_bw_limit:
|
||||
self.qos_driver.delete_bandwidth_limit(self.port)
|
||||
delete_bw_limit.assert_called_once_with()
|
||||
|
||||
def test_create_dscp_marking(self):
|
||||
expected_calls = [
|
||||
mock.call.add_chain(
|
||||
self._dscp_mark_chain_name(self.port['device'])),
|
||||
mock.call.add_rule(
|
||||
"POSTROUTING",
|
||||
self._dscp_postrouting_rule(self.port['device'])),
|
||||
mock.call.add_rule(
|
||||
self._dscp_mark_chain_name(self.port['device']),
|
||||
self._dscp_rule(DSCP_VALUE),
|
||||
tag=self._dscp_rule_tag(self.port['device'])
|
||||
)
|
||||
]
|
||||
with mock.patch.object(
|
||||
self.qos_driver, "iptables_manager") as iptables_manager:
|
||||
|
||||
iptables_manager.ip4['mangle'] = mock.Mock()
|
||||
iptables_manager.ip6['mangle'] = mock.Mock()
|
||||
self.qos_driver.create_dscp_marking(
|
||||
self.port, self.rule_dscp_marking)
|
||||
iptables_manager.ipv4['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.ipv6['mangle'].assert_has_calls(expected_calls)
|
||||
|
||||
def test_update_dscp_marking(self):
|
||||
expected_calls = [
|
||||
mock.call.clear_rules_by_tag(
|
||||
self._dscp_rule_tag(self.port['device'])),
|
||||
mock.call.add_chain(
|
||||
self._dscp_mark_chain_name(self.port['device'])),
|
||||
mock.call.add_rule(
|
||||
"POSTROUTING",
|
||||
self._dscp_postrouting_rule(self.port['device'])),
|
||||
mock.call.add_rule(
|
||||
self._dscp_mark_chain_name(self.port['device']),
|
||||
self._dscp_rule(DSCP_VALUE),
|
||||
tag=self._dscp_rule_tag(self.port['device'])
|
||||
)
|
||||
]
|
||||
with mock.patch.object(
|
||||
self.qos_driver, "iptables_manager") as iptables_manager:
|
||||
|
||||
iptables_manager.ip4['mangle'] = mock.Mock()
|
||||
iptables_manager.ip6['mangle'] = mock.Mock()
|
||||
self.qos_driver.update_dscp_marking(
|
||||
self.port, self.rule_dscp_marking)
|
||||
iptables_manager.ipv4['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.ipv6['mangle'].assert_has_calls(expected_calls)
|
||||
|
||||
def test_delete_dscp_marking_chain_empty(self):
|
||||
dscp_chain_name = self._dscp_mark_chain_name(self.port['device'])
|
||||
expected_calls = [
|
||||
mock.call.clear_rules_by_tag(
|
||||
self._dscp_rule_tag(self.port['device'])),
|
||||
mock.call.remove_chain(
|
||||
dscp_chain_name),
|
||||
mock.call.remove_rule(
|
||||
"POSTROUTING",
|
||||
self._dscp_postrouting_rule(self.port['device']))
|
||||
]
|
||||
with mock.patch.object(
|
||||
self.qos_driver, "iptables_manager") as iptables_manager:
|
||||
|
||||
iptables_manager.ip4['mangle'] = mock.Mock()
|
||||
iptables_manager.ip6['mangle'] = mock.Mock()
|
||||
iptables_manager.get_chain = mock.Mock(return_value=[])
|
||||
self.qos_driver.delete_dscp_marking(self.port)
|
||||
iptables_manager.ipv4['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.ipv6['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.get_chain.assert_has_calls([
|
||||
mock.call("mangle", dscp_chain_name, ip_version=4),
|
||||
mock.call("mangle", dscp_chain_name, ip_version=6)
|
||||
])
|
||||
|
||||
def test_delete_dscp_marking_chain_not_empty(self):
|
||||
dscp_chain_name = self._dscp_mark_chain_name(self.port['device'])
|
||||
expected_calls = [
|
||||
mock.call.clear_rules_by_tag(
|
||||
self._dscp_rule_tag(self.port['device'])),
|
||||
]
|
||||
with mock.patch.object(
|
||||
self.qos_driver, "iptables_manager") as iptables_manager:
|
||||
|
||||
iptables_manager.ip4['mangle'] = mock.Mock()
|
||||
iptables_manager.ip6['mangle'] = mock.Mock()
|
||||
iptables_manager.get_chain = mock.Mock(
|
||||
return_value=["some other rule"])
|
||||
self.qos_driver.delete_dscp_marking(self.port)
|
||||
iptables_manager.ipv4['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.ipv6['mangle'].assert_has_calls(expected_calls)
|
||||
iptables_manager.get_chain.assert_has_calls([
|
||||
mock.call("mangle", dscp_chain_name, ip_version=4),
|
||||
mock.call("mangle", dscp_chain_name, ip_version=6)
|
||||
])
|
||||
iptables_manager.ipv4['mangle'].remove_chain.assert_not_called()
|
||||
iptables_manager.ipv4['mangle'].remove_rule.assert_not_called()
|
||||
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
prelude: >
|
||||
The LinuxBridge agent now supports QoS DSCP marking.
|
||||
features:
|
||||
- The LinuxBridge agent can now configure DSCP marking for packets outgoing
|
||||
for ports with QoS policy.
|
Loading…
Reference in New Issue
Block a user