Merge "[OVN][QoS] Add external_ids reference to port QoS registers"
This commit is contained in:
commit
a88a8ab413
@ -22,6 +22,7 @@ OVN_ML2_MECH_DRIVER_NAME = 'ovn'
|
|||||||
OVN_NETWORK_NAME_EXT_ID_KEY = 'neutron:network_name'
|
OVN_NETWORK_NAME_EXT_ID_KEY = 'neutron:network_name'
|
||||||
OVN_NETWORK_MTU_EXT_ID_KEY = 'neutron:mtu'
|
OVN_NETWORK_MTU_EXT_ID_KEY = 'neutron:mtu'
|
||||||
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
OVN_PORT_NAME_EXT_ID_KEY = 'neutron:port_name'
|
||||||
|
OVN_PORT_EXT_ID_KEY = 'neutron:port_id'
|
||||||
OVN_PORT_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
OVN_PORT_FIP_EXT_ID_KEY = 'neutron:port_fip'
|
||||||
OVN_ROUTER_NAME_EXT_ID_KEY = 'neutron:router_name'
|
OVN_ROUTER_NAME_EXT_ID_KEY = 'neutron:router_name'
|
||||||
OVN_AZ_HINTS_EXT_ID_KEY = 'neutron:availability_zone_hints'
|
OVN_AZ_HINTS_EXT_ID_KEY = 'neutron:availability_zone_hints'
|
||||||
|
@ -154,14 +154,19 @@ class OVNClientQosExtension(object):
|
|||||||
ovn_qos_rule = {'switch': lswitch_name, 'direction': direction,
|
ovn_qos_rule = {'switch': lswitch_name, 'direction': direction,
|
||||||
'priority': OVN_QOS_DEFAULT_RULE_PRIORITY,
|
'priority': OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||||
'match': match}
|
'match': match}
|
||||||
if fip_id:
|
|
||||||
ovn_qos_rule['external_ids'] = {
|
|
||||||
ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
|
||||||
|
|
||||||
if delete:
|
if delete:
|
||||||
# Any specific rule parameter is left undefined.
|
# Any specific rule parameter is left undefined.
|
||||||
return ovn_qos_rule
|
return ovn_qos_rule
|
||||||
|
|
||||||
|
# All OVN QoS rules have an external ID reference to the port or the
|
||||||
|
# FIP that are attached to.
|
||||||
|
if fip_id:
|
||||||
|
key, value = ovn_const.OVN_FIP_EXT_ID_KEY, fip_id
|
||||||
|
else:
|
||||||
|
key, value = ovn_const.OVN_PORT_EXT_ID_KEY, port_id
|
||||||
|
ovn_qos_rule['external_ids'] = {key: value}
|
||||||
|
|
||||||
for rule_type, rule in rules.items():
|
for rule_type, rule in rules.items():
|
||||||
if rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT:
|
if rule_type == qos_consts.RULE_TYPE_BANDWIDTH_LIMIT:
|
||||||
ovn_qos_rule['rate'] = rule['max_kbps']
|
ovn_qos_rule['rate'] = rule['max_kbps']
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import abc
|
import abc
|
||||||
import copy
|
import copy
|
||||||
import inspect
|
import inspect
|
||||||
|
import re
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from futurist import periodics
|
from futurist import periodics
|
||||||
@ -733,6 +734,41 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
|
|||||||
txn.add(cmd)
|
txn.add(cmd)
|
||||||
raise periodics.NeverAgain()
|
raise periodics.NeverAgain()
|
||||||
|
|
||||||
|
# TODO(ralonsoh): Remove this in the Z+2 cycle
|
||||||
|
# A static spacing value is used here, but this method will only run
|
||||||
|
# once per lock due to the use of periodics.NeverAgain().
|
||||||
|
@periodics.periodic(spacing=600, run_immediately=True)
|
||||||
|
def update_port_qos_with_external_ids_reference(self):
|
||||||
|
"""Update all OVN QoS registers with the port ID
|
||||||
|
|
||||||
|
This method will only update the OVN QoS registers related to port QoS,
|
||||||
|
not FIP QoS. FIP QoS have the corresponding "external_ids" reference.
|
||||||
|
"""
|
||||||
|
if not self.has_lock:
|
||||||
|
return
|
||||||
|
|
||||||
|
regex = re.compile(
|
||||||
|
r'(inport|outport) == \"(?P<port_id>[a-z0-9\-]{36})\"')
|
||||||
|
cmds = []
|
||||||
|
for ls in self._nb_idl.ls_list().execute(check_error=True):
|
||||||
|
for qos in self._nb_idl.qos_list(ls.name).execute(
|
||||||
|
check_error=True):
|
||||||
|
if qos.external_ids:
|
||||||
|
continue
|
||||||
|
match = re.match(regex, qos.match)
|
||||||
|
if not match:
|
||||||
|
continue
|
||||||
|
port_id = match.group('port_id')
|
||||||
|
external_ids = {ovn_const.OVN_PORT_EXT_ID_KEY: port_id}
|
||||||
|
cmds.append(self._nb_idl.db_set(
|
||||||
|
'QoS', qos.uuid, ('external_ids', external_ids)))
|
||||||
|
|
||||||
|
if cmds:
|
||||||
|
with self._nb_idl.transaction(check_error=True) as txn:
|
||||||
|
for cmd in cmds:
|
||||||
|
txn.add(cmd)
|
||||||
|
raise periodics.NeverAgain()
|
||||||
|
|
||||||
|
|
||||||
class HashRingHealthCheckPeriodics(object):
|
class HashRingHealthCheckPeriodics(object):
|
||||||
|
|
||||||
|
@ -184,6 +184,10 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
|||||||
self.qos_driver._qos_rules(mock.ANY, mock.ANY))
|
self.qos_driver._qos_rules(mock.ANY, mock.ANY))
|
||||||
|
|
||||||
def _test__ovn_qos_rule_ingress(self, fip_id=None, ip_address=None):
|
def _test__ovn_qos_rule_ingress(self, fip_id=None, ip_address=None):
|
||||||
|
if fip_id:
|
||||||
|
external_ids = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||||
|
else:
|
||||||
|
external_ids = {ovn_const.OVN_PORT_EXT_ID_KEY: 'port_id'}
|
||||||
direction = constants.INGRESS_DIRECTION
|
direction = constants.INGRESS_DIRECTION
|
||||||
rule = {qos_constants.RULE_TYPE_BANDWIDTH_LIMIT: QOS_RULE_BW_1}
|
rule = {qos_constants.RULE_TYPE_BANDWIDTH_LIMIT: QOS_RULE_BW_1}
|
||||||
match = self.qos_driver._ovn_qos_rule_match(
|
match = self.qos_driver._ovn_qos_rule_match(
|
||||||
@ -191,9 +195,8 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
|||||||
expected = {'burst': 100, 'rate': 200, 'direction': 'to-lport',
|
expected = {'burst': 100, 'rate': 200, 'direction': 'to-lport',
|
||||||
'match': match,
|
'match': match,
|
||||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY,
|
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||||
'switch': 'neutron-network_id'}
|
'switch': 'neutron-network_id',
|
||||||
if fip_id:
|
'external_ids': external_ids}
|
||||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
|
||||||
result = self.qos_driver._ovn_qos_rule(
|
result = self.qos_driver._ovn_qos_rule(
|
||||||
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
||||||
ip_address=ip_address, resident_port='resident_port')
|
ip_address=ip_address, resident_port='resident_port')
|
||||||
@ -206,15 +209,18 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
|||||||
self._test__ovn_qos_rule_ingress(fip_id='fipid', ip_address='1.2.3.4')
|
self._test__ovn_qos_rule_ingress(fip_id='fipid', ip_address='1.2.3.4')
|
||||||
|
|
||||||
def _test__ovn_qos_rule_egress(self, fip_id=None, ip_address=None):
|
def _test__ovn_qos_rule_egress(self, fip_id=None, ip_address=None):
|
||||||
|
if fip_id:
|
||||||
|
external_ids = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||||
|
else:
|
||||||
|
external_ids = {ovn_const.OVN_PORT_EXT_ID_KEY: 'port_id'}
|
||||||
direction = constants.EGRESS_DIRECTION
|
direction = constants.EGRESS_DIRECTION
|
||||||
rule = {qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_1}
|
rule = {qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_1}
|
||||||
match = self.qos_driver._ovn_qos_rule_match(
|
match = self.qos_driver._ovn_qos_rule_match(
|
||||||
direction, 'port_id', ip_address, 'resident_port')
|
direction, 'port_id', ip_address, 'resident_port')
|
||||||
expected = {'direction': 'from-lport', 'match': match,
|
expected = {'direction': 'from-lport', 'match': match,
|
||||||
'dscp': 16, 'switch': 'neutron-network_id',
|
'dscp': 16, 'switch': 'neutron-network_id',
|
||||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY}
|
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||||
if fip_id:
|
'external_ids': external_ids}
|
||||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
|
||||||
result = self.qos_driver._ovn_qos_rule(
|
result = self.qos_driver._ovn_qos_rule(
|
||||||
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
||||||
ip_address=ip_address, resident_port='resident_port')
|
ip_address=ip_address, resident_port='resident_port')
|
||||||
@ -224,9 +230,8 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
|||||||
qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_2}
|
qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_2}
|
||||||
expected = {'direction': 'from-lport', 'match': match,
|
expected = {'direction': 'from-lport', 'match': match,
|
||||||
'rate': 300, 'dscp': 20, 'switch': 'neutron-network_id',
|
'rate': 300, 'dscp': 20, 'switch': 'neutron-network_id',
|
||||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY}
|
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||||
if fip_id:
|
'external_ids': external_ids}
|
||||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
|
||||||
result = self.qos_driver._ovn_qos_rule(
|
result = self.qos_driver._ovn_qos_rule(
|
||||||
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
||||||
ip_address=ip_address, resident_port='resident_port')
|
ip_address=ip_address, resident_port='resident_port')
|
||||||
|
@ -19,6 +19,7 @@ from futurist import periodics
|
|||||||
from neutron_lib import context
|
from neutron_lib import context
|
||||||
from neutron_lib.db import api as db_api
|
from neutron_lib.db import api as db_api
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from neutron.common.ovn import constants
|
from neutron.common.ovn import constants
|
||||||
from neutron.common.ovn import utils
|
from neutron.common.ovn import utils
|
||||||
@ -519,3 +520,26 @@ class TestDBInconsistenciesPeriodics(testlib_api.SqlTestCaseLight,
|
|||||||
options={'always_learn_from_arp_request': 'false',
|
options={'always_learn_from_arp_request': 'false',
|
||||||
'dynamic_neigh_routers': 'true'})]
|
'dynamic_neigh_routers': 'true'})]
|
||||||
nb_idl.update_lrouter.assert_has_calls(expected_calls)
|
nb_idl.update_lrouter.assert_has_calls(expected_calls)
|
||||||
|
|
||||||
|
def test_update_port_qos_with_external_ids_reference(self):
|
||||||
|
nb_idl = self.fake_ovn_client._nb_idl
|
||||||
|
lrs = [fakes.FakeOvsdbRow.create_one_ovsdb_row(
|
||||||
|
attrs={'name': 'lr%s' % idx}) for idx in range(3)]
|
||||||
|
uuid1 = uuidutils.generate_uuid()
|
||||||
|
qoses1 = [fakes.FakeOvsdbRow.create_one_ovsdb_row(
|
||||||
|
attrs={'external_ids': {}, 'match': 'inport == "%s"' % uuid1})]
|
||||||
|
qoses2 = [fakes.FakeOvsdbRow.create_one_ovsdb_row(
|
||||||
|
attrs={'external_ids': {constants.OVN_PORT_EXT_ID_KEY: uuid1},
|
||||||
|
'match': 'inport == "%s"' % uuid1})]
|
||||||
|
qoses3 = []
|
||||||
|
nb_idl.ls_list.return_value.execute.return_value = lrs
|
||||||
|
nb_idl.qos_list.return_value.execute.side_effect = [qoses1, qoses2,
|
||||||
|
qoses3]
|
||||||
|
self.assertRaises(
|
||||||
|
periodics.NeverAgain,
|
||||||
|
self.periodic.update_port_qos_with_external_ids_reference)
|
||||||
|
|
||||||
|
external_ids = {constants.OVN_PORT_EXT_ID_KEY: uuid1}
|
||||||
|
expected_calls = [mock.call('QoS', qoses1[0].uuid,
|
||||||
|
('external_ids', external_ids))]
|
||||||
|
nb_idl.db_set.assert_has_calls(expected_calls)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user