Merge "NSX|v QoS DSCP marking support"
This commit is contained in:
commit
f2e5c76cf0
@ -23,6 +23,8 @@ from vmware_nsx.dvs import dvs_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PORTGROUP_PREFIX = 'dvportgroup'
|
||||
QOS_OUT_DIRECTION = 'outgoingPackets'
|
||||
QOS_AGENT_NAME = 'dvfilter-generic-vmware'
|
||||
|
||||
|
||||
class DvsManager(object):
|
||||
@ -139,8 +141,10 @@ class DvsManager(object):
|
||||
return pg_spec
|
||||
|
||||
def update_port_group_spec_qos(self, pg_spec, qos_data):
|
||||
outPol = pg_spec.defaultPortConfig.outShapingPolicy
|
||||
if qos_data.enabled:
|
||||
port_conf = pg_spec.defaultPortConfig
|
||||
# Update the out bandwidth shaping policy
|
||||
outPol = port_conf.outShapingPolicy
|
||||
if qos_data.bandwidthEnabled:
|
||||
outPol.inherited = False
|
||||
outPol.enabled.inherited = False
|
||||
outPol.enabled.value = True
|
||||
@ -153,6 +157,46 @@ class DvsManager(object):
|
||||
else:
|
||||
outPol.inherited = True
|
||||
|
||||
# Update the DSCP marking
|
||||
if (port_conf.filterPolicy.inherited or
|
||||
len(port_conf.filterPolicy.filterConfig) == 0 or
|
||||
len(port_conf.filterPolicy.filterConfig[
|
||||
0].trafficRuleset.rules) == 0):
|
||||
|
||||
if qos_data.dscpMarkEnabled:
|
||||
# create the entire structure
|
||||
client_factory = self._session.vim.client.factory
|
||||
filter_rule = client_factory.create('ns0:DvsTrafficRule')
|
||||
filter_rule.action = client_factory.create(
|
||||
'ns0:DvsUpdateTagNetworkRuleAction')
|
||||
filter_rule.action.dscpTag = qos_data.dscpMarkValue
|
||||
# mark only outgoing packets
|
||||
filter_rule.direction = QOS_OUT_DIRECTION
|
||||
|
||||
traffic_filter_config = client_factory.create(
|
||||
'ns0:DvsTrafficFilterConfig')
|
||||
traffic_filter_config.trafficRuleset.rules = [filter_rule]
|
||||
traffic_filter_config.trafficRuleset.enabled = True
|
||||
traffic_filter_config.agentName = QOS_AGENT_NAME
|
||||
traffic_filter_config.inherited = False
|
||||
|
||||
port_conf.filterPolicy = client_factory.create(
|
||||
'ns0:DvsFilterPolicy')
|
||||
port_conf.filterPolicy.filterConfig = [
|
||||
traffic_filter_config]
|
||||
port_conf.filterPolicy.inherited = False
|
||||
else:
|
||||
# The structure was already initialized
|
||||
filter_policy = port_conf.filterPolicy
|
||||
if qos_data.dscpMarkEnabled:
|
||||
# just update the DSCP value
|
||||
traffic_filter_config = filter_policy.filterConfig[0]
|
||||
filter_rule = traffic_filter_config.trafficRuleset.rules[0]
|
||||
filter_rule.action.dscpTag = qos_data.dscpMarkValue
|
||||
else:
|
||||
# delete the filter policy data
|
||||
filter_policy.filterConfig = []
|
||||
|
||||
def _reconfigure_port_group(self, pg_moref, spec_update_calback,
|
||||
spec_update_data):
|
||||
# Get the current configuration of the port group
|
||||
|
@ -141,6 +141,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
"advanced-service-providers",
|
||||
"subnet_allocation"]
|
||||
|
||||
supported_qos_rule_types = [qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
|
||||
qos_consts.RULE_TYPE_DSCP_MARK]
|
||||
|
||||
__native_bulk_support = True
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
@ -32,14 +32,19 @@ class NsxVQosRule(object):
|
||||
def __init__(self, context=None, qos_policy_id=None):
|
||||
super(NsxVQosRule, self).__init__()
|
||||
|
||||
# Data structure to hold the NSX-V representation
|
||||
# of the neutron qos rule.
|
||||
self._qos_plugin = None
|
||||
self.enabled = False
|
||||
|
||||
# Data structure to hold the NSX-V representation
|
||||
# of the neutron QoS Bandwidth rule
|
||||
self.bandwidthEnabled = False
|
||||
self.averageBandwidth = 0
|
||||
self.peakBandwidth = 0
|
||||
self.burstSize = 0
|
||||
|
||||
# And data for the DSCP marking rule
|
||||
self.dscpMarkEnabled = False
|
||||
self.dscpMarkValue = 0
|
||||
|
||||
if qos_policy_id is not None:
|
||||
self._init_from_policy_id(context, qos_policy_id)
|
||||
|
||||
@ -51,16 +56,18 @@ class NsxVQosRule(object):
|
||||
|
||||
# init the nsx_v qos data (outShapingPolicy) from a neutron qos policy
|
||||
def _init_from_policy_id(self, context, qos_policy_id):
|
||||
self.enabled = False
|
||||
self.bandwidthEnabled = False
|
||||
self.dscpMarkEnabled = False
|
||||
|
||||
# read the neutron policy restrictions
|
||||
if qos_policy_id is not None:
|
||||
# read the QOS rule from DB
|
||||
plugin = self._get_qos_plugin()
|
||||
# read the QoS BW rule from DB
|
||||
rules_obj = plugin.get_policy_bandwidth_limit_rules(
|
||||
context, qos_policy_id)
|
||||
if rules_obj is not None and len(rules_obj) > 0:
|
||||
rule_obj = rules_obj[0]
|
||||
self.enabled = True
|
||||
rule_obj = rules_obj[0] # neutron supports only 1 rule for now
|
||||
self.bandwidthEnabled = True
|
||||
# averageBandwidth: kbps (neutron) -> bps (nsxv)
|
||||
self.averageBandwidth = rule_obj['max_kbps'] * 1024
|
||||
# peakBandwidth: the same as the average value because the
|
||||
@ -68,6 +75,15 @@ class NsxVQosRule(object):
|
||||
self.peakBandwidth = self.averageBandwidth
|
||||
# burstSize: kbps (neutron) -> Bytes (nsxv)
|
||||
self.burstSize = rule_obj['max_burst_kbps'] * 128
|
||||
|
||||
# read the QoS DSCP marking rule from DB
|
||||
rules_obj = plugin.get_policy_dscp_marking_rules(
|
||||
context, qos_policy_id)
|
||||
if rules_obj is not None and len(rules_obj) > 0:
|
||||
rule_obj = rules_obj[0] # neutron supports only 1 rule for now
|
||||
self.dscpMarkEnabled = True
|
||||
self.dscpMarkValue = rule_obj['dscp_mark']
|
||||
|
||||
return self
|
||||
|
||||
|
||||
|
@ -72,12 +72,17 @@ class TestQosNsxVNotification(test_plugin.NsxVPluginV2TestCase,
|
||||
'bandwidth_limit_rule': {'id': uuidutils.generate_uuid(),
|
||||
'max_kbps': 100,
|
||||
'max_burst_kbps': 150}}
|
||||
self.dscp_rule_data = {
|
||||
'dscp_marking_rule': {'id': uuidutils.generate_uuid(),
|
||||
'dscp_mark': 22}}
|
||||
|
||||
self.policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
|
||||
self.rule = rule_object.QosBandwidthLimitRule(
|
||||
self.ctxt, **self.rule_data['bandwidth_limit_rule'])
|
||||
self.dscp_rule = rule_object.QosDscpMarkingRule(
|
||||
self.ctxt, **self.dscp_rule_data['dscp_marking_rule'])
|
||||
|
||||
self._net_data = {'network': {
|
||||
'name': 'test-qos',
|
||||
@ -88,6 +93,7 @@ class TestQosNsxVNotification(test_plugin.NsxVPluginV2TestCase,
|
||||
'shared': False
|
||||
}}
|
||||
self._rules = [self.rule_data['bandwidth_limit_rule']]
|
||||
self._dscp_rules = [self.dscp_rule_data['dscp_marking_rule']]
|
||||
|
||||
mock.patch('neutron.objects.db.api.create_object').start()
|
||||
mock.patch('neutron.objects.db.api.update_object').start()
|
||||
@ -117,21 +123,25 @@ class TestQosNsxVNotification(test_plugin.NsxVPluginV2TestCase,
|
||||
# Create a policy with a rule
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
setattr(_policy, "rules", [self.rule])
|
||||
setattr(_policy, "rules", [self.rule, self.dscp_rule])
|
||||
|
||||
with mock.patch('neutron.services.qos.qos_plugin.QoSPlugin.'
|
||||
'get_policy_bandwidth_limit_rules',
|
||||
return_value=self._rules) as get_rules_mock:
|
||||
# create the network to use this policy
|
||||
net = self._create_net()
|
||||
with mock.patch('neutron.services.qos.qos_plugin.QoSPlugin.'
|
||||
'get_policy_dscp_marking_rules',
|
||||
return_value=self._dscp_rules) as get_dscp_mock:
|
||||
# create the network to use this policy
|
||||
net = self._create_net()
|
||||
|
||||
# make sure the network-policy binding was updated
|
||||
update_bindings_mock.assert_called_once_with(
|
||||
self.ctxt, net['id'], self.policy.id)
|
||||
# make sure the qos rule was found
|
||||
get_rules_mock.assert_called_with(self.ctxt, self.policy.id)
|
||||
# make sure the dvs was updated
|
||||
self.assertTrue(dvs_update_mock.called)
|
||||
# make sure the network-policy binding was updated
|
||||
update_bindings_mock.assert_called_once_with(
|
||||
self.ctxt, net['id'], self.policy.id)
|
||||
# make sure the qos rule was found
|
||||
get_rules_mock.assert_called_with(self.ctxt, self.policy.id)
|
||||
get_dscp_mock.assert_called_with(self.ctxt, self.policy.id)
|
||||
# make sure the dvs was updated
|
||||
self.assertTrue(dvs_update_mock.called)
|
||||
|
||||
def _test_rule_action_notification(self, action):
|
||||
with mock.patch.object(qos_com_utils, 'update_network_policy_binding'):
|
||||
@ -189,3 +199,72 @@ class TestQosNsxVNotification(test_plugin.NsxVPluginV2TestCase,
|
||||
is deleted
|
||||
"""
|
||||
self._test_rule_action_notification('delete')
|
||||
|
||||
def _test_dscp_rule_action_notification(self, action):
|
||||
with mock.patch.object(qos_com_utils, 'update_network_policy_binding'):
|
||||
with mock.patch.object(dvs.DvsManager,
|
||||
'update_port_groups_config') as dvs_mock:
|
||||
|
||||
# Create a policy with a rule
|
||||
_policy = policy_object.QosPolicy(
|
||||
self.ctxt, **self.policy_data['policy'])
|
||||
|
||||
# set the rule in the policy data
|
||||
if action != 'create':
|
||||
setattr(_policy, "rules", [self.dscp_rule])
|
||||
plugin = self.qos_plugin
|
||||
with mock.patch('neutron.services.qos.qos_plugin.QoSPlugin.'
|
||||
'get_policy_dscp_marking_rules',
|
||||
return_value=self._dscp_rules) as rules_mock:
|
||||
with mock.patch('neutron.objects.qos.policy.'
|
||||
'QosPolicy.get_object',
|
||||
return_value=_policy):
|
||||
# create the network to use this policy
|
||||
self._create_net()
|
||||
# create/update/delete the rule
|
||||
if action == 'create':
|
||||
with mock.patch('neutron.objects.db.api.'
|
||||
'create_object',
|
||||
return_value=self.dscp_rule_data):
|
||||
plugin.create_policy_dscp_marking_rule(
|
||||
self.ctxt,
|
||||
self.policy.id,
|
||||
self.dscp_rule_data)
|
||||
elif action == 'update':
|
||||
with mock.patch('neutron.objects.db.api.'
|
||||
'update_object',
|
||||
return_value=self.dscp_rule_data):
|
||||
plugin.update_policy_dscp_marking_rule(
|
||||
self.ctxt,
|
||||
self.dscp_rule.id,
|
||||
self.policy.id,
|
||||
self.dscp_rule_data)
|
||||
else:
|
||||
plugin.delete_policy_dscp_marking_rule(
|
||||
self.ctxt,
|
||||
self.dscp_rule.id,
|
||||
self.policy.id)
|
||||
|
||||
# make sure the qos rule was found
|
||||
self.assertTrue(rules_mock.called)
|
||||
|
||||
# make sure the dvs was updated
|
||||
self.assertTrue(dvs_mock.called)
|
||||
|
||||
def test_create_dscp_rule_notification(self):
|
||||
"""Test the DVS update when a QoS DSCP rule, attached to a network,
|
||||
is created
|
||||
"""
|
||||
self._test_dscp_rule_action_notification('create')
|
||||
|
||||
def test_update_dscp_rule_notification(self):
|
||||
"""Test the DVS update when a QoS DSCP rule, attached to a network,
|
||||
is modified
|
||||
"""
|
||||
self._test_dscp_rule_action_notification('update')
|
||||
|
||||
def test_delete_dscp_rule_notification(self):
|
||||
"""Test the DVS update when a QoS DSCP rule, attached to a network,
|
||||
is deleted
|
||||
"""
|
||||
self._test_dscp_rule_action_notification('delete')
|
||||
|
Loading…
x
Reference in New Issue
Block a user