Merge "Fullstack tests of packet rate limit for ovs qos driver"
This commit is contained in:
commit
f8673c0516
@ -17,6 +17,7 @@ import collections
|
||||
import functools
|
||||
import itertools
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
import uuid
|
||||
|
||||
@ -84,6 +85,11 @@ ActionFlowTuple = collections.namedtuple('ActionFlowTuple',
|
||||
['action', 'flow', 'flow_group_id'])
|
||||
|
||||
|
||||
MAX_METER_REGEX = re.compile(r"max_meter:(\w+) max_bands:(\w+) *")
|
||||
BAND_TYPES_REGEX = re.compile(r"band_types: (\w+)")
|
||||
CAPS_REGEX = re.compile(r"capabilities: (\w+) (\w+) (\w+) (\w+)")
|
||||
|
||||
|
||||
def _ovsdb_result_pending(result):
|
||||
"""Return True if ovsdb indicates the result is still pending."""
|
||||
# ovsdb can return '[]' for an ofport that has not yet been assigned
|
||||
@ -449,6 +455,24 @@ class OVSBridge(BaseOVS):
|
||||
def remove_all_flows(self):
|
||||
self.run_ofctl("del-flows", [])
|
||||
|
||||
def list_meter_features(self):
|
||||
# For fullstack test mainly
|
||||
f_list = self.run_ofctl("meter-features", []).split("\n")[1:]
|
||||
max_meter = max_bands = support_drop = support_caps = None
|
||||
for output in f_list:
|
||||
match = MAX_METER_REGEX.match(output)
|
||||
if match:
|
||||
max_meter = match.group(1)
|
||||
max_bands = match.group(2)
|
||||
match = BAND_TYPES_REGEX.match(output)
|
||||
if match:
|
||||
support_drop = match.group(1)
|
||||
match = CAPS_REGEX.match(output)
|
||||
if match:
|
||||
support_caps = [match.group(1), match.group(2),
|
||||
match.group(3), match.group(4)]
|
||||
return all([max_meter, max_bands, support_drop, support_caps])
|
||||
|
||||
@_ovsdb_retry
|
||||
def _get_port_val(self, port_name, port_val):
|
||||
return self.db_get_val("Interface", port_name, port_val)
|
||||
|
@ -86,6 +86,29 @@ def wait_until_dscp_marking_rule_applied_ovs(bridge, port_vif, rule):
|
||||
common_utils.wait_until_true(_dscp_marking_rule_applied)
|
||||
|
||||
|
||||
def wait_until_pkt_meter_rule_applied_ovs(bridge, port_vif, port_id,
|
||||
direction, mac=None):
|
||||
def _pkt_rate_limit_rule_applied():
|
||||
port_num = bridge.get_port_ofport(port_vif)
|
||||
port_vlan = bridge.get_port_tag_by_name(port_vif)
|
||||
key = "%s_%s" % (port_id, direction)
|
||||
meter_id = bridge.get_value_from_other_config(
|
||||
port_vif, key, value_type=int)
|
||||
|
||||
if direction == "egress":
|
||||
flows = bridge.dump_flows_for(table='59', in_port=str(port_num),
|
||||
dl_src=str(mac))
|
||||
else:
|
||||
flows = bridge.dump_flows_for(table='59', dl_vlan=str(port_vlan),
|
||||
dl_dst=str(mac))
|
||||
if mac:
|
||||
return bool(flows) and meter_id
|
||||
else:
|
||||
return not bool(flows) and not meter_id
|
||||
|
||||
common_utils.wait_until_true(_pkt_rate_limit_rule_applied)
|
||||
|
||||
|
||||
def wait_until_dscp_marking_rule_applied_linuxbridge(namespace, port_vif,
|
||||
expected_rule):
|
||||
|
||||
|
@ -283,6 +283,27 @@ class ClientFixture(fixtures.Fixture):
|
||||
|
||||
return rule['bandwidth_limit_rule']
|
||||
|
||||
def create_packet_rate_limit_rule(
|
||||
self, project_id, qos_policy_id, limit=None,
|
||||
burst=None, direction=None):
|
||||
rule = {'project_id': project_id}
|
||||
if limit:
|
||||
rule['max_kpps'] = limit
|
||||
if burst:
|
||||
rule['max_burst_kpps'] = burst
|
||||
if direction:
|
||||
rule['direction'] = direction
|
||||
rule = self.client.create_packet_rate_limit_rule(
|
||||
policy=qos_policy_id,
|
||||
body={'packet_rate_limit_rule': rule})
|
||||
|
||||
self.addCleanup(
|
||||
_safe_method(self.client.delete_packet_rate_limit_rule),
|
||||
rule['packet_rate_limit_rule']['id'],
|
||||
qos_policy_id)
|
||||
|
||||
return rule['packet_rate_limit_rule']
|
||||
|
||||
def create_minimum_bandwidth_rule(self, tenant_id, qos_policy_id,
|
||||
min_bw, direction=None):
|
||||
rule = {'tenant_id': tenant_id,
|
||||
|
@ -45,6 +45,9 @@ BANDWIDTH_LIMIT = 500
|
||||
MIN_BANDWIDTH = 300
|
||||
DSCP_MARK = 16
|
||||
|
||||
PACKET_RATE_LIMIT = 10000
|
||||
PACKET_RATE_BURST = 1000
|
||||
|
||||
|
||||
class BaseQoSRuleTestCase(object):
|
||||
number_of_hosts = 1
|
||||
@ -546,6 +549,96 @@ class TestDscpMarkingQoSLinuxbridge(_TestDscpMarkingQoS,
|
||||
vm.host.host_namespace, vm.port.name, dscp_mark)
|
||||
|
||||
|
||||
class _TestPacketRateLimitQoS(BaseQoSRuleTestCase):
|
||||
|
||||
number_of_hosts = 1
|
||||
|
||||
def _wait_for_packet_rate_limit_rule_applied(self, vm, direction):
|
||||
l2_extensions.wait_until_pkt_meter_rule_applied_ovs(
|
||||
vm.bridge, vm.port.name, vm.neutron_port['id'],
|
||||
direction, vm.mac_address)
|
||||
|
||||
def _wait_for_packet_rate_limit_rule_removed(self, vm, direction):
|
||||
l2_extensions.wait_until_pkt_meter_rule_applied_ovs(
|
||||
vm.bridge, vm.port.name, vm.neutron_port['id'], direction)
|
||||
|
||||
def _add_packet_rate_limit_rule(self, limit, burst, direction, qos_policy):
|
||||
qos_policy_id = qos_policy['id']
|
||||
rule = self.safe_client.create_packet_rate_limit_rule(
|
||||
self.tenant_id, qos_policy_id, limit, burst, direction)
|
||||
rule['type'] = qos_consts.RULE_TYPE_PACKET_RATE_LIMIT
|
||||
rule['qos_policy_id'] = qos_policy_id
|
||||
qos_policy['rules'].append(rule)
|
||||
|
||||
def _create_vm_with_limit_rules(self):
|
||||
# Create port with qos policy attached, with different direction
|
||||
vm, qos_policy = self._prepare_vm_with_qos_policy(
|
||||
[functools.partial(
|
||||
self._add_packet_rate_limit_rule,
|
||||
PACKET_RATE_LIMIT, PACKET_RATE_BURST, self.direction),
|
||||
functools.partial(
|
||||
self._add_packet_rate_limit_rule,
|
||||
PACKET_RATE_LIMIT, PACKET_RATE_BURST, self.reverse_direction)])
|
||||
|
||||
self._wait_for_packet_rate_limit_rule_applied(
|
||||
vm, self.direction)
|
||||
self._wait_for_packet_rate_limit_rule_applied(
|
||||
vm, self.reverse_direction)
|
||||
return vm, qos_policy
|
||||
|
||||
def test_packet_rate_limit_qos_policy_rule_lifecycle(self):
|
||||
new_limit = PACKET_RATE_LIMIT + 100
|
||||
|
||||
# Create port with qos policy attached
|
||||
vm, qos_policy = self._prepare_vm_with_qos_policy(
|
||||
[functools.partial(
|
||||
self._add_packet_rate_limit_rule,
|
||||
PACKET_RATE_LIMIT, PACKET_RATE_BURST, self.direction)])
|
||||
|
||||
vm.bridge.use_at_least_protocol(ovs_constants.OPENFLOW13)
|
||||
if not vm.bridge.list_meter_features():
|
||||
self.skip("Test ovs bridge %s does not support meter.",
|
||||
vm.bridge.br_name)
|
||||
|
||||
pkt_rule = qos_policy['rules'][0]
|
||||
self._wait_for_packet_rate_limit_rule_applied(
|
||||
vm, self.direction)
|
||||
qos_policy_id = qos_policy['id']
|
||||
|
||||
self.client.delete_packet_rate_limit_rule(pkt_rule['id'],
|
||||
qos_policy_id)
|
||||
self._wait_for_packet_rate_limit_rule_removed(vm, self.direction)
|
||||
|
||||
new_rule = self.safe_client.create_packet_rate_limit_rule(
|
||||
self.tenant_id, qos_policy_id, new_limit, direction=self.direction)
|
||||
self._wait_for_packet_rate_limit_rule_applied(
|
||||
vm, self.direction)
|
||||
|
||||
# Update qos policy rule id
|
||||
self.client.update_packet_rate_limit_rule(
|
||||
new_rule['id'], qos_policy_id,
|
||||
body={'packet_rate_limit_rule': {
|
||||
'max_kpps': PACKET_RATE_LIMIT,
|
||||
'max_burst_kpps': PACKET_RATE_BURST}})
|
||||
self._wait_for_packet_rate_limit_rule_applied(
|
||||
vm, self.direction)
|
||||
|
||||
# Remove qos policy from port
|
||||
self.client.update_port(
|
||||
vm.neutron_port['id'],
|
||||
body={'port': {'qos_policy_id': None}})
|
||||
self._wait_for_packet_rate_limit_rule_removed(vm, self.direction)
|
||||
|
||||
|
||||
class TestPacketRateLimitQoSOvs(_TestPacketRateLimitQoS,
|
||||
base.BaseFullStackTestCase):
|
||||
l2_agent_type = constants.AGENT_TYPE_OVS
|
||||
scenarios = [
|
||||
('ingress', {'direction': constants.INGRESS_DIRECTION}),
|
||||
('egress', {'direction': constants.EGRESS_DIRECTION})
|
||||
]
|
||||
|
||||
|
||||
class TestQoSWithL2Population(base.BaseFullStackTestCase):
|
||||
scenarios = [
|
||||
(constants.AGENT_TYPE_OVS,
|
||||
|
Loading…
x
Reference in New Issue
Block a user