Merge "[OVN][QoS] Update the Logical_Swith_Port options with the QoS values"

This commit is contained in:
Zuul
2025-04-10 02:44:28 +00:00
committed by Gerrit Code Review
4 changed files with 86 additions and 5 deletions

View File

@@ -205,7 +205,23 @@ class OVNClientQosExtension:
return ovn_qos_rule
def _ovn_lsp_rule(self, rules):
def get_lsp_options_qos(self, port_id):
"""Return the current LSP.options QoS fields, passing the port ID"""
qos_options = {}
lsp = self.nb_idl.lookup('Logical_Switch_Port', port_id, default=None)
if not lsp:
return {}
for qos_key in (ovn_const.LSP_OPTIONS_QOS_MAX_RATE,
ovn_const.LSP_OPTIONS_QOS_BURST,
ovn_const.LSP_OPTIONS_QOS_MIN_RATE):
qos_value = lsp.options.get(qos_key)
if qos_value is not None:
qos_options[qos_key] = qos_value
return qos_options
@staticmethod
def _ovn_lsp_rule(rules):
"""Generate the OVN LSP.options for physical network ports (egress)
The Logical_Switch_Port options field is a dictionary that can contain

View File

@@ -497,8 +497,11 @@ class OVNClient:
if self.is_mcast_flood_broken and port_type not in (
'vtep', ovn_const.LSP_TYPE_LOCALPORT, 'router'):
options.update({ovn_const.LSP_OPTIONS_MCAST_FLOOD_REPORTS: 'true'})
sg_ids = ' '.join(utils.get_lsp_security_groups(port))
lsp_options_qos = self._qos_driver.get_lsp_options_qos(port['id'])
options.update(lsp_options_qos)
return OvnPortInfo(port_type, options, addresses, port_security,
parent_name, tag, dhcpv4_options, dhcpv6_options,
cidrs.strip(), device_owner, sg_ids,

View File

@@ -16,8 +16,11 @@ from neutron_lib.api.definitions import external_net
from neutron_lib.api.definitions import network_mtu as mtu_def
from neutron_lib.api.definitions import provider_net
from neutron_lib import constants
from neutron_lib.plugins import constants as plugins_constants
from neutron_lib.services.qos import constants as qos_const
from oslo_config import cfg
from oslo_utils import strutils
from oslo_utils import uuidutils
from neutron.common.ovn import constants as ovn_const
from neutron.common.ovn import utils as ovn_utils
@@ -30,8 +33,11 @@ from neutron.tests.unit.extensions import test_l3
class TestOVNClient(base.TestOVNFunctionalBase,
test_l3.L3NatTestCaseMixin):
def setUp(self, **kwargs):
super().setUp(**kwargs)
_extension_drivers = ['qos']
def setUp(self, *args):
service_plugins = {plugins_constants.QOS: 'qos'}
super().setUp(service_plugins=service_plugins)
ext_mgr = test_l3.L3TestExtensionManager()
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
@@ -309,3 +315,55 @@ class TestOVNClient(base.TestOVNFunctionalBase,
# MTU connected to the router.
self._check_gw_lrp_mtu(router_id,
min(router_attached_net_mtus))
def test_update_port_with_qos(self):
def _check_bw(port_id, max_kbps=None, max_burst_kbps=None):
lsp = self.nb_api.lookup('Logical_Switch_Port', port_id)
if max_kbps:
self.assertEqual(
'{}'.format(max_kbps * 1000),
lsp.options[ovn_const.LSP_OPTIONS_QOS_MAX_RATE])
else:
self.assertNotIn(ovn_const.LSP_OPTIONS_QOS_MAX_RATE,
lsp.options)
if max_burst_kbps:
self.assertEqual(
'{}'.format(max_burst_kbps * 1000),
lsp.options[ovn_const.LSP_OPTIONS_QOS_BURST])
else:
self.assertNotIn(ovn_const.LSP_OPTIONS_QOS_BURST,
lsp.options)
res = self._create_qos_policy(self.fmt, is_admin=True)
qos = self.deserialize(self.fmt, res)['policy']
max_kbps, max_burst_kbps = 1000, 800
self._create_qos_rule(self.fmt, qos['id'],
qos_const.RULE_TYPE_BANDWIDTH_LIMIT,
max_kbps=max_kbps, max_burst_kbps=max_burst_kbps,
is_admin=True)
net_args = {provider_net.NETWORK_TYPE: 'flat',
provider_net.PHYSICAL_NETWORK: 'datacentre'}
with self.network(uuidutils.generate_uuid(),
arg_list=tuple(net_args.keys()), as_admin=True,
**net_args) as net:
with self.subnet(net) as subnet:
with self.port(subnet) as port:
port_data = port['port']
# Check no QoS options.
_check_bw(port_data['id'])
# Add QoS policy.
req = self.new_update_request(
'ports',
{'port': {'qos_policy_id': qos['id']}},
port_data['id'])
req.get_response(self.api)
_check_bw(port_data['id'], max_kbps, max_burst_kbps)
# Update port.
req = self.new_update_request(
'ports',
{'port': {'name': uuidutils.generate_uuid()}},
port_data['id'])
req.get_response(self.api)
_check_bw(port_data['id'], max_kbps, max_burst_kbps)

View File

@@ -97,7 +97,9 @@ class MechDriverSetupBase(abc.ABC):
self.mech_driver.nb_ovn = fakes.FakeOvsdbNbOvnIdl()
self.mech_driver.sb_ovn = fakes.FakeOvsdbSbOvnIdl()
self.mech_driver._post_fork_event.set()
self.mech_driver._ovn_client._qos_driver = mock.Mock()
self.mech_driver._ovn_client._qos_driver = mock.Mock(
get_lsp_options_qos=mock.Mock(return_value={})
)
self._agent_cache = neutron_agent.AgentCache(self.mech_driver)
agent1 = self._add_agent('agent1')
neutron_agent.AgentCache().get_agents = mock.Mock()
@@ -189,6 +191,8 @@ class TestOVNMechanismDriverBase(MechDriverSetupBase,
self.rp_ns = self.mech_driver.resource_provider_uuid5_namespace
self.placement_ext = self.mech_driver._ovn_client.placement_extension
self.placement_ext._reset(self.placement_ext._driver)
mock.patch.object(self.mech_driver._ovn_client._qos_driver,
'get_lsp_options_qos', return_value={}).start()
self.fake_subnet = fakes.FakeSubnet.create_one_subnet().info()