vmware-nsx-tempest-plugin/vmware_nsx_tempest_plugin/tests/scenario/test_qos.py

494 lines
22 KiB
Python

# Copyright 2017 VMware Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import subprocess
import time
from oslo_log import log as logging
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest import test
from vmware_nsx_tempest_plugin.lib import feature_manager
from vmware_nsx_tempest_plugin.services import nsx_client
CONF = config.CONF
CONF.validation.auth_method = 'None'
LOG = logging.getLogger(__name__)
DSCP_MARK = 12
DSCP_MARK_UPDATED = 16
BW_VALUE_KBPS = 1024
BW_VALUE_MBPS = 1
UPDATED_BW_VALUE_KBPS = 2048
UPDATED_BW_VALUE_MBPS = 2
MAX_BURST_KBPS = 1024000
MAX_BURST_MBPS = 1
class TestQosOps(feature_manager.FeatureManager):
@classmethod
def skip_checks(cls):
super(TestQosOps, cls).skip_checks()
if not (CONF.network.project_networks_reachable or
CONF.network.public_network_id):
msg = ('Either project_networks_reachable must be "true", or '
'public_network_id must be defined.')
raise cls.skipException(msg)
if not CONF.network.public_network_cidr:
msg = "public_network_cidr must be defined in network section."
raise cls.skipException(msg)
if not test.is_extension_enabled('qos', 'network'):
msg = "q-qos extension not enabled."
raise cls.skipException(msg)
@classmethod
def setup_credentials(cls):
cls.set_network_resources()
cls.admin_mgr = cls.get_client_manager('admin')
super(TestQosOps, cls).setup_credentials()
@classmethod
def setup_clients(cls):
"""
Create various client connections. Such as NSX.
"""
super(TestQosOps, cls).setup_clients()
cls.nsx_client = nsx_client.NSXClient(
CONF.network.backend,
CONF.nsxv3.nsx_manager,
CONF.nsxv3.nsx_user,
CONF.nsxv3.nsx_password)
def define_security_groups(self):
self.qos_sg = self.create_topology_empty_security_group(
namestart="qos_sg_")
# Common rules to allow the following traffic
# 1. Egress ICMP IPv4 any any
# 2. Egress ICMP IPv6 any any
# 3. Ingress ICMP IPv4 from public network
# 4. Ingress TCP 22 (SSH) from public network
common_ruleset = [dict(direction='egress', protocol='icmp'),
dict(direction='egress', protocol='icmp',
ethertype='IPv6'),
dict(direction='egress', protocol='tcp',
port_range_min=22, port_range_max=22),
dict(direction='egress', protocol='udp'),
dict(direction='ingress', protocol='tcp',
port_range_min=22, port_range_max=22),
dict(direction='ingress', protocol='udp'),
dict(direction='ingress', protocol='icmp')]
for rule in common_ruleset:
self.add_security_group_rule(self.qos_sg, rule)
def check_show_policy(self, policy_id, rule_type=None,
rule_bw=None, rule_dscp=None):
retrieved_policy = self.show_qos_policy(policy_id)
policy_rules = retrieved_policy['rules']
if rule_type == 'bw':
self.assertEqual(1, len(policy_rules))
self.assertEqual(rule_bw['id'], policy_rules[0]['id'])
self.assertEqual(feature_manager.RULE_TYPE_BANDWIDTH_LIMIT,
policy_rules[0]['type'])
elif rule_type == 'dscp':
self.assertEqual(1, len(policy_rules))
self.assertEqual(rule_dscp['id'], policy_rules[0]['id'])
self.assertEqual(feature_manager.RULE_TYPE_DSCP_MARK,
policy_rules[0]['type'])
elif rule_type == 'bw+dscp':
self.assertEqual(2, len(policy_rules))
self.assertEqual(rule_bw['id'], policy_rules[0]['id'])
self.assertEqual(rule_dscp['id'], policy_rules[1]['id'])
self.assertEqual(feature_manager.RULE_TYPE_BANDWIDTH_LIMIT,
policy_rules[0]['type'])
self.assertEqual(feature_manager.RULE_TYPE_DSCP_MARK,
policy_rules[1]['type'])
def deploy_qos_ops_topology(self):
router_qos = self.create_topology_router("router_qos")
# Qos network
network_qos = self.create_topology_network("network_qos")
self.create_topology_subnet("subnet_qos", network_qos,
router_id=router_qos["id"])
return network_qos
def create_qos_bw_setup(self, bw_value_kbps, burst_kbps=0):
name = data_utils.rand_name('test-qos-policy-')
policy = self.create_qos_policy(name,
description='bandwidth_rule',
shared=False)
rule = self.create_bandwidth_limit_rule(
policy_id=policy['id'], max_kbps=bw_value_kbps,
max_burst_kbps=burst_kbps)
# Test 'show rule'
retrieved_rule = self.show_bandwidth_limit_rule(
rule['id'], policy['id'])
self.assertEqual(rule['id'], retrieved_rule['id'])
self.assertEqual(bw_value_kbps, retrieved_rule['max_kbps'])
self.assertEqual(burst_kbps, retrieved_rule['max_burst_kbps'])
network = self.deploy_qos_ops_topology()
# Test 'list rules'
rules = self.list_bandwidth_limit_rules(policy['id'])
rules_ids = [r['id'] for r in rules]
self.assertIn(rule['id'], rules_ids)
# Test 'show policy'
self.check_show_policy(policy_id=policy['id'], rule_type='bw',
rule_bw=rule)
#Verify backend
nsx_policy = self.nsx_client.get_qos_switching_profile(policy['name'])
#verify bandwidth-limit rule at the backend
avg_bw, peak_bw, max_burst = self.nsx_client.get_qos_bandwidth_rule(
nsx_policy['id'])
#check the values at the backend
msg = 'Backend bw-limit rule values are incorrect'
self.assertEqual(avg_bw, BW_VALUE_MBPS, msg)
self.assertEqual(peak_bw, BW_VALUE_MBPS * 2, msg)
self.assertEqual(max_burst, 0, msg)
return dict(network_qos=network,
policy_id=policy['id'])
def create_qos_dscp_setup(self, dscp_mark):
name = data_utils.rand_name('test-qos-policy-')
policy = self.create_qos_policy(name,
description='dscp_rule',
shared=False)
# add dscp rule
rule = self.create_dscp_marking_rule(
policy_id=policy['id'], dscp_mark=dscp_mark)
# Test 'show rule'
retrieved_rule = self.show_dscp_marking_rule(
rule['id'], policy['id'])
self.assertEqual(rule['id'], retrieved_rule['id'])
self.assertEqual(DSCP_MARK, retrieved_rule['dscp_mark'])
network = self.deploy_qos_ops_topology()
# Test 'list rules'
rules = self.list_dscp_marking_rules(policy['id'])
rules_ids = [r['id'] for r in rules]
self.assertIn(rule['id'], rules_ids)
# Test 'show policy'
self.check_show_policy(policy_id=policy['id'],
rule_type='dscp', rule_dscp=rule)
#Verify backend
nsx_policy = self.nsx_client.get_qos_switching_profile(policy['name'])
#verify dscp rule at the backend
dscp_value = self.nsx_client.get_qos_dscp_rule(
nsx_policy['id'])
#check the values at the backend
msg = 'Backend DSCP value is incorrect'
self.assertEqual(dscp_value, DSCP_MARK, msg)
return dict(network_qos=network,
policy_id=policy['id'])
def create_qos_bw_dscp_setup(self, bw_value_kbps, dscp_mark, burst_kbps=0):
name = data_utils.rand_name('test-qos-policy-')
policy = self.create_qos_policy(name,
description='bw_dscp_rule',
shared=False)
# add bw rule
self.create_bandwidth_limit_rule(
policy_id=policy['id'], max_kbps=bw_value_kbps,
max_burst_kbps=burst_kbps)
# add dscp rule
self.create_dscp_marking_rule(
policy_id=policy['id'], dscp_mark=dscp_mark)
network = self.deploy_qos_ops_topology()
#Verify backend
nsx_policy = self.nsx_client.get_qos_switching_profile(policy['name'])
#verify bandwidth-limit rule at the backend
avg_bw, peak_bw, max_burst = self.nsx_client.get_qos_bandwidth_rule(
nsx_policy['id'])
#check the values at the backend
msg = 'Backend bw-limit rule values are incorrect'
self.assertEqual(avg_bw, BW_VALUE_MBPS, msg)
self.assertEqual(peak_bw, BW_VALUE_MBPS * 2, msg)
self.assertEqual(max_burst, 0, msg)
#verify dscp rule at the backend
dscp_value = self.nsx_client.get_qos_dscp_rule(
nsx_policy['id'])
#check the values at the backend
msg = 'Backend DSCP value is incorrect'
self.assertEqual(dscp_value, DSCP_MARK, msg)
return dict(network_qos=network,
policy_id=policy['id'])
def create_vms(self, network):
#Obtain image id of debian_vmdk used for qos testing
image_id = self.get_glance_image_id('debian')
qos_src_vm = self.create_topology_instance(
"qos_src_vm", [network],
security_groups=[{'name': self.qos_sg['name']}],
create_floating_ip=True, image_id=image_id)
qos_dst_vm = self.create_topology_instance(
"qos_dst_vm", [network],
security_groups=[{'name': self.qos_sg['name']}],
create_floating_ip=True, image_id=image_id)
return (qos_src_vm, qos_dst_vm)
def check_internal_connectivity(self, network):
src_server_floatingip = self.topology_servers["qos_src_vm"][
"floating_ip"]
src_server = self.topology_servers["qos_src_vm"]
self.check_vm_internal_connectivity(network,
src_server_floatingip, src_server)
dst_server_floatingip = self.topology_servers["qos_dst_vm"][
"floating_ip"]
dst_server = self.topology_servers["qos_dst_vm"]
self.check_vm_internal_connectivity(network,
dst_server_floatingip, dst_server)
def verify_bandwidth_rule(self, max_mbps, max_burst=0):
"""Check if traffic received is greater than configured value
For example if configured value is 5Mbps and sending rate is 6Mbps
Traffic should be capped below 5.5 which includes default burst
"""
send_rate = max_mbps + max_burst + 1
bw_value = self.use_iperf_send_traffic(
src_server=self.topology_servers["qos_src_vm"],
dst_server=self.topology_servers["qos_dst_vm"],
send_rate=send_rate, traffic_type='udp')
if bw_value == -1:
raise Exception('Incorrect IPERF output received')
elif float(bw_value) - (float(max_mbps) + float(max_burst)) > 0.5:
LOG.info("Traffic received: {bw}".format(bw=bw_value))
raise Exception('Traffic is not limited by bw-limit rule')
elif((float(max_mbps) + float(max_burst)) - float(bw_value)) > 0.5:
LOG.info("Traffic received: {bw}".format(bw=bw_value))
raise Exception('Traffic is limited below configured value')
def verify_dscp_rule(self, dscp_value):
"""Check if traffic received is marked with configured dscp value
"""
dscp_filename = self.capture_iperf_traffic_dscp(
src_server=self.topology_servers["qos_src_vm"],
dst_server=self.topology_servers["qos_dst_vm"],
traffic_type='udp', send_dscp='0', interface='eth0')
# Check the entire file to see if any UDP packets are sent without
# configured dscp value.Example capture all UDP packets with
# DSCP value !=12
src_vm_ip_dict = self.topology_servers['qos_src_vm']['floating_ips'][0]
filter_string = ('tshark -r %s -Y '
'\"ip.dsfield.dscp != %s && udp.dstport == 49162 '
'&& ip.src == %s && ip.dst == %s\"' %
(dscp_filename, str(dscp_value),
src_vm_ip_dict['fixed_ip_address'],
self.topology_servers['qos_dst_vm']))
p = subprocess.Popen(filter_string, shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = p.communicate()
LOG.info(stdout)
LOG.info(stderr)
#output should not contain packet trace
if "Source port:" in stdout:
raise Exception('Traffic is not being marked with correct DSCP')
class QosBandwidthLimitRuleTest(TestQosOps):
@decorators.idempotent_id('68fa3170-b61c-4e69-b0b7-6cbe34b57724')
def test_qos_bw_rule_network(self):
"""
Test bandwidth_limit rule by sending traffic between two instances
and verifying if egress traffic is being bandwidth-limited
"""
self.define_security_groups()
qos_bw_dict = self.create_qos_bw_setup(bw_value_kbps=BW_VALUE_KBPS)
self.admin_mgr.networks_client.update_network(
qos_bw_dict['network_qos']['id'],
qos_policy_id=qos_bw_dict['policy_id'])
updated_network = self.admin_mgr.networks_client.show_network(
qos_bw_dict['network_qos']['id'])
qos_network = updated_network.get('network', updated_network)
self.assertEqual(
qos_bw_dict['policy_id'], qos_network['qos_policy_id'])
self.create_vms(qos_bw_dict['network_qos'])
#sleep to ensure VMs have finished complete bootup
time.sleep(120)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS)
@decorators.idempotent_id('bf687826-ec76-4655-90a0-cc8f5316eaaf')
def test_qos_bw_rule_network_with_burst(self):
"""
Test bandwidth_limit rule by sending traffic between two instances
and verifying if egress traffic is being bandwidth-limited
"""
self.define_security_groups()
qos_bw_dict = self.create_qos_bw_setup(bw_value_kbps=BW_VALUE_KBPS,
burst_kbps=MAX_BURST_KBPS)
self.admin_mgr.networks_client.update_network(
qos_bw_dict['network_qos']['id'],
qos_policy_id=qos_bw_dict['policy_id'])
updated_network = self.admin_mgr.networks_client.show_network(
qos_bw_dict['network_qos']['id'])
qos_network = updated_network.get('network', updated_network)
self.assertEqual(
qos_bw_dict['policy_id'], qos_network['qos_policy_id'])
self.create_vms(qos_bw_dict['network_qos'])
#sleep to ensure VMs have finished complete bootup
time.sleep(120)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS,
max_burst=MAX_BURST_MBPS)
@decorators.idempotent_id('531c7476-6cee-4224-9b23-8e67e4c30703')
def test_qos_bw_rule_port(self):
"""
Test bandwidth_limit rule by sending traffic between two instances
and verifying if egress traffic is being bandwidth-limited
"""
self.define_security_groups()
qos_bw_dict = self.create_qos_bw_setup(bw_value_kbps=BW_VALUE_KBPS)
qos_src_vm, qos_dst_vm = self.create_vms(qos_bw_dict['network_qos'])
self.os_admin.ports_client.update_port(
qos_src_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dict['policy_id'])
self.os_admin.ports_client.update_port(
qos_dst_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dict['policy_id'])
#sleep to ensure VMs have finished complete bootup
time.sleep(120)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS)
@decorators.idempotent_id('ae40717f-6a08-4e9c-86d0-87e45375c844')
def test_qos_bw_rule_port_with_burst(self):
"""
Test bandwidth_limit rule by sending traffic between two instances
and verifying if egress traffic is being bandwidth-limited
"""
self.define_security_groups()
qos_bw_dict = self.create_qos_bw_setup(bw_value_kbps=BW_VALUE_KBPS,
burst_kbps=MAX_BURST_KBPS)
qos_src_vm, qos_dst_vm = self.create_vms(qos_bw_dict['network_qos'])
self.os_admin.ports_client.update_port(
qos_src_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dict['policy_id'])
self.os_admin.ports_client.update_port(
qos_dst_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dict['policy_id'])
#sleep to ensure VMs have finished complete bootup
time.sleep(120)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS,
max_burst=MAX_BURST_MBPS)
class QosDSCPRuleTest(TestQosOps):
@decorators.idempotent_id('40995e11-9231-406e-b3d7-b36dd362a94b')
def test_qos_dscp_mark_network(self):
"""
Test qos dscp rule by sending traffic between two instance
and verifying if egress traffic is marked with dscp value
"""
self.define_security_groups()
qos_dscp_dict = self.create_qos_dscp_setup(dscp_mark=DSCP_MARK)
self.admin_mgr.networks_client.update_network(
qos_dscp_dict['network_qos']['id'],
qos_policy_id=qos_dscp_dict['policy_id'])
updated_network = self.admin_mgr.networks_client.show_network(
qos_dscp_dict['network_qos']['id'])
qos_network = updated_network.get('network', updated_network)
self.assertEqual(
qos_dscp_dict['policy_id'], qos_network['qos_policy_id'])
self.create_vms(qos_dscp_dict['network_qos'])
#sleep to ensure VMs have finished complete bootup
time.sleep(240)
#check dscp rule
self.verify_dscp_rule(dscp_value=DSCP_MARK)
@decorators.idempotent_id('4c5dc539-2878-4235-8880-35927b7a0c33')
def test_qos_dscp_mark_port(self):
"""
Test qos dscp rule by sending traffic between two instance
and verifying if egress traffic is marked with dscp value
"""
self.define_security_groups()
qos_dscp_dict = self.create_qos_dscp_setup(dscp_mark=DSCP_MARK)
qos_src_vm, qos_dst_vm = self.create_vms(qos_dscp_dict['network_qos'])
self.os_admin.ports_client.update_port(
qos_src_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_dscp_dict['policy_id'])
self.os_admin.ports_client.update_port(
qos_dst_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_dscp_dict['policy_id'])
#sleep to ensure VMs have finished complete bootup
time.sleep(240)
#check dscp rule
self.verify_dscp_rule(dscp_value=DSCP_MARK)
class QosPolicyRuleTest(TestQosOps):
@decorators.idempotent_id('3566016a-31cc-4905-b217-98844caad4a9')
def test_qos_bw_dscp_rule_network(self):
"""
Test qos and bw dscp rule by sending traffic between two instance
and verifying if traffic is rate-limited and marked with dscp value
"""
self.define_security_groups()
qos_bw_dscp_dict = self.create_qos_bw_dscp_setup(
bw_value_kbps=BW_VALUE_KBPS,
dscp_mark=DSCP_MARK)
self.admin_mgr.networks_client.update_network(
qos_bw_dscp_dict['network_qos']['id'],
qos_policy_id=qos_bw_dscp_dict['policy_id'])
updated_network = self.admin_mgr.networks_client.show_network(
qos_bw_dscp_dict['network_qos']['id'])
qos_network = updated_network.get('network', updated_network)
self.assertEqual(
qos_bw_dscp_dict['policy_id'], qos_network['qos_policy_id'])
self.create_vms(qos_bw_dscp_dict['network_qos'])
#sleep to ensure VMs have finished complete bootup
time.sleep(240)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS)
#check dscp rule
self.verify_dscp_rule(dscp_value=DSCP_MARK)
@decorators.idempotent_id('c545c322-b37e-45e2-af22-b160a5320594')
def test_qos_bw_dscp_rule_port(self):
"""
Test qos and bw dscp rule by sending traffic between two instance
and verifying if traffic is rate-limited and marked with dscp value
"""
self.define_security_groups()
qos_bw_dscp_dict = self.create_qos_bw_dscp_setup(
bw_value_kbps=BW_VALUE_KBPS,
dscp_mark=DSCP_MARK)
qos_src_vm, qos_dst_vm = self.create_vms(
qos_bw_dscp_dict['network_qos'])
self.os_admin.ports_client.update_port(
qos_src_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dscp_dict['policy_id'])
self.os_admin.ports_client.update_port(
qos_dst_vm['floating_ips'][0]['port_id'],
qos_policy_id=qos_bw_dscp_dict['policy_id'])
#sleep to ensure VMs have finished complete bootup
time.sleep(240)
#check bandwidth rule
self.verify_bandwidth_rule(max_mbps=BW_VALUE_MBPS)
#check dscp rule
self.verify_dscp_rule(dscp_value=DSCP_MARK)