Merge "[OVN] Implement floating IP QoS in OVN backend"
This commit is contained in:
@@ -80,7 +80,7 @@ oslo.versionedobjects==1.35.1
|
||||
oslotest==3.2.0
|
||||
osprofiler==2.3.0
|
||||
ovs==2.8.0
|
||||
ovsdbapp==1.3.0
|
||||
ovsdbapp==1.4.0
|
||||
Paste==2.0.2
|
||||
PasteDeploy==1.5.0
|
||||
pbr==4.0.0
|
||||
|
||||
@@ -39,6 +39,7 @@ OVN_CIDRS_EXT_ID_KEY = 'neutron:cidrs'
|
||||
OVN_FIP_EXT_ID_KEY = 'neutron:fip_id'
|
||||
OVN_FIP_PORT_EXT_ID_KEY = 'neutron:fip_port_id'
|
||||
OVN_FIP_EXT_MAC_KEY = 'neutron:fip_external_mac'
|
||||
OVN_FIP_NET_ID = 'neutron:fip_network_id'
|
||||
OVN_REV_NUM_EXT_ID_KEY = 'neutron:revision_number'
|
||||
OVN_QOS_POLICY_EXT_ID_KEY = 'neutron:qos_policy_id'
|
||||
OVN_SG_IDS_EXT_ID_KEY = 'neutron:security_group_ids'
|
||||
|
||||
@@ -17,6 +17,12 @@ from neutron_lib.api.definitions import availability_zone as az_def
|
||||
from neutron_lib.api.definitions import expose_port_forwarding_in_fip
|
||||
from neutron_lib.api.definitions import fip_pf_description
|
||||
from neutron_lib.api.definitions import floating_ip_port_forwarding
|
||||
from neutron_lib.api.definitions import port_resource_request
|
||||
from neutron_lib.api.definitions import qos
|
||||
from neutron_lib.api.definitions import qos_bw_limit_direction
|
||||
from neutron_lib.api.definitions import qos_default
|
||||
from neutron_lib.api.definitions import qos_rule_type_details
|
||||
from neutron_lib.api.definitions import qos_rules_alias
|
||||
from neutron_lib.api.definitions import router_availability_zone as raz_def
|
||||
from neutron_lib.api.definitions import segment as seg_def
|
||||
|
||||
@@ -32,6 +38,7 @@ ML2_SUPPORTED_API_EXTENSIONS_OVN_L3 = [
|
||||
'ext-gw-mode',
|
||||
'fip-port-details',
|
||||
'pagination',
|
||||
'qos-fip',
|
||||
'sorting',
|
||||
'project-id',
|
||||
'dns-integration',
|
||||
@@ -54,6 +61,12 @@ ML2_SUPPORTED_API_EXTENSIONS = [
|
||||
'network-ip-availability',
|
||||
'port-security',
|
||||
'provider',
|
||||
port_resource_request.ALIAS,
|
||||
qos.ALIAS,
|
||||
qos_bw_limit_direction.ALIAS,
|
||||
qos_default.ALIAS,
|
||||
qos_rule_type_details.ALIAS,
|
||||
qos_rules_alias.ALIAS,
|
||||
'quotas',
|
||||
'rbac-address-scope',
|
||||
'rbac-policies',
|
||||
|
||||
@@ -74,6 +74,12 @@ def ovn_lrouter_port_name(id):
|
||||
return constants.LRP_PREFIX + '%s' % id
|
||||
|
||||
|
||||
def ovn_cr_lrouter_port_name(_id):
|
||||
# The name of the OVN chassisredirect lrouter port entry will be
|
||||
# cr-lrp-<UUID>
|
||||
return 'cr-lrp-%s' % _id
|
||||
|
||||
|
||||
def ovn_provnet_port_name(network_id):
|
||||
# The name of OVN lswitch provider network port entry will be
|
||||
# provnet-<Network-UUID>. The port is created for network having
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
# under the License.
|
||||
|
||||
from neutron_lib.api.definitions import l3
|
||||
from neutron_lib.api.definitions import qos
|
||||
from neutron_lib.api import extensions
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
|
||||
@@ -26,6 +27,7 @@ EXTENDED_ATTRIBUTES_2_0 = {
|
||||
'validate': {'type:uuid_or_none': None}}
|
||||
}
|
||||
}
|
||||
REQUIRED_EXTENSIONS = [l3.ALIAS, qos.ALIAS]
|
||||
|
||||
|
||||
class Qos_fip(extensions.ExtensionDescriptor):
|
||||
@@ -48,7 +50,7 @@ class Qos_fip(extensions.ExtensionDescriptor):
|
||||
return "2017-07-20T00:00:00-00:00"
|
||||
|
||||
def get_required_extensions(self):
|
||||
return ["router", "qos"]
|
||||
return REQUIRED_EXTENSIONS
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
|
||||
@@ -335,12 +335,12 @@ class QosPolicy(rbac_db.NeutronRbacObject):
|
||||
self.id)
|
||||
|
||||
def get_bound_floatingips(self):
|
||||
return binding.QosPolicyFloatingIPBinding.get_objects(self.obj_context,
|
||||
self.id)
|
||||
return binding.QosPolicyFloatingIPBinding.get_objects(
|
||||
self.obj_context, policy_id=self.id)
|
||||
|
||||
def get_bound_routers(self):
|
||||
return binding.QosPolicyRouterGatewayIPBinding.get_objects(
|
||||
self.obj_context, self.id)
|
||||
self.obj_context, policy_id=self.id)
|
||||
|
||||
@classmethod
|
||||
def _get_bound_tenant_ids(cls, session, binding_db, bound_db,
|
||||
|
||||
@@ -19,10 +19,12 @@ from neutron.objects.qos import policy as qos_policy
|
||||
from neutron.objects.qos import rule as qos_rule
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import context as n_context
|
||||
from neutron_lib.plugins import constants as plugins_const
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.services.qos import constants as qos_consts
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
from neutron.common.ovn import utils
|
||||
|
||||
|
||||
@@ -38,6 +40,7 @@ class OVNClientQosExtension(object):
|
||||
super(OVNClientQosExtension, self).__init__()
|
||||
self._driver = driver
|
||||
self._plugin_property = None
|
||||
self._plugin_l3_property = None
|
||||
|
||||
@property
|
||||
def _plugin(self):
|
||||
@@ -45,6 +48,12 @@ class OVNClientQosExtension(object):
|
||||
self._plugin_property = directory.get_plugin()
|
||||
return self._plugin_property
|
||||
|
||||
@property
|
||||
def _plugin_l3(self):
|
||||
if self._plugin_l3_property is None:
|
||||
self._plugin_l3_property = directory.get_plugin(plugins_const.L3)
|
||||
return self._plugin_l3_property
|
||||
|
||||
@staticmethod
|
||||
def _qos_rules(context, policy_id):
|
||||
"""QoS Neutron rules classified per direction and type
|
||||
@@ -81,8 +90,25 @@ class OVNClientQosExtension(object):
|
||||
'policy_id': policy_id})
|
||||
return qos_rules
|
||||
|
||||
@staticmethod
|
||||
def _ovn_qos_rule_match(direction, port_id, ip_address):
|
||||
if direction == constants.EGRESS_DIRECTION:
|
||||
in_or_out = 'inport'
|
||||
src_or_dst = 'src'
|
||||
else:
|
||||
in_or_out = 'outport'
|
||||
src_or_dst = 'dst'
|
||||
|
||||
match = '%s == "%s"' % (in_or_out, port_id)
|
||||
if ip_address:
|
||||
match += (' && ip4.%s == %s && is_chassis_resident("%s")' %
|
||||
(src_or_dst, ip_address,
|
||||
utils.ovn_cr_lrouter_port_name(port_id)))
|
||||
|
||||
return match
|
||||
|
||||
def _ovn_qos_rule(self, rules_direction, rules, port_id, network_id,
|
||||
delete=False):
|
||||
fip_id=None, ip_address=None, delete=False):
|
||||
"""Generate an OVN QoS register based on several Neutron QoS rules
|
||||
|
||||
A OVN QoS register can contain "bandwidth" and "action" parameters.
|
||||
@@ -96,8 +122,13 @@ class OVNClientQosExtension(object):
|
||||
:param rules_direction: (string) rules direction (egress, ingress).
|
||||
:param rules: (dict) {bw_limit: {max_kbps, max_burst_kbps},
|
||||
dscp: {dscp_mark}}
|
||||
:param port_id: (string) port ID.
|
||||
:param port_id: (string) port ID; for L3 floating IP bandwidth
|
||||
limit this is the router gateway port ID.
|
||||
:param network_id: (string) network ID.
|
||||
:param fip_id: (string) floating IP ID, for L3 floating IP bandwidth
|
||||
limit.
|
||||
:param ip_address: (string) IP address, for L3 floating IP bandwidth
|
||||
limit.
|
||||
:param delete: (bool) defines if this rule if going to be a partial
|
||||
one (without any bandwidth or DSCP information) to be
|
||||
used only as deletion rule.
|
||||
@@ -108,17 +139,17 @@ class OVNClientQosExtension(object):
|
||||
return
|
||||
|
||||
lswitch_name = utils.ovn_name(network_id)
|
||||
|
||||
if rules_direction == constants.EGRESS_DIRECTION:
|
||||
direction = 'from-lport'
|
||||
match = 'inport == "{}"'.format(port_id)
|
||||
else:
|
||||
direction = 'to-lport'
|
||||
match = 'outport == "{}"'.format(port_id)
|
||||
direction = (
|
||||
'from-lport' if rules_direction == constants.EGRESS_DIRECTION else
|
||||
'to-lport')
|
||||
match = self._ovn_qos_rule_match(rules_direction, port_id, ip_address)
|
||||
|
||||
ovn_qos_rule = {'switch': lswitch_name, 'direction': direction,
|
||||
'priority': OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||
'match': match}
|
||||
if fip_id:
|
||||
ovn_qos_rule['external_ids'] = {
|
||||
ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||
|
||||
if delete:
|
||||
# Any specific rule parameter is left undefined.
|
||||
@@ -234,6 +265,42 @@ class OVNClientQosExtension(object):
|
||||
|
||||
return updated_port_ids
|
||||
|
||||
def create_floatingip(self, txn, floatingip):
|
||||
self.update_floatingip(txn, floatingip)
|
||||
|
||||
def update_floatingip(self, txn, floatingip):
|
||||
router_id = floatingip.get('router_id')
|
||||
qos_policy_id = floatingip.get('qos_policy_id')
|
||||
if floatingip['floating_network_id']:
|
||||
lswitch_name = utils.ovn_name(floatingip['floating_network_id'])
|
||||
txn.add(self._driver._nb_idl.qos_del_ext_ids(
|
||||
lswitch_name,
|
||||
{ovn_const.OVN_FIP_EXT_ID_KEY: floatingip['id']}))
|
||||
|
||||
if not (router_id and qos_policy_id):
|
||||
return
|
||||
|
||||
admin_context = n_context.get_admin_context()
|
||||
router_db = self._plugin_l3._get_router(admin_context, router_id)
|
||||
gw_port_id = router_db.get('gw_port_id')
|
||||
if not gw_port_id:
|
||||
return
|
||||
|
||||
qos_rules = self._qos_rules(admin_context, qos_policy_id)
|
||||
for direction, rules in qos_rules.items():
|
||||
ovn_rule = self._ovn_qos_rule(
|
||||
direction, rules, gw_port_id,
|
||||
floatingip['floating_network_id'], fip_id=floatingip['id'],
|
||||
ip_address=floatingip['floating_ip_address'])
|
||||
if ovn_rule:
|
||||
txn.add(self._driver._nb_idl.qos_add(**ovn_rule))
|
||||
|
||||
def delete_floatingip(self, txn, floatingip):
|
||||
self.update_floatingip(txn, floatingip)
|
||||
|
||||
def disassociate_floatingip(self, txn, floatingip):
|
||||
self.delete_floatingip(txn, floatingip)
|
||||
|
||||
def update_policy(self, context, policy):
|
||||
updated_port_ids = set([])
|
||||
bound_networks = policy.get_bound_networks()
|
||||
@@ -256,3 +323,8 @@ class OVNClientQosExtension(object):
|
||||
filters={'id': port_ids}):
|
||||
self.update_port(txn, port, {}, reset=True,
|
||||
qos_rules=qos_rules)
|
||||
|
||||
for fip_binding in policy.get_bound_floatingips():
|
||||
fip = self._plugin_l3.get_floatingip(context,
|
||||
fip_binding.fip_id)
|
||||
self.update_floatingip(txn, fip)
|
||||
|
||||
@@ -643,7 +643,8 @@ class OVNClient(object):
|
||||
floatingip, ovn_const.TYPE_FLOATINGIPS)),
|
||||
ovn_const.OVN_FIP_PORT_EXT_ID_KEY: floatingip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: gw_lrouter_name,
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: port_db['mac_address']}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: port_db['mac_address'],
|
||||
ovn_const.OVN_FIP_NET_ID: floatingip['floating_network_id']}
|
||||
columns = {'type': 'dnat_and_snat',
|
||||
'logical_ip': floatingip['fixed_ip_address'],
|
||||
'external_ip': floatingip['floating_ip_address'],
|
||||
@@ -879,7 +880,9 @@ class OVNClient(object):
|
||||
|
||||
def create_floatingip(self, context, floatingip):
|
||||
try:
|
||||
self._create_or_update_floatingip(floatingip)
|
||||
with self._nb_idl.transaction(check_error=True) as txn:
|
||||
self._create_or_update_floatingip(floatingip, txn=txn)
|
||||
self._qos_driver.create_floatingip(txn, floatingip)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Unable to create floating ip in gateway '
|
||||
@@ -896,21 +899,11 @@ class OVNClient(object):
|
||||
n_context.get_admin_context(), floatingip['id'],
|
||||
const.FLOATINGIP_STATUS_ACTIVE)
|
||||
|
||||
# TODO(lucasagomes): The ``fip_object`` parameter was added to
|
||||
# keep things backward compatible since old FIPs might not have
|
||||
# the OVN_FIP_EXT_ID_KEY in their external_ids field. Remove it
|
||||
# in the Rocky release.
|
||||
def update_floatingip(self, context, floatingip, fip_object=None):
|
||||
def update_floatingip(self, context, floatingip):
|
||||
fip_status = None
|
||||
router_id = None
|
||||
ovn_fip = self._nb_idl.get_floatingip(floatingip['id'])
|
||||
|
||||
if not ovn_fip and fip_object:
|
||||
router_id = fip_object.get('router_id')
|
||||
ovn_fip = self._nb_idl.get_floatingip_by_ips(
|
||||
router_id, fip_object['fixed_ip_address'],
|
||||
fip_object['floating_ip_address'])
|
||||
|
||||
check_rev_cmd = self._nb_idl.check_revision_number(
|
||||
floatingip['id'], floatingip, ovn_const.TYPE_FLOATINGIPS)
|
||||
with self._nb_idl.transaction(check_error=True) as txn:
|
||||
@@ -926,6 +919,8 @@ class OVNClient(object):
|
||||
self._create_or_update_floatingip(floatingip, txn=txn)
|
||||
fip_status = const.FLOATINGIP_STATUS_ACTIVE
|
||||
|
||||
self._qos_driver.update_floatingip(txn, floatingip)
|
||||
|
||||
if check_rev_cmd.result == ovn_const.TXN_COMMITTED:
|
||||
db_rev.bump_revision(
|
||||
context, floatingip, ovn_const.TYPE_FLOATINGIPS)
|
||||
@@ -934,26 +929,20 @@ class OVNClient(object):
|
||||
self._l3_plugin.update_floatingip_status(
|
||||
context, floatingip['id'], fip_status)
|
||||
|
||||
# TODO(lucasagomes): The ``fip_object`` parameter was added to
|
||||
# keep things backward compatible since old FIPs might not have
|
||||
# the OVN_FIP_EXT_ID_KEY in their external_ids field. Remove it
|
||||
# in the Rocky release.
|
||||
def delete_floatingip(self, context, fip_id, fip_object=None):
|
||||
def delete_floatingip(self, context, fip_id):
|
||||
router_id = None
|
||||
ovn_fip = self._nb_idl.get_floatingip(fip_id)
|
||||
|
||||
if not ovn_fip and fip_object:
|
||||
router_id = fip_object.get('router_id')
|
||||
ovn_fip = self._nb_idl.get_floatingip_by_ips(
|
||||
router_id, fip_object['fixed_ip_address'],
|
||||
fip_object['floating_ip_address'])
|
||||
|
||||
if ovn_fip:
|
||||
lrouter = ovn_fip['external_ids'].get(
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY,
|
||||
utils.ovn_name(router_id))
|
||||
fip_net_id = ovn_fip['external_ids'].get(ovn_const.OVN_FIP_NET_ID)
|
||||
fip_dict = {'floating_network_id': fip_net_id, 'id': fip_id}
|
||||
try:
|
||||
self._delete_floatingip(ovn_fip, lrouter)
|
||||
with self._nb_idl.transaction(check_error=True) as txn:
|
||||
self._delete_floatingip(ovn_fip, lrouter, txn=txn)
|
||||
self._qos_driver.delete_floatingip(txn, fip_dict)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error('Unable to delete floating ip in gateway '
|
||||
|
||||
@@ -20,6 +20,7 @@ from neutron.quota import resource_registry
|
||||
from neutron_lib.api.definitions import external_net
|
||||
from neutron_lib.api.definitions import portbindings
|
||||
from neutron_lib.api.definitions import provider_net as pnet
|
||||
from neutron_lib.api.definitions import qos as qos_api
|
||||
from neutron_lib.callbacks import events
|
||||
from neutron_lib.callbacks import registry
|
||||
from neutron_lib.callbacks import resources
|
||||
@@ -30,6 +31,7 @@ from neutron_lib.exceptions import availability_zone as az_exc
|
||||
from neutron_lib.plugins import constants as plugin_constants
|
||||
from neutron_lib.plugins import directory
|
||||
from neutron_lib.services import base as service_base
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_utils import excutils
|
||||
|
||||
@@ -38,7 +40,9 @@ from neutron.common.ovn import extensions
|
||||
from neutron.common.ovn import utils
|
||||
from neutron.db.availability_zone import router as router_az_db
|
||||
from neutron.db import l3_fip_port_details
|
||||
from neutron.db import l3_fip_qos
|
||||
from neutron.db import ovn_revision_numbers_db as db_rev
|
||||
from neutron.extensions import qos_fip as qos_fip_api
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import ovn_client
|
||||
from neutron.scheduler import l3_ovn_scheduler
|
||||
from neutron.services.portforwarding.drivers.ovn import driver \
|
||||
@@ -56,7 +60,8 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
l3_gwmode_db.L3_NAT_db_mixin,
|
||||
dns_db.DNSDbMixin,
|
||||
l3_fip_port_details.Fip_port_details_db_mixin,
|
||||
router_az_db.RouterAvailabilityZoneMixin):
|
||||
router_az_db.RouterAvailabilityZoneMixin,
|
||||
l3_fip_qos.FloatingQoSDbMixin):
|
||||
"""Implementation of the OVN L3 Router Service Plugin.
|
||||
|
||||
This class implements a L3 service plugin that provides
|
||||
@@ -66,7 +71,7 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
|
||||
# TODO(mjozefcz): Start consuming it from neutron-lib
|
||||
# once available.
|
||||
supported_extension_aliases = (
|
||||
_supported_extension_aliases = (
|
||||
extensions.ML2_SUPPORTED_API_EXTENSIONS_OVN_L3)
|
||||
|
||||
@resource_registry.tracked_resources(router=l3_models.Router,
|
||||
@@ -89,6 +94,19 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
self.create_floatingip_precommit, resources.FLOATING_IP,
|
||||
events.PRECOMMIT_CREATE)
|
||||
|
||||
@staticmethod
|
||||
def disable_qos_fip_extension_by_extension_drivers(aliases):
|
||||
if (qos_api.ALIAS not in cfg.CONF.ml2.extension_drivers and
|
||||
qos_fip_api.FIP_QOS_ALIAS in aliases):
|
||||
aliases.remove(qos_fip_api.FIP_QOS_ALIAS)
|
||||
|
||||
@property
|
||||
def supported_extension_aliases(self):
|
||||
if not hasattr(self, '_aliases'):
|
||||
self._aliases = self._supported_extension_aliases[:]
|
||||
self.disable_qos_fip_extension_by_extension_drivers(self._aliases)
|
||||
return self._aliases
|
||||
|
||||
@property
|
||||
def _ovn_client(self):
|
||||
if self._ovn_client_inst is None:
|
||||
@@ -242,25 +260,13 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
return fip
|
||||
|
||||
def delete_floatingip(self, context, id):
|
||||
# TODO(lucasagomes): Passing ``original_fip`` object as a
|
||||
# parameter to the OVNClient's delete_floatingip() method is done
|
||||
# for backward-compatible reasons. Remove it in the Rocky release
|
||||
# of OpenStack.
|
||||
original_fip = self.get_floatingip(context, id)
|
||||
super(OVNL3RouterPlugin, self).delete_floatingip(context, id)
|
||||
self._ovn_client.delete_floatingip(context, id,
|
||||
fip_object=original_fip)
|
||||
self._ovn_client.delete_floatingip(context, id)
|
||||
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
# TODO(lucasagomes): Passing ``original_fip`` object as a
|
||||
# parameter to the OVNClient's update_floatingip() method is done
|
||||
# for backward-compatible reasons. Remove it in the Rocky release
|
||||
# of OpenStack.
|
||||
original_fip = self.get_floatingip(context, id)
|
||||
fip = super(OVNL3RouterPlugin, self).update_floatingip(context, id,
|
||||
floatingip)
|
||||
self._ovn_client.update_floatingip(context, fip,
|
||||
fip_object=original_fip)
|
||||
self._ovn_client.update_floatingip(context, fip)
|
||||
return fip
|
||||
|
||||
def update_floatingip_status(self, context, floatingip_id, status):
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
from unittest import mock
|
||||
|
||||
from neutron_lib import constants
|
||||
from neutron_lib.services.qos import constants as qos_constants
|
||||
|
||||
from neutron.common.ovn import utils as ovn_utils
|
||||
from neutron.db import l3_db
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.extensions \
|
||||
import qos as qos_extension
|
||||
from neutron.tests.functional import base
|
||||
@@ -63,19 +65,32 @@ class TestOVNClientQosExtension(base.TestOVNFunctionalBase):
|
||||
self._add_logical_switch()
|
||||
_ovn_client = _OVNClient(self.nb_api)
|
||||
self.qos_driver = qos_extension.OVNClientQosExtension(_ovn_client)
|
||||
self.gw_port_id = 'gw_port_id'
|
||||
self._mock_get_router = mock.patch.object(l3_db.L3_NAT_dbonly_mixin,
|
||||
'_get_router')
|
||||
self.mock_get_router = self._mock_get_router.start()
|
||||
self.mock_get_router.return_value = {'gw_port_id': self.gw_port_id}
|
||||
self._mock_qos_rules = mock.patch.object(self.qos_driver,
|
||||
'_qos_rules')
|
||||
self.mock_qos_rules = self._mock_qos_rules.start()
|
||||
self.fip = {'router_id': 'router_id', 'qos_policy_id': 'qos_policy_id',
|
||||
'floating_network_id': self.network_1,
|
||||
'id': 'fip_id', 'floating_ip_address': '1.2.3.4'}
|
||||
|
||||
def _add_logical_switch(self):
|
||||
self.network_1 = 'network_1'
|
||||
with self.nb_api.transaction(check_error=True) as txn:
|
||||
txn.add(self.nb_api.ls_add(ovn_utils.ovn_name(self.network_1)))
|
||||
|
||||
def _check_rules(self, rules, port_id, network_id):
|
||||
def _check_rules(self, rules, port_id, network_id, fip_id=None,
|
||||
ip_address=None):
|
||||
egress_ovn_rule = self.qos_driver._ovn_qos_rule(
|
||||
constants.EGRESS_DIRECTION, rules.get(constants.EGRESS_DIRECTION),
|
||||
port_id, network_id)
|
||||
port_id, network_id, fip_id=fip_id, ip_address=ip_address)
|
||||
ingress_ovn_rule = self.qos_driver._ovn_qos_rule(
|
||||
constants.INGRESS_DIRECTION,
|
||||
rules.get(constants.INGRESS_DIRECTION), port_id, network_id)
|
||||
rules.get(constants.INGRESS_DIRECTION), port_id, network_id,
|
||||
fip_id=fip_id, ip_address=ip_address)
|
||||
|
||||
with self.nb_api.transaction(check_error=True):
|
||||
ls = self.qos_driver._driver._nb_idl.lookup(
|
||||
@@ -100,10 +115,8 @@ class TestOVNClientQosExtension(base.TestOVNFunctionalBase):
|
||||
port = 'port1'
|
||||
|
||||
def update_and_check(qos_rules):
|
||||
with self.nb_api.transaction(check_error=True) as txn, \
|
||||
mock.patch.object(self.qos_driver,
|
||||
'_qos_rules') as mock_rules:
|
||||
mock_rules.return_value = qos_rules
|
||||
with self.nb_api.transaction(check_error=True) as txn:
|
||||
self.mock_qos_rules.return_value = qos_rules
|
||||
self.qos_driver._update_port_qos_rules(
|
||||
txn, port, self.network_1, 'qos1', None)
|
||||
self._check_rules(qos_rules, port, self.network_1)
|
||||
@@ -112,3 +125,27 @@ class TestOVNClientQosExtension(base.TestOVNFunctionalBase):
|
||||
update_and_check(QOS_RULES_2)
|
||||
update_and_check(QOS_RULES_3)
|
||||
update_and_check({})
|
||||
|
||||
def _update_fip_and_check(self, fip, qos_rules):
|
||||
with self.nb_api.transaction(check_error=True) as txn:
|
||||
self.mock_qos_rules.return_value = qos_rules
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
self._check_rules(qos_rules, self.gw_port_id, self.network_1,
|
||||
fip_id='fip_id', ip_address='1.2.3.4')
|
||||
|
||||
def test_create_floatingip(self):
|
||||
self._update_fip_and_check(self.fip, QOS_RULES_1)
|
||||
|
||||
def test_update_floatingip(self):
|
||||
fip_updated = copy.deepcopy(self.fip)
|
||||
fip_updated['qos_policy_id'] = 'another_qos_policy'
|
||||
self._update_fip_and_check(self.fip, QOS_RULES_1)
|
||||
self._update_fip_and_check(fip_updated, QOS_RULES_2)
|
||||
self._update_fip_and_check(fip_updated, QOS_RULES_3)
|
||||
self._update_fip_and_check(fip_updated, {})
|
||||
|
||||
def test_delete_floatingip(self):
|
||||
self._update_fip_and_check(self.fip, QOS_RULES_1)
|
||||
fip_dict = {'floating_network_id': self.fip['floating_network_id'],
|
||||
'id': self.fip['id']}
|
||||
self._update_fip_and_check(fip_dict, {})
|
||||
|
||||
@@ -51,7 +51,8 @@ class TestFloatingIPQoSIntPlugin(
|
||||
class TestFloatingIPQoSL3NatServicePlugin(
|
||||
test_l3.TestL3NatServicePlugin,
|
||||
l3_fip_qos.FloatingQoSDbMixin):
|
||||
supported_extension_aliases = [l3_apidef.ALIAS, qos_fip.FIP_QOS_ALIAS]
|
||||
supported_extension_aliases = [l3_apidef.ALIAS, 'qos',
|
||||
qos_fip.FIP_QOS_ALIAS]
|
||||
|
||||
|
||||
class FloatingIPQoSDBTestCaseBase(object):
|
||||
|
||||
@@ -146,6 +146,7 @@ class FakeOvsdbNbOvnIdl(object):
|
||||
self.ls_get = mock.Mock()
|
||||
self.check_liveness = mock.Mock()
|
||||
self.ha_chassis_group_get = mock.Mock()
|
||||
self.qos_del_ext_ids = mock.Mock()
|
||||
|
||||
|
||||
class FakeOvsdbSbOvnIdl(object):
|
||||
|
||||
@@ -15,18 +15,21 @@
|
||||
from unittest import mock
|
||||
|
||||
import netaddr
|
||||
from neutron_lib.api.definitions import qos as qos_api
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import context
|
||||
from neutron_lib.services.qos import constants as qos_constants
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron.common.ovn import constants as ovn_const
|
||||
from neutron.core_extensions import qos as core_qos
|
||||
from neutron import manager
|
||||
from neutron.objects import network as network_obj
|
||||
from neutron.objects import ports as port_obj
|
||||
from neutron.objects.qos import policy as policy_obj
|
||||
from neutron.objects.qos import rule as rule_obj
|
||||
from neutron.objects import router as router_obj
|
||||
from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb.extensions \
|
||||
import qos as qos_extension
|
||||
from neutron.tests.unit.plugins.ml2 import test_plugin
|
||||
@@ -51,19 +54,20 @@ class _Context(object):
|
||||
class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
|
||||
CORE_PLUGIN_CLASS = 'neutron.plugins.ml2.plugin.Ml2Plugin'
|
||||
_extension_drivers = ['qos']
|
||||
_extension_drivers = [qos_api.ALIAS]
|
||||
l3_plugin = ('neutron.tests.unit.extensions.test_qos_fip.'
|
||||
'TestFloatingIPQoSL3NatServicePlugin')
|
||||
|
||||
def setUp(self):
|
||||
cfg.CONF.set_override('extension_drivers', self._extension_drivers,
|
||||
group='ml2')
|
||||
cfg.CONF.set_override('service_plugins', self._extension_drivers)
|
||||
extensions.register_custom_supported_check(qos_api.ALIAS, lambda: True,
|
||||
plugin_agnostic=True)
|
||||
super(TestOVNClientQosExtension, self).setUp()
|
||||
self.setup_coreplugin(self.CORE_PLUGIN_CLASS, load_plugins=True)
|
||||
manager.init()
|
||||
self._mock_qos_loaded = mock.patch.object(
|
||||
core_qos.QosCoreResourceExtension, 'plugin_loaded')
|
||||
self.mock_qos_loaded = self._mock_qos_loaded.start()
|
||||
|
||||
self.txn = _Context()
|
||||
mock_driver = mock.Mock()
|
||||
mock_driver._nb_idl.transaction.return_value = self.txn
|
||||
@@ -81,10 +85,34 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
return obj_cls.modify_fields_to_db(
|
||||
self.get_random_object_fields(obj_cls))
|
||||
|
||||
def _create_one_port(self, mac_address_int, network_id):
|
||||
mac_address = netaddr.EUI(mac_address_int)
|
||||
port = port_obj.Port(
|
||||
self.ctx, project_id=self.project_id,
|
||||
network_id=network_id, device_owner='',
|
||||
admin_state_up=True, status='DOWN', device_id='2',
|
||||
mac_address=mac_address)
|
||||
port.create()
|
||||
return port
|
||||
|
||||
def _create_one_router(self):
|
||||
self.router_gw_port = self._create_one_port(2000, self.fips_network.id)
|
||||
self.router = router_obj.Router(self.ctx, id=uuidutils.generate_uuid(),
|
||||
gw_port_id=self.router_gw_port.id)
|
||||
self.router.create()
|
||||
|
||||
def _initialize_objs(self):
|
||||
self.qos_policies = []
|
||||
self.ports = []
|
||||
self.networks = []
|
||||
self.fips = []
|
||||
self.fips_network = network_obj.Network(
|
||||
self.ctx, id=uuidutils.generate_uuid(), project_id=self.project_id)
|
||||
self.fips_network.create()
|
||||
self._create_one_router()
|
||||
self.fips_ports = []
|
||||
fip_cidr = netaddr.IPNetwork('10.10.0.0/24')
|
||||
|
||||
for net_idx in range(2):
|
||||
qos_policy = policy_obj.QosPolicy(
|
||||
self.ctx, id=uuidutils.generate_uuid(),
|
||||
@@ -96,10 +124,21 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
# the port dictionary extended with the QoS policy information; see
|
||||
# QoSPlugin._extend_port_resource_request
|
||||
qos_rule = rule_obj.QosDscpMarkingRule(
|
||||
self.ctx, dscp=20, id=uuidutils.generate_uuid(),
|
||||
self.ctx, dscp_mark=20, id=uuidutils.generate_uuid(),
|
||||
qos_policy_id=qos_policy.id)
|
||||
qos_rule.create()
|
||||
|
||||
self.fips_ports.append(self._create_one_port(1000 + net_idx,
|
||||
self.fips_network.id))
|
||||
fip_ip = str(netaddr.IPAddress(fip_cidr.ip + net_idx + 1))
|
||||
fip = router_obj.FloatingIP(
|
||||
self.ctx, id=uuidutils.generate_uuid(),
|
||||
project_id=self.project_id, floating_ip_address=fip_ip,
|
||||
floating_network_id=self.fips_network.id,
|
||||
floating_port_id=self.fips_ports[-1].id)
|
||||
fip.create()
|
||||
self.fips.append(fip)
|
||||
|
||||
network = network_obj.Network(
|
||||
self.ctx, id=uuidutils.generate_uuid(),
|
||||
project_id=self.project_id)
|
||||
@@ -107,14 +146,8 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
self.networks.append(network)
|
||||
|
||||
for port_idx in range(3):
|
||||
mac_address = netaddr.EUI(net_idx * 16 + port_idx)
|
||||
port = port_obj.Port(
|
||||
self.ctx, project_id=self.project_id,
|
||||
network_id=network.id, device_owner='',
|
||||
admin_state_up=True, status='DOWN', device_id='2',
|
||||
mac_address=mac_address)
|
||||
port.create()
|
||||
self.ports.append(port)
|
||||
self.ports.append(
|
||||
self._create_one_port(net_idx * 16 + port_idx, network.id))
|
||||
|
||||
@mock.patch.object(qos_extension.LOG, 'warning')
|
||||
@mock.patch.object(rule_obj, 'get_rules')
|
||||
@@ -150,36 +183,59 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
self.assertEqual(expected,
|
||||
self.qos_driver._qos_rules(mock.ANY, mock.ANY))
|
||||
|
||||
def test__ovn_qos_rule_ingress(self):
|
||||
def _test__ovn_qos_rule_ingress(self, fip_id=None, ip_address=None):
|
||||
direction = constants.INGRESS_DIRECTION
|
||||
rule = {qos_constants.RULE_TYPE_BANDWIDTH_LIMIT: QOS_RULE_BW_1}
|
||||
match = self.qos_driver._ovn_qos_rule_match(
|
||||
direction, 'port_id', ip_address)
|
||||
expected = {'burst': 100, 'rate': 200, 'direction': 'to-lport',
|
||||
'match': 'outport == "port_id"',
|
||||
'match': match,
|
||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY,
|
||||
'switch': 'neutron-network_id'}
|
||||
if fip_id:
|
||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||
result = self.qos_driver._ovn_qos_rule(
|
||||
direction, rule, 'port_id', 'network_id')
|
||||
direction, rule, 'port_id', 'network_id', fip_id=fip_id,
|
||||
ip_address=ip_address)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test__ovn_qos_rule_egress(self):
|
||||
def test__ovn_qos_rule_ingress(self):
|
||||
self._test__ovn_qos_rule_ingress()
|
||||
|
||||
def test__ovn_qos_rule_ingress_fip(self):
|
||||
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):
|
||||
direction = constants.EGRESS_DIRECTION
|
||||
rule = {qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_1}
|
||||
expected = {'direction': 'from-lport', 'match': 'inport == "port_id"',
|
||||
match = self.qos_driver._ovn_qos_rule_match(
|
||||
direction, 'port_id', ip_address)
|
||||
expected = {'direction': 'from-lport', 'match': match,
|
||||
'dscp': 16, 'switch': 'neutron-network_id',
|
||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY}
|
||||
if fip_id:
|
||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||
result = self.qos_driver._ovn_qos_rule(
|
||||
direction, rule, 'port_id', 'network_id')
|
||||
direction, rule, 'port_id', 'network_id', fip_id, ip_address)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
rule = {qos_constants.RULE_TYPE_BANDWIDTH_LIMIT: QOS_RULE_BW_2,
|
||||
qos_constants.RULE_TYPE_DSCP_MARKING: QOS_RULE_DSCP_2}
|
||||
expected = {'direction': 'from-lport', 'match': 'inport == "port_id"',
|
||||
expected = {'direction': 'from-lport', 'match': match,
|
||||
'rate': 300, 'dscp': 20, 'switch': 'neutron-network_id',
|
||||
'priority': qos_extension.OVN_QOS_DEFAULT_RULE_PRIORITY}
|
||||
if fip_id:
|
||||
expected['external_ids'] = {ovn_const.OVN_FIP_EXT_ID_KEY: fip_id}
|
||||
result = self.qos_driver._ovn_qos_rule(
|
||||
direction, rule, 'port_id', 'network_id')
|
||||
direction, rule, 'port_id', 'network_id', fip_id, ip_address)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test__ovn_qos_rule_egress(self):
|
||||
self._test__ovn_qos_rule_egress()
|
||||
|
||||
def test__ovn_qos_rule_egress_fip(self):
|
||||
self._test__ovn_qos_rule_egress(fip_id='fipid', ip_address='1.2.3.4')
|
||||
|
||||
def test__port_effective_qos_policy_id(self):
|
||||
port = {'qos_policy_id': 'qos1'}
|
||||
self.assertEqual(('qos1', 'port'),
|
||||
@@ -349,6 +405,8 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
- port21: qos_policy0 --> handled during "update_network", not updated
|
||||
handled during "update_port" and updated
|
||||
- port22: qos_policy1 --> handled during "update_network", not updated
|
||||
fip1: qos_policy0
|
||||
fip2: qos_policy1
|
||||
"""
|
||||
self.ports[1].qos_policy_id = self.qos_policies[0].id
|
||||
self.ports[1].update()
|
||||
@@ -360,9 +418,15 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
self.ports[5].update()
|
||||
self.networks[1].qos_policy_id = self.qos_policies[0].id
|
||||
self.networks[1].update()
|
||||
self.fips[0].qos_policy_id = self.qos_policies[0].id
|
||||
self.fips[0].update()
|
||||
self.fips[1].qos_policy_id = self.qos_policies[1].id
|
||||
self.fips[1].update()
|
||||
mock_qos_rules = mock.Mock()
|
||||
with mock.patch.object(self.qos_driver, '_qos_rules',
|
||||
return_value=mock_qos_rules):
|
||||
return_value=mock_qos_rules), \
|
||||
mock.patch.object(self.qos_driver, 'update_floatingip') as \
|
||||
mock_update_fip:
|
||||
self.qos_driver.update_policy(self.ctx, self.qos_policies[0])
|
||||
updated_ports = [self.ports[1], self.ports[3], self.ports[4]]
|
||||
calls = [mock.call(self.txn, port.id, port.network_id,
|
||||
@@ -371,3 +435,74 @@ class TestOVNClientQosExtension(test_plugin.Ml2PluginV2TestCase):
|
||||
# We can't ensure the call order because we are not enforcing any order
|
||||
# when retrieving the port and the network list.
|
||||
self.mock_rules.assert_has_calls(calls, any_order=True)
|
||||
fip = self.qos_driver._plugin_l3._make_floatingip_dict(self.fips[0])
|
||||
mock_update_fip.asssert_called_once_with(self.txn, fip, reset=True)
|
||||
|
||||
def test_update_floatingip(self):
|
||||
nb_idl = self.qos_driver._driver._nb_idl
|
||||
fip = self.fips[0]
|
||||
original_fip = self.fips[1]
|
||||
txn = mock.Mock()
|
||||
|
||||
# Update FIP, no QoS policy nor port/router
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_not_called()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Attach a port and a router, not QoS policy
|
||||
fip.router_id = self.router.id
|
||||
fip.fixed_port_id = self.fips_ports[0].id
|
||||
fip.update()
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_not_called()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Add a QoS policy
|
||||
fip.qos_policy_id = self.qos_policies[0].id
|
||||
fip.update()
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_called_once()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Remove QoS
|
||||
fip.qos_policy_id = None
|
||||
fip.update()
|
||||
original_fip.qos_policy_id = self.qos_policies[0].id
|
||||
original_fip.update()
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_not_called()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Add again another QoS policy
|
||||
fip.qos_policy_id = self.qos_policies[1].id
|
||||
fip.update()
|
||||
original_fip.qos_policy_id = None
|
||||
original_fip.update()
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_called_once()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Detach the port and the router
|
||||
fip.router_id = None
|
||||
fip.fixed_port_id = None
|
||||
fip.update()
|
||||
original_fip.router_id = self.router.id
|
||||
original_fip.fixed_port_id = self.fips_ports[0].id
|
||||
original_fip.qos_policy_id = self.qos_policies[1].id
|
||||
original_fip.update()
|
||||
self.qos_driver.update_floatingip(txn, fip)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_not_called()
|
||||
nb_idl.reset_mock()
|
||||
|
||||
# Force reset (delete any QoS)
|
||||
fip_dict = {'floating_network_id': fip.floating_network_id,
|
||||
'id': fip.id}
|
||||
self.qos_driver.update_floatingip(txn, fip_dict)
|
||||
nb_idl.qos_del_ext_ids.assert_called_once()
|
||||
nb_idl.qos_add.assert_not_called()
|
||||
|
||||
@@ -911,7 +911,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -935,7 +937,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-router-id', type='dnat_and_snat', logical_ip='10.0.0.10',
|
||||
external_ip='192.168.0.10', external_mac='00:01:02:03:04:05',
|
||||
@@ -961,7 +965,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-router-id', type='dnat_and_snat', logical_ip='10.0.0.10',
|
||||
external_ip='192.168.0.10',
|
||||
@@ -982,7 +988,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -1006,7 +1014,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -1161,7 +1171,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip_new['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip_new['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-new-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -1185,7 +1197,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip_new['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip_new['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-new-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -1219,7 +1233,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip_new['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip_new['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: '00:01:02:03:04:05',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-new-router-id', type='dnat_and_snat',
|
||||
logical_ip='10.10.10.10', external_ip='192.168.0.10',
|
||||
@@ -1248,7 +1264,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip_new['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip_new['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-new-router-id',
|
||||
type='dnat_and_snat',
|
||||
@@ -1281,7 +1299,9 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
self.fake_floating_ip_new['port_id'],
|
||||
ovn_const.OVN_ROUTER_NAME_EXT_ID_KEY: utils.ovn_name(
|
||||
self.fake_floating_ip_new['router_id']),
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa'}
|
||||
ovn_const.OVN_FIP_EXT_MAC_KEY: 'aa:aa:aa:aa:aa:aa',
|
||||
ovn_const.OVN_FIP_NET_ID:
|
||||
self.fake_floating_ip['floating_network_id']}
|
||||
self.l3_inst._ovn.add_nat_rule_in_lrouter.assert_called_once_with(
|
||||
'neutron-new-router-id',
|
||||
type='dnat_and_snat',
|
||||
|
||||
@@ -45,7 +45,7 @@ oslo.versionedobjects>=1.35.1 # Apache-2.0
|
||||
osprofiler>=2.3.0 # Apache-2.0
|
||||
os-ken >= 0.3.0 # Apache-2.0
|
||||
ovs>=2.8.0 # Apache-2.0
|
||||
ovsdbapp>=1.3.0 # Apache-2.0
|
||||
ovsdbapp>=1.4.0 # Apache-2.0
|
||||
psutil>=3.2.2 # BSD
|
||||
pyroute2>=0.5.13;sys_platform!='win32' # Apache-2.0 (+ dual licensed GPL2)
|
||||
pyOpenSSL>=17.1.0 # Apache-2.0
|
||||
|
||||
Reference in New Issue
Block a user